redis作为mysql的缓存服务器(读写分离)

来源:互联网 发布:安徽继远软件知乎 编辑:程序博客网 时间:2024/05/16 06:14

转自 http://www.iyunv.com/thread-52670-1-1.html

一、redis简介

Redis是一个key-value存储系统。和Memcached类似,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。在部分场合可以对关系数据库起到很好的补充作用。它提供了Java,C/C++(hiredis),C#,PHP,JavaScript,Perl,Object-C,Python,Ruby等客户端,使用很方便。

二、架构图
 
大致结构就是读写分离,将mysql中的数据通过触发器同步到redis中


三、安装LNMP环境(这里为了省事,就是用yum来安装)

1、修改yum源
1
2
3
4
5
6
7
8
9
10
11
12
13
[iyunv@redis ~]# vim /etc/yum.repos.d/epel.repo    #添加这个文件
[epel]
name=Extra Packages for Enterprise Linux 6 - $basearch
baseurl=http://download.fedoraproject.org/pub/epel/6/$basearch
failovermethod=priority
enabled=1
gpgcheck=0

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/6/$basearch/
gpgcheck=0
enabled=1




2、yum安装

1
[iyunv@redis ~]# yum -y install nginx php php-fpm php-cli php-common php-gd php-mbstring php-mysql php-pdo php-devel php-xmlrpc php-xml php-bcmath php-dba php-enchant mysql mysql-server




3、简单配置一下nginx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[iyunv@redis ~]# vim /etc/nginx/nginx.conf
server {
        listen       80;
        #定义使用www.xx.com访问
        server_name  www.xx.com;

        #设定本虚拟主机的访问日志
        access_log  /logs/www.xx.com.access.log  main;

        #默认请求
        location / {
          root   /www/;      #定义服务器的默认网站根目录位置
          index index.php index.html index.htm;   #定义首页索引文件的名称
        }
        location ~ \.php$ {
        root /www/;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME /www/$fastcgi_script_name;
        include fastcgi_params;
        }
    }




4、启动服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[iyunv@redis ~]# sed -i 's/apache/nginx/g' /etc/php-fpm.d/www.conf
[iyunv@redis ~]# /etc/init.d/php-fpm start
正在启动 php-fpm:                                         [确定]

[iyunv@redis ~]# /etc/init.d/mysqld start
正在启动 mysqld:                                          [确定]

[iyunv@redis ~]# mkdir /{logs,www}
[iyunv@redis ~]# chown -R nginx:nginx /{logs,www}
[iyunv@redis ~]# /etc/init.d/nginx start
正在启动 nginx:                                           [确定]

[iyunv@redis www]# service iptables stop
iptables: Flushing firewall rules:                         [  OK  ]
iptables: Setting chains to policy ACCEPT: filter          [  OK  ]
iptables: Unloading modules:                               [  OK  ]

[iyunv@redis redis]# netstat -tnlp      #查看监听
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name   
tcp        0      0 0.0.0.0:80                  0.0.0.0:*                   LISTEN      2101/nginx                   
tcp        0      0 127.0.0.1:9000              0.0.0.0:*                   LISTEN      7544/php-fpm        
tcp        0      0 0.0.0.0:3306                0.0.0.0:*                   LISTEN      1871/mysqld




5、给mysql授权
1
2
3
4
[iyunv@redis ~]# mysql
mysql> grant all privileges on *.* to root@localhost identified by '123456';

mysql> flush privileges;




6、测试
1
2
3
4
[iyunv@redis ~]# vim /www/index.php 
<?php
     phpinfo();
?>



然后访问页面看到php的相关信息,基础环境就算搭建完成了。

四、安装redis

1、安装redis
1
2
3
4
5
6
7
8
9
10
11
12
[iyunv@redis ~]# wget -c -t 0 http://download.redis.io/releases/redis-2.8.19.tar.gz
  
[iyunv@redis ~]# mkdir /usr/local/redis

[iyunv@redis ~]# tar xvf redis-2.8.19.tar.gz 
#安装很简单、直接make就可以了
[iyunv@redis ~]# cd redis-2.8.19
[iyunv@redis redis-2.8.19]# make 

#编译完成后,将src中的可执行文件拷贝到刚刚创建的目录中
[iyunv@redis src]# cp redis-benchmark redis-check-aof redis-check-dump redis-cli redis-sentinel redis-server /usr/local/redis/
[iyunv@redis redis-2.8.19]# cp redis.conf sentinel.conf /usr/local/redis/



Redis-benchmark      压力测试工具
Redis-check-aof      检查redis持久化命令文件的完整性
Redis-check-dump     检查redis持久化数据文件的完整性
Redis-cli            redis在linux上的客户端
Redis-sentinel       redis-sentinel是集群管理工具,主要负责主从切换。
Redis-server         Redis服务器的daemon启动程序

