使用redis做為MySQL的緩存
介紹
- 在實際項目中,MySQL數據庫服務器有時會位於另外一台主機,需要通過網絡來訪問數據庫;即使應用程序與MySQL數據庫在同一個主機中,訪問MySQL也涉及到磁盤IO操作(MySQL也有一些數據預讀技術,能夠減少磁盤IO讀寫,此部分后續繼續研究),總之,直接從MySQL中讀取數據不如直接從內存中讀取數據來的效率高。為了提高數據庫訪問效率,人們采用了各種各樣的方法,其中方法之一就是使用一個給予內存的緩存系統放置在數據庫和應用程序之間。在查找數據的時候,首先從內存中查找,如果找到則使用,如果沒有找到,那么再真正訪問數據庫。這種方法在一些場景下(例如:頻繁查找相同數據)能夠提高系統的整體效率。
- 本文的主要目的即介紹上文說的這樣一種方法,采用redis nosql數據庫作為Mysql數據庫的緩存,在查找的時候,首先查找redis緩存,如果找到則返回結果;如果在redis中沒有找到,那么查找Mysql數據庫,找到的花則返回結果並且更新redis;如果沒有找到則返回空。對於寫入的情況,直接寫入mysql數據庫,mysql數據庫通過觸發器及UDF機制自動把變更的內容更新到redis中。
框圖
讀取步驟:
- 1. client讀取redis,如果命中返回結果,如果沒有命中轉到2.
2. client讀取數據庫,在數據庫中沒有查到,返回空;在數據庫中查到了,返回查到的結果並更新Redis。 - 寫入步驟:
1. client修改/刪除或者新增數據到MySQL。
2. MySQL的觸發器調用用戶自定義的UDF。
3. UDF把修改/刪除或者新增的數據更新到redis中。
代碼實現
軟件需求
- redis server與client安裝,redis編程相關的c庫。
- mysql server安裝,mysql-devel包的安裝,此包包含操作mysql數據庫的C語言API包。 -
實現步驟
1. 安裝並驗證redis
127.0.0.1:6379> hgetall w3ckey (empty list or set) #最開始在reids中沒有w3ckey的K-V對。 127.0.0.1:6379>
2. 安裝MySQL數據庫服務器
2.1 創建MySQL數據庫的腳本如下
drop database if exists mysqlRedis; create database mysqlRedis; use mysqlRedis; create table test1( id INT NOT NULL AUTO_INCREMENT, name VARCHAR(64), age INT, description VARCHAR(1000), primary key(id));
2.2 創建UDF使用的動態庫
#include <stdio.h> #include <stdlib.h> #include <mysql.h> #include <string.h> #include <hiredis/hiredis.h> int gxupdate(UDF_INIT * initid, UDF_ARGS * args, char * is_null, char * error) { redisContext * c = redisConnect("127.0.0.1", 6379); if(c->err) { redisFree(c); return 1; }
/*
//如果設有密碼為ubuntu
redisReply *reply;
char strReply[] = "AUTH ubuntu";
reply = (redisReply*)redisCommand(c, strReply);
freeReplyObject(reply);
reply = NULL;
*/
const char * command1 = "HMSET w3ckey id %d name %s age %d description %s";
redisReply * r = (redisReply *)redisCommand(c, command1,
*(int*)args->args[0], args->args[1], *(int *)args->args[2], args->args[3]);
if (r == NULL) {
return 1;
}
if (!((r->type == REDIS_REPLY_STATUS) && (strcasecmp(r->str, "OK") == 0))) {
freeReplyObject(r);
redisFree(c);
return 1;
}
freeReplyObject(r);
return 0;
} my_bool gxupdate_init(UDF_INIT * initid, UDF_ARGS * args, char * message) { return 0; }
編譯為動態庫:
gcc -shared -fPIC -I /usr/include/mysql -o udfredis.so mysqlUDFdemo.c /usr/local/lib/libhiredis.a
編譯完成之后拷貝動態庫udfgx.so到 /usr/lib/mysql/plugin/文件夾中,並修改成用戶對應權限。
2.3 配置udf與trigger。
use mysqlRedis;
drop function if exists gxupdate; create function gxupdate returns INTEGER soname "udfredis.so"; drop trigger if exists insert_redis; drop trigger if exists update_redis; drop trigger if exists delete_redis; delimiter | create trigger insert_redis after insert on test1 for each row begin declare ret int; select gxupdate(NEW.id, NEW.name, NEW.age, NEW.description) into @ret; #必須加into @ret,否則返回錯誤ERROR 1415 (0A000) #at line 6: Not allowed to return a result set from a trigger #insert只有NEW變量。 #update有NEW和OLD變量。 #delete只有OLD變量。 end| create trigger update_redis after update on test1 for each row begin declare ret int; select gxupdate(NEW.id, NEW.name, NEW.age, NEW.description) into @ret; end| create trigger delete_redis after delete on test1 for each row begin declare ret int; select gxupdate(OLD.id, OLD.name, OLD.age, OLD.description) into @ret; end| delimiter ;
注意,在MySQL中創建UDF的時候,insert, update和delete不能寫成一個觸發器,只能分別定義成三個觸發器。
測試
查看redis
[root@VM_24_16_centos mysql_redis]# redis-cli 127.0.0.1:6379> hgetall w3ckey (empty list or set) 127.0.0.1:6379>
redis中無key w3ckey 對應的value。
insert MySQL
mysql> insert into test1 (name, age, description) values ("ggglwlop", 23, "ddddgdg"); Query OK, 1 row affected (0.02 sec) mysql>
插入mysql。
查看redis
127.0.0.1:6379> hgetall w3ckey 1) "name" 2) "ggglwlop" 3) "description" 4) "ddddgdg" 5) "likes" 6) "27" 7) "visitors" 8) "23" 127.0.0.1:6379>
MySQL中有了對應的數據,說明mysql通過triger+udf的方式把改動更新到了redis中。
有用的鏈接
http://blog.csdn.net/socho/article/details/52292064 https://www.cnblogs.com/linuxbug/p/4950626.html https://www.cnblogs.com/tommy-huang/p/4703514.html 使用redis作為mysql緩存時的redis結構設計。 http://blog.csdn.net/shikaiwencn/article/details/51792059 需要根據實際需求來靈活設計redis kv關系。 https://www.cnblogs.com/bruceleeliya/archive/2009/05/23/Linux-C-Mysql.html 使用mysql的C API訪問mysql。 https://www.2cto.com/database/201110/108925.html #mysql udf。 https://www.cnblogs.com/linuxbug/p/4950626.html #udf使用的一個例子。 https://www.jianshu.com/p/4381a38403a1 http://blog.csdn.net/socho/article/details/52292064