如何使用 Redis 和 Node.js 緩存 MySQL 數據

介紹

Node.js 的主要優點是通過將多個請求放入事件隊列來處理它們。 這種事件驅動的架構使 Node.js 非常適合編寫現代實時應用程序。 雖然 Node.js 速度很快,但您可以通過使用緩存來提高其數據庫訪問性能。

有許多數據庫緩存解決方案,但本指南主要關注 Redis。 Redis 是一個鍵值對存儲,它使用計算機的 RAM 進行存儲。 RAM 的傳輸速度比典型的固態硬盤 (SSD) 快幾倍。

使用 Node.js 訪問數據庫時,應使用 Redis 服務器緩存頻繁訪問數據的查詢結果。 例如,您可以緩存電子商務軟件中的產品、會計應用程序中的付款方式或客戶註冊數據庫中的國家/地區列表。

本指南向您展示如何使用 Redis 和 Node.js 緩存 MySQL 數據Ubuntu20.04。

以前的要求

要遵循本指南:

  • 部署 Ubuntu 20.04 服務器。
  • 安裝並保護 MySQL 服務器。
  • 安裝 Node.js 的 PPA 版本(選項 2)。
  • 安裝和配置 Redis 服務器。

1.設置MySQL數據庫

第一步是建立一個數據庫,將數據永久存儲在磁盤上。 因為 Redis 使用計算機的 RAM 來存儲數據,所以不適合存儲關係數據。 儘管 Redis 可以將數據持久化到磁盤,但它並不是為此目的而設計的,並且可能無法達到最佳性能。 按照以下步驟創建 MySQL 數據庫、用戶帳戶和示例表:

  1. 登錄到您的 MySQL 服務器 root 用戶名。

                              
                                $ sudo mysql -u root -p
    
                              
                            
  2. 輸入你的 MySQL root 密碼並按 ENTER 繼續。 然後發出以下 SQL 命令來創建示例 e-commerce 數據庫和用戶帳戶。 代替 EXAMPLE_PASSWORD 使用強密碼。

                              
                                mysql> CREATE DATABASE e_commerce;
           CREATE USER 'e_commerce_user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'EXAMPLE_PASSWORD';
           GRANT ALL PRIVILEGES ON e_commerce.* TO 'e_commerce_user'@'localhost';
           FLUSH PRIVILEGES;
    
                              
                            

    生產。

                              
                                ...
    Query OK, 0 rows affected (0.01 sec)
    
                              
                            
  3. 切換到新的 e_commerce 數據庫。

                              
                                mysql> USE e_commerce;
    
                              
                            

    生產。

                              
                                Database changed
    
                              
                            
  4. 創建一個 countries 桌子。 此表存儲國家/地區列表,供以後在前端應用程序中使用。 例如,當客戶訂閱您的服務時。 您應該考慮緩存很少更改的對象,例如國家、支付方式和產品,以避免向前端用戶提供過時的數據。

                              
                                mysql> CREATE TABLE countries (
               country_id BIGINT NOT NULL PRIMARY KEY,
               country_name VARCHAR(100)
           ) ENGINE = InnoDB;
    
                              
                            

    生產。

                              
                                Query OK, 0 rows affected (0.01 sec)
    
                              
                            
  5. 將樣本數據插入 countries 桌子。

                              
                                mysql> INSERT INTO countries (country_id, country_name) values ('1', "USA");
           INSERT INTO countries (country_id, country_name) values ('39', "ITALY");
           INSERT INTO countries (country_id, country_name) values ('86', "CHINA");
           INSERT INTO countries (country_id, country_name) values ('81', "JAPAN");
           INSERT INTO countries (country_id, country_name) values ('27', "SOUTH AFRICA");
    
                              
                            

    生產。

                              
                                ...
    Query OK, 1 row affected (0.01 sec)
    
                              
                            
  6. 諮詢 countries 表以確保數據到位。

                              
                                mysql> SELECT
               country_id,
               country_name
           FROM countries;
    
                              
                            

    生產。

                              
                                +------------+--------------+
    | country_id | country_name |
    +------------+--------------+
    |          1 | USA          |
    |         27 | SOUTH AFRICA |
    |         39 | ITALY        |
    |         81 | JAPAN        |
    |         86 | CHINA        |
    +------------+--------------+
    5 rows in set (0.01 sec)
    
                              
                            
  7. 註銷 MySQL 服務器。

                              
                                mysql> QUIT;
    
                              
                            

    生產。

                              
                                Bye
    
                              
                            

建立數據庫後,下一步重點是創建查詢數據庫表以檢索國家列表的 Node.js 代碼。 稍後,本指南將向您展示如何在 Redis 服務器上緩存 MySQL 服務器結果。

2. 創建一個 mysql_database 班級