2、安装php的redis扩展
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[iyunv@redis ~]# wget -c -t 0 https://github.com/owlient/phpredis/archive/master.zip
[iyunv@redis ~]# unzip master.zip

[iyunv@redis ~]# cd phpredis-master/
[iyunv@redis phpredis-master]# phpize 
[iyunv@redis phpredis-master]# ./configure --with-php-config=/usr/bin/php-config
[iyunv@redis phpredis-master]# make && make install 

#修改php的配置文件,如果没有“extension=redis.so”,就加上这一行
[iyunv@redis ~]# vim /etc/php.ini 
extension=redis.so

[iyunv@redis ~]# /etc/init.d/php-fpm restart
停止 php-fpm:                                             [确定]
正在启动 php-fpm:                                         [确定]




3、是否安装成功

还是访问phpinfo的那个界面

 
看到这个就是安装完成了。

五、读写分离
这里只是简单的做了一下读,没有写操作的相关代码,过一会测试,直接到数据库里执行update来模拟写操作。
1、在mysql中插入一些测试数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[iyunv@redis ~]# mysql -u root -p123456
mysql> create database mytest;
mysql> CREATE TABLE `test` (`id` int(7) NOT NULL AUTO_INCREMENT, `name` char(8) DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
mysql> INSERT INTO `test` VALUES (1,'sven'),(2,'jim'),(3,'zhu'),(4,'wang'),(5,'ftd'),(6,'test'),(7,'test01'),(8,'test02'),(9,'test03');
mysql> select * from mytest.test;
+----+--------+
| id | name   |
+----+--------+
|  1 | sven   |
|  2 | jim    |
|  3 | zhu    |
|  4 | wang   |
|  5 | ftd    |
|  6 | test   |
|  7 | test01 |
|  8 | test02 |
|  9 | test03 |
+----+--------+




2、编写php的测试代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php
        $redis = new Redis();
        $redis->connect('127.0.0.1',6379) or die ("could net connect redis server");
        $query = "select * from test limit 8";
        //为了简单一点,这里就读取了8条数据
        for ($key = 1; $key < 9; $key++)
        {
                if (!$redis->get($key))
                {
                        $connect = mysql_connect('127.0.0.1','root','123456');
                        mysql_select_db(mytest);
                        $result = mysql_query($query);
                        //如果没有找到$key,就将该查询sql的结果缓存到redis
                        while ($row = mysql_fetch_assoc($result))
                        {
                                $redis->set($row['id'],$row['name']);
                        }
                        $myserver = 'mysql';
                        break;
                }
                else
                {
                        $myserver = "redis";
                        $data[$key] = $redis->get($key);
                }
        }

        echo $myserver;
        echo "<br>";
        for ($key = 1; $key < 9; $key++)
        {
                echo "number is <b><font color=#FF0000>$key</font></b>";

                echo "<br>";

                echo "name is <b><font color=#FF0000>$data[$key]</font></b>";

                echo "<br>";
        }
?>



第一次访问,redis中没有对应的KEY时
 
再次访问,此时redis中已有相关数据
 
到这里,我们已经实现了redis作为mysql的缓存服务器,但是如果更新了mysql,redis中仍然会有对应的KEY,数据就不会更新,此时就会出现mysql和redis数据不一致的情况。所以接下来就要通过mysql触发器将改变的数据同步到redis中。

六、通过gearman实现同步

1、介绍

Gearman是一个支持分布式的任务分发框架:
   Gearman Job Server:Gearman核心程序,需要编译安装并以守护进程形式运行在后台。
   Gearman Client:可以理解为任务的请求者。
   Gearman Worker:任务的真正执行者,一般需要自己编写具体逻辑并通过守护进程方式运行,Gearman Worker接收到Gearman Client传递的任务内容后,会按顺序处理。

大致流程:

下面要编写的mysql触发器,就相当于Gearman的客户端。修改表,插入表就相当于直接下发任务。然后通过lib_mysqludf_json UDF库函数将关系数据映射为JSON格式,然后在通过gearman-mysql-udf插件将任务加入到Gearman的任务队列中,最后通过redis_worker.php,也就是Gearman的worker端来完成redis数据库的更新。

2、安装启动

1
2
3
4
5
[iyunv@redis ~]# yum -y install gearmand libgearman-devel
[iyunv@redis ~]# /etc/init.d/gearmand start
正在启动 gearmand:                                        [确定]
[iyunv@redis ~]# /etc/init.d/gearmand status
gearmand (pid  7702) 正在运行...




3、安装php的gearman扩展

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[iyunv@redis ~]# wget -c -t 0 https://pecl.php.net/get/gearman-1.1.1.tgz
  
[iyunv@redis ~]# tar xvf gearman-1.1.1.tgz 
[iyunv@redis ~]# cd gearman-1.1.1
[iyunv@redis gearman-1.1.1]# phpize 
[iyunv@redis gearman-1.1.1]# ./configure --with-php-config=/usr/bin/php-config
[iyunv@redis gearman-1.1.1]# make 
[iyunv@redis gearman-1.1.1]# make install

#如果php的配置文件中没有extension = gearman.so,就加上此行
[iyunv@redis ~]# vim /etc/php.ini 
extension = gearman.so
[iyunv@redis ~]# /etc/init.d/php-fpm restart
停止 php-fpm:                                             [确定]
正在启动 php-fpm:                                         [确定]



 
这样就是安装成功了

4、安装lib_mysqludf_json
lib_mysqludf_json UDF库函数将关系数据映射为JSON格式。通常,数据库中的数据映射为JSON格式,是通过程序来转换的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[iyunv@redis ~]# wget -c -t 0 https://github.com/mysqludf/lib_mysqludf_json/archive/master.zip
[iyunv@redis ~]# unzip master.zip 
[iyunv@redis ~]# cd lib_mysqludf_json-master/
[iyunv@redis lib_mysqludf_json-master]# gcc $(mysql_config --cflags) -shared -fPIC -o lib_mysqludf_json.so lib_mysqludf_json.c
lib_mysqludf_json.c:40:23: 错误:my_global.h:没有那个文件或目录
lib_mysqludf_json.c:41:20: 错误:my_sys.h:没有那个文件或目录
lib_mysqludf_json.c:43:19: 错误:mysql.h:没有那个文件或目录
lib_mysqludf_json.c:44:21: 错误:m_ctype.h:没有那个文件或目录
lib_mysqludf_json.c:45:22: 错误:m_string.h:没有那个文件或目录

#这里编译报错是因为没有安装mysql的开发包,如果是源码安装的mysql,需要在/etc/ld.so.conf.d/
#目录下新建一个文件告诉系统mysql的头文件在哪里
[iyunv@redis lib_mysqludf_json-master]# yum -y install mysql-devel
[iyunv@redis lib_mysqludf_json-master]# gcc $(mysql_config --cflags) -shared -fPIC -o lib_mysqludf_json.so lib_mysqludf_json.c

mysql> show global variables like 'plugin_dir';
+---------------+-------------------------+
| Variable_name | Value                   |
+---------------+-------------------------+
| plugin_dir    | /usr/lib64/mysql/plugin |
+---------------+-------------------------+

#将模块拷贝到插件目录下
[iyunv@redis lib_mysqludf_json-master]# cp lib_mysqludf_json.so /usr/lib64/mysql/plugin/

#注册UDF函数
mysql> CREATE FUNCTION json_object RETURNS STRING SONAME 'lib_mysqludf_json.so';




5、安装gearman-mysql-udf
这个插件是用来管理调用 Gearman 的分布式的队列。 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[iyunv@redis ~]# wget -c -t 0 https://launchpad.net/gearman-my ... ysql-udf-0.6.tar.gz
[iyunv@redis ~]# tar xvf gearman-mysql-udf-0.6.tar.gz

[iyunv@redis ~]# cd gearman-mysql-udf-0.6
[iyunv@redis gearman-mysql-udf-0.6]# ./configure --with-mysql=/usr/bin/mysql_config --libdir=/usr/lib64/mysql/plugin/
[iyunv@redis gearman-mysql-udf-0.6]# make 
[iyunv@redis gearman-mysql-udf-0.6]# make install

#注册UDF函数
mysql> CREATE FUNCTION gman_do_background RETURNS STRING SONAME 'libgearman_mysql_udf.so';
mysql> CREATE FUNCTION gman_servers_set RETURNS STRING SONAME 'libgearman_mysql_udf.so';

#查看函数
mysql> select * from mysql.func;
+--------------------+-----+-------------------------+----------+
| name               | ret | dl                      | type     |
+--------------------+-----+-------------------------+----------+
| json_object        |   0 | lib_mysqludf_json.so    | function |
| gman_do_background |   0 | libgearman_mysql_udf.so | function |
| gman_servers_set   |   0 | libgearman_mysql_udf.so | function |
+--------------------+-----+-------------------------+----------+

#指定gearman的服务信息
mysql> SELECT gman_servers_set('127.0.0.1:4730');




6、编写mysql触发器(根据实际情况编写)

1
2
3
4
5
DELIMITER $$
CREATE TRIGGER datatoredis AFTER UPDATE ON test FOR EACH ROW BEGIN
    SET @RECV=gman_do_background('syncToRedis', json_object(NEW.id as `id`, NEW.name as `name`)); 
  END$$
DELIMITER ;




7、编写gearman的worker端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[iyunv@redis ~]# vim /www/redis_worker.php
<?php
$worker = new GearmanWorker();
$worker->addServer();
$worker->addFunction('syncToRedis', 'syncToRedis');

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

while($worker->work());
function syncToRedis($job)
{
        global $redis;
        $workString = $job->workload();
        $work = json_decode($workString);
        if(!isset($work->id)){
                return false;
        }
        $redis->set($work->id, $work->name);
}
?>

#后台运行
[iyunv@redis www]# nohup php redis_worker.php &



"$redis->set($work->id, $work->name);"这条语句就是将id作KEY和name作VALUE分开存储,需要和前面写的php测试代码的存取一致。

8、更新mysql中的数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
mysql> set @RECV = 1;
mysql> select @RECV;
+------+
| @RECV|
+------+
|    1 |
+------+
mysql> update test set name = 'ssss' where id = 1;
mysql> select @RECV;
+------+
| @RECV|
+------+
| NULL |
+------+



从返回值可以看到,触发器是触发成功的(这里的@RECV是上面mysql TIGGER的返回值)。我们在redis中查看数据:
1
2
3
[iyunv@redis redis]# ./redis-cli 
127.0.0.1:6379> get 1
"sven"



这里的数据居然没有变化,这是我们就要排错了。
1
2
3
4
5
6
7
8
9
10
11
[iyunv@redis ~]# vim /var/log/audit/audit.log 
type=AVC msg=audit(1427807674.425:107): avc:  denied  { name_connect } for  pid=12453 comm="mysqld" dest=4730 scontext=unconfined_u:system_r:mysqld_t:s0 tcontext=system_u:o
bject_r:port_t:s0 tclass=tcp_socket
#看到这样一条日志,就知道是selinux阻止了同步

#现在将selinux的模式调成Permissive 
[iyunv@redis ~]# getenforce 
Enforcing
[iyunv@redis ~]# setenforce 0
[iyunv@redis ~]# getenforce 
Permissive



设置完成以后,再次执行update,进入redis进行查看

1
2
127.0.0.1:6379> get 1
"ssss"



刷新一下刚刚的php界面

 
到这里就基本算是大功告成了,只要application将数据写到mysql中,mysql触发器检测到更新,就会通过Gearman将数据同步到redis中。然后读取的话,就直接从redis中进行读取。当然这只是个实验环境,实际上还有很多细节要调整。

参考文章:http://avnpc.com/pages/mysql-replication-to-redis-by-gearman
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 二晓啊相公太爱我了怎么办全文免费 车牌被套牌了又有违章怎么办 高中生只学好主课副科学不好怎么办 母泰迪怀孕23天了不吃饭怎么办 媳妇一再触碰我的底线怎么办 发票商品编码好多选错了分类怎么办 吃了用福尔马林泡的食物怎么办 没大没小说话不尊重人的孩子怎么办 升级安卓8.0后app闪退怎么办 业主装门占用消防通道物业怎么办? 想改名字派出所不给改怎么办 物业不给地热打压影响装修怎么办 pos机pin效码验证错误怎么办 苹果下载东西要发验证码怎么办 接口断在了丝扣里面怎么办 政府下了一张关停取缔单怎么办 微信运动数据不刷新了怎么办 邻居霸占我的土地不还我该怎么办 双层水浴式杀菌锅阀门坏了怎么办 通下水管的钢丝断水管里了怎么办 塑料水管与水阀连接处漏水怎么办 介质流向标识管道温度太高怎么办 雪碧里气体太多瓶子涨得要炸怎么办 餐厅不清洗油烟管道物业该怎么办 用完权健洁净宝后奇痒的厉害怎么办 老房子铸铁暖气管从外锈蚀了怎么办 德意壁挂炉补水多了水压过高怎么办 新空调的散热片铜管漏了怎么办 猪舍被别人推掉漏电电到人怎么办? 网上买的燃气灶连接用软管怎么办 哈弗h3后减振器上支架坏了怎么办 汽车用收录机电机皮带断了怎么办 大便太粗把马桶堵了怎么办 大便过粗把马桶堵了怎么办 大便硬的像石头拉不出来怎么办 家里埋在地下的水管漏水怎么办 埋在墙里的水管漏水怎么办 开发商暗埋水管热熔接头漏水怎么办 钻墙把水管钻破了怎么办 钻墙时不小心把水管钻破了怎么办 孩子把同桌的铅笔盒弄坏了怎么办