黑帽联盟

 找回密码
 会员注册
查看: 649|回复: 0
打印 上一主题 下一主题

[mysql] redis结合mysql,redis与mysql的自动同步

[复制链接]

895

主题

38

听众

3329

积分

管理员

Rank: 9Rank: 9Rank: 9

  • TA的每日心情
    难过
    昨天 22:31
  • 签到天数: 1652 天

    [LV.Master]伴坛终老

    本文自己未作测试是否有效,有需求自己测试

    1. redis结合mysql
    由于目前互联网巨大的访问量,在生产环境中常常需要redis结合mysql来用,如下图例,


    我们可以将redis当作mysql的缓存,应用(app)所有读的操作都负载到redis上,因为redis够快,如果直接从mysql上读会对它造成巨大的压力,之前的mysql主从复制同样也是为了解决这样的问题,如果redis中没有想要的内容再从mysql中读并把读到的内容缓存到redis中。但是现在存在一个问题:当应用执行update操作时,就是往mysql中添加内容时,这时候redis无法完成更新,并且mysql无法将更改传递到redis中,因为二者的数据结构不同并且没有专门的连接端口,这时候我们该如何解决呢?


    第一种传统的方式:在mysql中事先定义好触发器,通过udf(用户自定义函数)将mysql数据做映射,比如说将其映射为json数据,json数据可以跨平台传输,因此可以将json文件传递给redis从而完成数据的同步。但是这种方式从根本上是对mysql做操作,相当于给数据库创建函数对象,这种操作对数据库的侵入度是比较高的


    第二种方式是目前比较主流的,阿里开发的canal应用,它直接伪装成mysql slave的身份来对mysql进行复制,相当于mysql主从复制,然后通过事先准备好的javaclient将数据同步到redis,由于主从复制是mysql本身的功能,通过mysql主从复制协议实现的,因此侵入mysql数据库的程度更小


    21.png


    1.1 lamp架构搭建
    [root@server12 ~]# cd rhel7/

    [root@server12 rhel7]# yum install -y php-* libgearman-* libevent-*  ##server12上安装php-fpm

    [root@server12 rhel7]# systemctl start php-fpm.service  ##启动php-fpm

    [root@server12 rhel7]# netstat -antulp  ##查看是否开启相关端口

    tcp        0      0 127.0.0.1:9000          0.0.0.0:*               LISTEN      4121/php-fpm: maste

    [root@server11 local]# rsync -a nginx server12:/usr/local/ ##把server11上配置好的nginx复制到server12指定目录中

    22.png

    23.png

    24.png

    25.png


    [root@server12 ~]# cd /usr/local/nginx/
    [root@server12 nginx]# ls
    client_body_temp  conf  fastcgi_temp  html  logs  proxy_temp  sbin  scgi_temp  uwsgi_temp
    [root@server12 nginx]# cd conf/
    [root@server12 conf]# cp nginx.conf.default nginx.conf
    cp: overwrite ‘nginx.conf’? y
    [root@server12 conf]# vim nginx.conf  ##打开php站点注释
    [root@server12 ~]# vim .bash_profile  ##配置环境变量
    [root@server12 ~]# source .bash_profile
    [root@server12 ~]# nginx -t
    nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
    nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
    [root@server12 ~]# nginx  ##开启nginx
    [root@server12 ~]# php -m | grep mysql
    mysql
    mysqli
    pdo_mysql
    [root@server12 ~]# php -m | grep redis
    redis
    37


    26.png



    27.png


    访问测试

    28.png

    1.2 server13上启动redis,server14安装mysql
    server13上启动redis
    [root@server13 ~]# systemctl start redis_server
    [root@server13 ~]# redis-cli

    server14安装mysql
    [root@server14 local]# yum install -y mariadb-server
    [root@server14 local]# systemctl start mariadb
    [root@server14 local]# mysql


    29.png

    30.png

    31.png


    1.3 测试文件配置
    [root@server12 ~]# cd rhel7
    [root@server12 rhel7]# ll test.php
    -rw-r--r-- 1 root root 1369 Apr 16 10:34 test.php
    [root@server12 rhel7]# cp test.php /usr/local/nginx/html/ ##复制测试文件到nginx默认发布目录
    [root@server12 rhel7]# cd /usr/local/nginx/html/
    [root@server12 html]# vim test.php

    32.png

    33.png
    [root@server14 local]# mysql
    MariaDB [(none)]> show databases;
    MariaDB [(none)]> grant all on test.* to redis@'%' identified by 'westos'; ##授权远程用户连接

    [root@server12 rhel7]# scp test.sql server14:  ##将测试数据复制到mysql主机中
    [root@server14 ~]# cat test.sql   
    [root@server14 ~]# mysql < test.sql ##测试数据导入数据库

    34.png

    35.png

    测试文件内容
    36.png


    1.4 访问测试
    [root@server14 ~]# mysql
    MariaDB [(none)]> use test
    MariaDB [test]> show tables;
    MariaDB [test]> select * from test;  ##查看test库中生成的测试内容

    [root@server13 ~]# redis-cli
    127.0.0.1:6379> get 1
    "test1"
    127.0.0.1:6379> get 2
    "test2"

    37.png

    第一次访问,redis中没有缓存,看不到数据库中相关内容
    38.png

    再次访问,已将mysql中相关内容缓存进redis中,可以访问到
    39.png

    40.png

    server14
    MariaDB [test]> update test set name='westos' where id=1;
    server13
    127.0.0.1:6379> DEL 1
    (integer) 1


    mysql中更新后,redis并没有同步。
    41.png

    删除redis中的缓存,nginx自动将新的内容缓存进redis中。
    42.png


    2. redis与mysql的自动同步
    配置 gearman 实现数据同步:
    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 整体流程框图
    43.png

    2.2 安装lib_mysqludf_json
    lib_mysqludf_json UDF 库函数将关系数据映射为 JSON 格式。通常,数据库中的数据映射为 JSON 格式,是通过程序来转换的。
    在mysql主机上(server14):
    unzip lib_mysqludf_json-master.zip
    cd lib_mysqludf_json-master/
    yum install -y mysql-devel gcc
    gcc $(mysql_config --cflags) -shared -fPIC -o lib_mysqludf_json.so lib_mysqludf_json.c  ##生成so文件

    拷贝 lib_mysqludf_json.so 模块:
    cp lib_mysqludf_json.so /usr/lib64/mysql/plugin/


    查看 mysql 的模块目录:
    mysql> show global variables like 'plugin_dir';
    +---------------+-------------------------+
    | Variable_name | Value |
    +---------------+-------------------------+
    | plugin_dir | /usr/lib64/mysql/plugin |
    +---------------+-------------------------+

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

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

    44.png

    45.png

    2.3 安装 gearman-mysql-udf
    gearman-mysql-udf用来管理调用 Gearman 的分布式的队列
    server14上:
    yum install -y libgearman-* libevent-devel-2.0.21-4.el7.x86_64.rpm
    tar zxf gearman-mysql-udf-0.6.tar.gz
    cd gearman-mysql-udf-0.6
    ./configure --libdir=/usr/lib64/mysql/plugin/
    make
    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('192.168.0.12:4730');       %指定gearman后台,负责接收mysql更改,但不负责处理,处理交给指定的worker

    46.png

    47.png

    48.png

    49.png

    50.png

    51.png


    2.4 配置 gearman 的 worker 端
    [root@server12 rhel7]# yum install -y gearmand-1.1.12-18.el7.x86_64.rpm
    [root@server12 rhel7]# systemctl start gearmand.service
    [root@server12 rhel7]# netstat -antlp | grep 4730
    tcp        0      0 0.0.0.0:4730            0.0.0.0:*               LISTEN      19099/gearmand      
    tcp6       0      0 :::4730                 :::*                    LISTEN      19099/gearmand      
    [root@server12 rhel7]# vim worker.php  
    [root@server12 rhel7]# php -m | grep redis
    redis
    [root@server12 rhel7]# nohup php worker.php & ##worker打入后台执行
    [root@server12 rhel7]# ps ax

    52.png


    指定worker端
    53.png

    54.png

    2.5 配置mysql 触发器
    客户提交update任务,然后触发器启动,通过触发器中定义的函数将数据同步到redis。
    [root@server14 ~]# vim test.sql
    use test;
    ELIMITER $$
    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 ;
    [root@server14 ~]# mysql < test.sql
    [root@server14 ~]# mysql
    MariaDB [(none)]> SHOW TRIGGERS FROM test;
    MariaDB [(none)]> use test
    MariaDB [test]> update test set name='redhat' where id=1;
    [root@server13 ~]# redis-cli
    127.0.0.1:6379> get 1
    "redhat"

    55.png

    2.6 访问测试
    更新mysql,redis自动同步更新
    56.png

    57.png



    本人转载自:https://blog.51cto.com/u_14731/6522883

    帖子永久地址: 

    黑帽联盟 - 论坛版权1、本主题所有言论和图片纯属会员个人意见,与本论坛立场无关
    2、本站所有主题由该帖子作者发表,该帖子作者与黑帽联盟享有帖子相关版权
    3、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者和黑帽联盟的同意
    4、帖子作者须承担一切因本文发表而直接或间接导致的民事或刑事法律责任
    5、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
    6、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除并致以最深的歉意
    7、黑帽联盟管理员和版主有权不事先通知发贴者而删除本文

    勿忘初心,方得始终!
    您需要登录后才可以回帖 登录 | 会员注册

    发布主题 !fastreply! 收藏帖子 返回列表 搜索
    回顶部