為了提高代碼的可讀性和支持,您應該為這個示例應用程序中的每個函數創建一個單獨的模塊。 您需要的第一個模塊是 mysql_database 班級。 此類允許您連接到 MySQL 數據庫並從中檢索數據。 countries 使用 Node.js 的表 mysql 模塊。 按照以下步驟創建類:

  1. 做一個 project 您的應用程序的目錄。

                              
                                $ mkdir project
    
                              
                            
  2. 導航到新的 project 目錄。

                              
                                $ cd project
    
                              
                            
  3. 開一個新的 mysql_database.js 在文本編輯器中。

                              
                                $ nano mysql_database.js
    
                              
                            
  4. 在輸入框輸入以下信息 mysql_database.js 訴訟程序。 代替 EXAMPLE_PASSWORD 使用 MySQL 用戶的正確密碼。

                              
                                class mysql_database {
    
        getData(callBack) {
    
            const mysql = require('mysql');
    
            const mysql_con = mysql.createConnection({
                host: "localhost",
                user: "e_commerce_user",
                password: "EXAMPLE_PASSWORD",
                database: "e_commerce"
             });
    
            mysql_con.connect(function(err) {
                if (err) {
                    console.log(err.message);
                }
            });
    
           var queryString = "select * from countries";
    
           mysql_con.query(queryString , [], function (err, result) {
               if (err) {
                   callBack(err, null);
               } else {
                   callBack(null, result);
               }
          });
    
        }
    }
    
    module.exports = mysql_database;
    
                              
                            
  5. 保存並關閉 mysql_database.js 完成編輯後的文件。

mysql_database.js 文件解釋:

  1. mysql_database.js 該文件將數據庫操作包含在一個 mysql_database 班級。

                              
                                class mysql_database {
        ...
    }
    
                              
                            
  2. mysql_database 該類有一個方法。 那是 getData(...) 方法。

                              
                                getData(callBack) {
        ...
    }
    
                              
                            
  3. getData(...) 該方法從數據庫中獲取憑據並使用 mysql.createConnection({...}) connect(...) 功能

  4. queryString 變量存儲 SQL 命令 ( select * from countries ) 從 countries 桌子。

  5. 接近尾聲時, getData(...) 方法分配 result 從數據庫查詢到 callBack 進一步處理的功能。 稍後,本指南將向您展示如何編寫 callBack 功能。

  6. module.exports = mysql_database; 文件末尾的行告訴 Node.js 使模塊在其他源文件中可用。

他們的 mysql_database 課準備好了。 您可以將該類導入到任何需要數據庫操作的源代碼文件中,使用 require('./mysql_database'); 陳述。

3. 創建一個 redis_server 班級

作為 mysql_database 類,你需要一個單獨的 redis_server 類連接到存儲和檢索鍵值的 Redis。

  1. 開一個新的 redis_server.js 在文本編輯器中。

                              
                                $ nano redis_server.js
    
                              
                            
  2. 在文件中輸入以下信息。 本指南使用 localhost ( 127.0.0.1 ) 因為您已經在本地機器上部署了 Redis。 如果要訪問遠程 Redis 服務器,請使用遠程主機的正確公共 IP 地址更新此值。 默認情況下,Redis 服務器偵聽端口上的傳入連接 6379 .

                              
                                class redis_server {
    
        redisConnect() {
    
            const redis = require('redis');
    
            const redisClient = redis.createClient('127.0.0.1', 6379);
    
            redisClient.connect();
    
            redisClient.on('error', err => {
                console.log('Error ' + err);
            });
    
            return redisClient;
        }
    
        setData(data) {
            var redisClient = this.redisConnect();
            redisClient.set('countries', data);
        }
    
        getData(callBack) {
            var redisClient = this.redisConnect();
            var resp = redisClient.get('countries');
    
            resp.then(function(result) {
                callBack(null, result)
            });
        }
    }
    
    module.exports = redis_server;
    
                              
                            
  3. 保存並關閉 redis_server.js 完成編輯後。

redis_server.js 文件解釋:

  1. redis_server.js 文件包含一個 redis_server 班級。

                              
                                class redis_server {
        ...
    }
    
                              
                            
  2. redis_server 該類包含三種方法:

    • redisConnect(){...} :此方法導入 redis 模塊並使用 redis.createClient(...) redisClient.connect() 功能

    • setData(data){...} : 這個方法接受一個 data 包含 MySQL 數據庫結果的字符串參數。 這 setData(data){...} 然後該方法使用 Redis 連接 ( this.redisConnect(...) ) 使用 redisClient.set('countries', data) 陳述。 這 countries variable 是 Redis 服務器上存儲數據的 Redis 鍵的名稱。

    • getData(callBack){} : 這個函數連接到 Redis 服務器 ( this.redisConnect() ) 並使用 Redis redisClient.get('countries') 函數檢索值 countries 扳手。

  3. module.exports = redis_server; 文件末尾的語句允許您公開和導入 redis_server 其他源文件中的函數。

