UNPKG

mysql-redis

Version:
217 lines (150 loc) 6.43 kB
# mysql-redis :rocket: Transform your mysql server with `Redis` caching layer for [mysql](https://www.npmjs.com/package/mysql)/[mysql2](https://www.npmjs.com/package/mysql2). - MysqlRedis checks if there is a cached result for the query in redis - if not found in cache, it will retrieve data from mysql and on successful result cache it in redis for future queries - if redis is unavailable or errors, query will be served by mysql - zero external dependency (farmhash is now option after v0.7) ## Use-case Use _along_ with mysql and redis. This is not a replacement of either. Use it with queries/stored procedures that only perform `select` and will return same result set every time. - **No brainer** for retrieving static data, eg, `select * from countries` - Data that will not be updated once created, typically timeseries data like chat messages, logs - Use with caution where data may get updated in mysql as redis cache may be stale ### Hashing The above is achieved by creating a unique hash for every query "select 1+2" => #️⃣ In redis, the hash and query results are stored as key-value pair #️⃣ => [{'1+2':3}] #### Currently supported hash types are: **md5hash** ⚡🗜️ MD5hash is the new default to prevent non mandatory dependency on farmhash MD5 hash is generated without any external lib **farmhash32** ⚡🗜️ Example redis key: _prefix._`2jNDCJ` Fast!!! Over ~5 million hashes/s on reference machine. Most compact key. (if you have millions of possible queries, these hashes can collide :collision:) **farmhash64** Example redis key: _prefix._`DiHlF3yv0V$` fast (~2 million hashes/sec on reference machine ) _farmhash32/64_ use Google's farmhash, non-crypto algorithm (if you have millions of possible queries, these hashes can collide :collision:) **blake2b512** 🛡️ Example redis key: _prefix._`4KbMOx3xJi+7mJNy0tDbju6NY9uHqOroDsG4rYjpHK1mEwXJokls5Ofdjs7iDsn3cAtibgUkT8RDdpCE2phhiQ==` Crypto safe, ~500k hashes/sec on reference machine. Use it for caching millions of different queries (eg. chats, logs) Note that the key is longer than farmhash32/64. **full** Matches full query string. Use this if you are paranoid or if your queries are smaller than blake2b512 hashes Or you can **provide your own hash _per_ query**, eg, _prefix._`p.123` to represent `select * from person p where id = 123` ## Getting Started ### Pre-Requisites mysql ([mysql](https://www.npmjs.com/package/mysql)/[mysql2](https://www.npmjs.com/package/mysql2)), and redis ([redis](https://www.npmjs.com/package/redis)/[ioredis](https://www.npmjs.com/package/ioredis)). Internally MysqlRedis relies on mysql/mysql2's `query` function and redis's `get` and `set` functions For async/await api, you can use mysql2's promise api and [async-redis](https://www.npmjs.com/package/async-redis) ### Installing `npm i mysql-redis --save` ### Usage ``` const { MysqlRedis, HashTypes, Caching } = require("mysql-redis"); // or if you use async await api const { MysqlRedisAsync, HashTypes, Caching } = require("mysql-redis"); ``` #### Creating an instance of MysqlRedis requires - a mysql connection or pool (mysqlRedis will call it's query method when no cache found) - redis connection (mysqlRedis will call its set and get methods) - cache options (optional) #### Creating an instance of MysqlRedisAsync requires - a mysql connection or pool promise `// Example from mysql2 docs: const poolPromise = mysql.createPool({ host:'localhost', user: 'root', database: 'test' }) .promise();` - async redis ```` eg: const asyncRedis = require("async-redis"); const redis = asyncRedis.createClient(redisOptions); ``` ```` - cache options (optional) import `HashTypes` and `Caching` from mysql-redis ``` const cacheOptions = { expire: 2629746,// seconds, defaults to 30 days keyPrefix: "sql.", // default hashType: HashTypes.md5 //default caching: Caching.CACHE //default }; ``` `hashType` can be - `HashTypes.farmhash32` - `HashTypes.farmhash64` - `HashTypes.blake2b512` - `HashTypes.full` `caching` can be - `Caching.CACHE` to get data from Redis if available, else mysql - `Caching.SKIP` to get data from mysql, do not save to redis - `Caching.REFRESH` to get data from mysql and save to redis Options can be specified when creating mysqlRedis instance or overriden at the time of query. At query time, you can also provide a custom hash as _cacheOptions.hash_ (ignores hashType if specified) ``` const mysqlRedis = new MysqlRedis( mysqlConnection, redisConnection, cacheOptions ); ``` Now if you wish to get something from cache, just use mysqlRedis.query instead of your mysql connection's query. (Use your mysql connection normally to bypass cache) ``` mysqlRedis.query('select * from logs where id =?",["some-log-id"], (err,data,fields)=>{ console.log(data) // if served by Redis, fields value is something like [ { cacheHit: 'sql.Dh9VSNbN5V$' } ] // else mysql fields }); ``` or if you like promises, then: ``` const mysqlRedis = new MysqlRedisAsync( mysqlConnection, redisConnection, cacheOptions ); ... in an async function ... try{ [result,fields]=await mysqlRedis.query("select 1+?+?",[2,3]); }catch(err){ // handle err } ``` You can override cache options per query as below: ``` mysqlRedis.query('select * from logs where id =?",["some-log-id"], { //cache option keyPrefix:'sql-abc-', expire:3600, hashType: HashTypes.farmhash64 //or hash: myHash <- provide your own // caching: Caching.SKIP or Caching.REFRESH or Caching.CACHE }, (err,data,fields)=>{ console.log(data) // if served by Redis, fields value is something like [ { cacheHit: 'sql.Dh9VSNbN5V$' } ] // else mysql fields }); // promise api [result,fields]=await mysqlRedis.query("select 1+?+?",[2,3], { //cache option keyPrefix:'sql-abc-', expire:3600, hashType: HashTypes.farmhash64 //or hash: myHash <- provide your own // caching: Caching.SKIP or Caching.REFRESH or Caching.CACHE }); ``` ## Testing - Start mysql and redis servers on your local (host 127.0.0.1, default ports) - create user `test_user` in mysql, no need to give any grants ``` CREATE USER 'test_user'@'%' IDENTIFIED BY PASSWORD 'User@123'; ``` - then run `npm run test` ## Contributing Feel free to fork/send PR ## Authors - **Gi Singh** ## License This project is licensed under the [MIT](./LICENSE).