Redis缓存Mysql技术实现:
Redis缓存的相关内容这里不介绍,具体可参考博文《专题之Redis缓存分析及使用》。这里着重介绍下Redis如何缓存Mysql数据的IO压力,做到可观的性能提升目的。在实际的业务需求下,随着企业数据量的不断递增,访问数据库的IO频率大大提升,即使Mysql做了相关的优化,但也不能满足需求,时而等待许久服务端才会响应(技术讨论群:489451956(新))。
这里就以用户登录为例进行说明(只实现后台部分,使用Redis前提是用户量已经达到百万级,否则有点大才小用)。首先从Redis中查询(为了提高访问响应速度),前提是Mysql中的数据已经同步到Redis中,如果Redis中已经存在该用户,那么就直接从其中获取并返回,否则再从Mysql中读取。这是一个简单的缓存技术例子,也是Redis使用的开始,后续我会在这个例子中继续优化处理细节,因为目的只有一个:就是提供服务端性能和用户体验。
一、数据表构建
新建一张t_user_info数据表:
二、Redis与Mysql数据同步
同步Mysql数据到Redis中:
1、数据表插入200万条数据(存储过程)
2、同步数据到Redis中
在这里使用了Redis的管道技术,目的是提高Redis的服务性能。
A、首先,准备编写一个.sql脚本
SELECT CONCAT(
'*14\r\n',
'$',LENGTH(redis_cmd),'\r\n',redis_cmd,'\r\n',
'$',LENGTH(redis_key),'\r\n',redis_key,'\r\n',
'$',LENGTH(id_key),'\r\n',id_key,'\r\n','$',LENGTH(id_val),'\r\n',id_val,'\r\n',
'$',LENGTH(account_key),'\r\n',account_key,'\r\n','$',LENGTH(account_val),'\r\n',account_val,'\r\n',
'$',LENGTH(password_key),'\r\n',password_key,'\r\n','$',LENGTH(password_val),'\r\n',password_val,'\r\n',
'$',LENGTH(nickname_key),'\r\n',nickname_key,'\r\n','$',LENGTH(nickname_val),'\r\n',nickname_val,'\r\n',
'$',LENGTH(email_key),'\r\n',email_key,'\r\n','$',LENGTH(email_val),'\r\n',email_val,'\r\n',
'$',LENGTH(address_key),'\r\n',address_key,'\r\n','$',LENGTH(address_val),'\r\n',address_val,'\r'
)
FROM(
SELECT
'HMSET' ASredis_cmd,CONCAT(account,password,'_hash') AS redis_key,
'id' AS id_key,id AS id_val,
'account' AS account_key,account ASaccount_val,
'password' AS password_key,password ASpassword_val,
'nickname' AS nickname_key,nickname ASnickname_val,
'email' AS email_key,email AS email_val,
'address' AS address_key,address ASaddress_val
FROM t_user_info
) AS t
B、其次,编写个redis的table到json的lua
Redis2.6版本以后开始支持内嵌了lua环境,支持使用lua解释器执行脚本:
for k,v in pairs(ok) do
for key,val in pairs(v) do
if key%2 == 0 then
tmp[v[key-1]] = v[key];
end
end
ret[k]=tmp;
end
ngx.say(cjson.encode(ret));
C、最后,执行数据同步命令
$ mysql -h 127.0.0.1 -uroot-Dcwteam --skip-column-names --raw < /redis/sql/mysql_to_redis.sql |redis-cli --eval /redis/lua/redis_table_json.lua --pipe
结果:
看到上图,说明我们已经导入成功了,速度真够快的,只用了30秒左右。
三、Redis缓存Mysql
Redis缓存Mysql的实现比较简单,在文章的叙述部分已经说明,这里不再赘述。这部分主要介绍的内容是介绍如何从Redis和mysql中获取数据,如何缓存Mysql的基本实现,因为前面已经做好了Redis和Mysql之间的数据格式协议,并在同步的时候,就将redis的Hash做好了对应关系,并转化为json格式,具体的实现请参看下面:
1、Php代码实现:
//使用Redis缓存Mysql
public functionredisCacheMysql() {
header("Content-Type:text/html;charset=utf-8");
$uRedis= new\Redis();
$uRedis->connect('127.0.0.1',6379);
//前端获得的账号信息(这只是演示例子,也只是一种方式)
$account= 'cwteam';
$password= 'e10adc3949ba59abbe56e057f20f883e';
$result= '';
$userKey= $account.$password.'_hash';
//先从Redis中取,如果没有就去请求mysql
if(!$uRedis->exists($userKey)) {
//不存在读取数据库
$where= array();
$where['account'] = $account;
$where['password'] = $password;
$user= D('UserInfo')->where($where)->find();
if($user) {
$result.= json_encode($user).'';
}else{
$result.= '结果:该用户不存在!';
}
$result.= '我从mysql中读取的!';
} else{
//存在就从redis中取
$user= $uRedis->hGetAll($userKey);
if($user) {
$result.= json_encode($user).'';
}else{
$result.= '结果:该用户不存在!';
}
$result.= '我从Redis中读取的!';
}
echo'结果:'.$result .= '';
}
2、结果验证
Redis无缓存时:
此时,我们可以在mysql中新增一条Redis中未缓存的记录,然后执行:
Redis有缓存时:
注意:
使用Redis缓存Mysql的实现是很有必要的,当实际数据量很大并且请求频次很高的时候,Redis就凸显出了它的优势所在,这样做的目的有:a、减轻数据库IO的压力,b、提高用户请求响应的速度。
好了,文章中不免会有遗漏的地方,欢迎在顶部的Q群或下面的讨论中交流。