redis_server 該模塊現已準備就緒。 您可以使用以下命令將其導入其他源代碼文件 require('./redis_server'); 陳述。

4. 創建一個 main.js 訴訟

該項目需要的最後一個文件是 main.js 訴訟程序。 該文件在您運行應用程序時執行。 這 main.js 該文件是您的應用程序的入口點。 請按照以下步驟創建文件:

  1. 開一個新的 main.js 文本編輯器中的文件。

                              
                                $ nano main.js
    
                              
                            
  2. 在輸入框輸入以下信息 main.js 訴訟程序。

                              
                                const mysql_database = require('./mysql_database');
    const redis_server = require('./redis_server');
    
    const http = require('http');
    const hostname="127.0.0.1";
    const port = 8080;
    
    const server = http.createServer(httpHandler);
    
    server.listen(port, hostname, () => {
        console.log(`Server running at https://${hostname}:${port}/`);
    });
    
    function httpHandler(req, res) {
    
        const mysqlDatabase = new mysql_database();
        const redisServer = new redis_server();
    
        redisServer.getData( (redisErr, redisResult) => {
    
            if (redisErr) {
                console.log(redisErr.message);
            } else {
    
                if (redisResult == null )  {
    
                    mysqlDatabase.getData((mysqlErr, mysqlResult) => {
    
                        jsonData = JSON.stringify(mysqlResult, null, 4)
                        redisServer.setData(jsonData);
    
                        var countries = {_source:'MySQL Server', data: JSON.parse(jsonData)};
    
                        res.write(JSON.stringify(countries, null, 4));
                        res.end();
                    });
    
                } else {
    
                    var countries = {_source:'Redis Server', data: JSON.parse(redisResult)};
    
                    res.write(JSON.stringify(countries, null, 4));
                    res.end();
                }
        }
    
        });
    
    
    }
    
                              
                            
  3. 保存並關閉 main.js 訴訟程序。

main.js 文件解釋:

  1. 文件頂部的前兩行導入 mysql_database redis_server 您之前創建的模塊。

                              
                                ...
    const mysql_database = require('./mysql_database');
    const redis_server = require('./redis_server');
    ...
    
                              
                            
  2. 以下行導入 http 服務器模塊。 該模塊允許您在應用程序中運行 Node.js 的內置 HTTP 服務器。 HTTP 服務器偵聽端口上的傳入連接 8080 . 然後你使用了 http.createServer(httpHandler); 行指示 http 模塊將 HTTP 請求轉發到 httpHandler(...) 功能。

                              
                                ...
    const http = require('http');
    const hostname="127.0.0.1";
    const port = 8080;
    
    const server = http.createServer(httpHandler);
    
    server.listen(port, hostname, () => {
        console.log(`Server running at https://${hostname}:${port}/`);
    });
    ...
    
                              
                            
  3. httpHandler(req, res) {...}) 該函數在您的應用程序接收到 HTTP 請求時執行。

                              
                                ...
    function httpHandler(req, res) {
        ...
    }
    ...
    
                              
                            
  4. 在下面 httpHandler(req, res) {...}) 函數,您正在創建 MySQL 實例( mysql_database ) 和 Redis ( redis_server ) 您之前使用以下語句編寫的數據庫模塊。

                              
                                ...
    const mysqlDatabase = new mysql_database();
    const redisServer = new redis_server();
    ...
    
                              
                            
  5. redisServer.getData(..){..} 然後該函數會查詢 Redis 服務器以檢查 countries 扳手。

                              
                                ...
    redisServer.getData( (redisErr, redisResult) => {
        ...
    }
    ...
    
                              
                            
  6. 邏輯陳述 if (redisResult == null ) {...} 語句進一步檢查 Redis 輸出以檢查 Redis 是否返回 null 值得。 一個 null 該值表示 Redis 服務器沒有 MySQL 結果的副本。 在這種情況下,應用程序會查詢 MySQL 數據庫( mysqlDatabase.getData(...) ),返回JSON格式的值,並將數據緩存在Redis服務器上( redisServer.setData(jsonData); )。 如果 Redis 服務器已經緩存了數據,則返回結果。

                              
                                ...
            if (redisErr) {
                console.log(redisErr.message);
            } else {
    
                if (redisResult == null )  {
    
                    mysqlDatabase.getData((mysqlErr, mysqlResult) => {
    
                        jsonData = JSON.stringify(mysqlResult, null, 4)
                        redisServer.setData(jsonData);
    
                        var countries = {_source:'MySQL Server', data: JSON.parse(jsonData)};
    
                        res.write(JSON.stringify(countries, null, 4));
                        res.end();
                    });
    
                } else {
    
                    var countries = {_source:'Redis Server', data: JSON.parse(redisResult)};
    
                    res.write(JSON.stringify(countries, null, 4));
                    res.end();
                }
        }
    ...
    
                              
                            
  7. JSON.stringify(mysqlResult, null, 4) 該函數在傳遞給 Redis 時將數據轉換為 JSON 字符串。 該函數還將漂亮的 JSON 輸出返回給調用函數。

您已經編寫了所有必要的模塊並創建了一個 main.js 文件為您的應用程序。 下一步是測試應用程序。

5. 試用應用程序

您的應用現在可以進行測試了。 這一步的重點是導入你在這個應用程序中使用的模塊,初始化你的包目錄,並使用 Linux 運行測試 curl 領域。

  1. 初始化您的應用程序 project 目錄。

                              
                                $ npm init
    
                              
                            

    回復以下信息:

                              
                                package name: (project) redis-cache ENTER
    version: (1.0.0) 1.0.0 ENTER
    description: Redis cache with Node.js and MySQL ENTER
    entry point: (main.js) main.js ENTER
    test command: ENTER
    git repository: ENTER
    keywords: redis, cache, mysql ENTER
    author: test author ENTER
    license: (ISC) ENTER
    ...
    Is this OK? (yes) yes ENTER
    
                              
                            

    生產。

                              
                                npm notice
    npm notice New minor version of npm available! 8.11.0 -> 8.15.1
    npm notice Changelog: https://github.com/npm/cli/releases/tag/v8.15.1
    npm notice Run npm install -g [email protected] to update!
    npm notice
    
                              
                            

    忽略 npm 暫時警告。 您的應用程序應該可以正常運行已安裝 npm 版本。

  2. 使用 Node.js 包管理器 ( npm ) 下載 mysql redis 模塊。

                              
                                $ npm install mysql
    $ npm install redis
    
                              
                            

    生產。

                              
                                added 11 packages, and audited 12 packages in 2s
    found 0 vulnerabilities
    ...
    added 10 packages, and audited 22 packages in 4s
    found 0 vulnerabilities
    
                              
                            
  3. 使用 node 命令來運行應用程序。 該命令具有阻塞功能。 不要在活動終端窗口中輸入任何其他命令。

                              
                                $ node main.js
    
                              
                            

    您的應用程序會激活 Web 服務器並顯示以下輸出。

                              
                                Server running at https://127.0.0.1:8080/
    
                              
                            
  4. 在另一個終端窗口中連接到您的 Ubuntu 服務器並運行以下命令 curl 命令發送一個 GET 向應用程序請求。

                              
                                $ curl -X GET https://localhost:8080
    
                              
                            
  5. 檢查的值 _source 屬性 ( MySQL Server )。 由於您是第一次運行應用程序,應用程序直接從 MySQL 服務器返回數據。

                              
                                {
        "_source": "MySQL Server",
        "data": [
            {
                "country_id": 1,
                "country_name": "USA"
            },
            {
                "country_id": 27,
                "country_name": "SOUTH AFRICA"
            },
            {
                "country_id": 39,
                "country_name": "ITALY"
            },
            {
                "country_id": 81,
                "country_name": "JAPAN"
            },
            {
                "country_id": 86,
                "country_name": "CHINA"
            }
        ]
    }
    
                              
                            
  6. 重複 curl 領域。 這一次, _source 屬性的值變為 Redis Server . 輸出顯示您的應用程序已成功在 Redis 服務器上緩存 MySQL 數據,並且該應用程序現在正在處理所有 Redis 請求。

                              
                                {
        "_source": "Redis Server",
        "data": [
            {
                "country_id": 1,
                "country_name": "USA"
            },
            {
                "country_id": 27,
                "country_name": "SOUTH AFRICA"
            },
            {
                "country_id": 39,
                "country_name": "ITALY"
            },
            {
                "country_id": 81,
                "country_name": "JAPAN"
            },
            {
                "country_id": 86,
                "country_name": "CHINA"
            }
        ]
    }
    
                              
                            

您的應用程序按預期工作。

結論

本指南演示了在 Node.js 應用程序中使用 Redis 緩存 MySQL 數據的想法。 儘管本指南緩存了單個 MySQL 數據庫表,但您可以根據應用程序的用例擴展源代碼以緩存其他對象。 但是,請通過設置緩存失效策略來避免提供過時的數據。 一個好的策略應該可以幫助您在 MySQL 服務器上更新基值後使 Redis 鍵失效。

文章標題 名稱(可選) 電子郵件(可選) 描述

發送建議

相關文章