一.前言
对一个关系型数据库进行调优以获得高查询性能可能会比较困难。如果对数据模型优化和对查询调优不起作用,DBA就可以使用缓存系统,比如Redis,它是一个可以提供内存和永久数据存储的键值数据存储系统。
由于Redis能够将数据快速读写至数据存储系统,比起关系型数据库它更具性能优势。但是键值数据存储比较简单,它们没有类似SQL那样的查询语言或是结构化数据模型。取而代之的是,它们包含用键作为标识符并与值相关联的一个简单字典或是哈希模型。DBA可以通过这些键来存储和检索值。
键值存储简单而又快速,这使得它们可以很好地匹配关系型数据库丰富的数据模型和查询功能。有时使用键值和关系型数据库的组合是更好的选择。另外,还有大量支持商业化的键值数据库,包括Redis,Riak和Areospike。
要运行Redis缓存来优化常用查询的性能,首先要对你想要缓存的查询结果进行识别。将注意力集中在那些最频繁使用和耗时的查询上,然后从你要缓存的查询中识别数据。简言之,就是缓存一个查询返回的所有字段值。
client——>app——>redis——>mysql——>redis——>client
二.实验环境(rhel7.3版本)
1.selinux和firewalld状态为disabled
2.各主机信息如下:
主机 | ip |
---|---|
server1(nginx服务器) | 172.25.83.1 |
server2(redis服务器) | 172.25.83.2 |
server3(mysql数据库) | 172.25.83.3 |
三.实验过程
配置server1:(因为server1之前是做过redis cluster集群的。所以要将之前打开的redis-server的进程杀掉)
前期准备:
杀掉redis-server的进程
(1)安装相应的软件,以提供killall命令(killall工具可以杀死所有关键字进程)
(2)杀掉redis-server的所有进程
此时再次查看进程,发现已经不存在redis-server的进程了
1.配置php
下载php对应的安装包及其对应的依赖包,并进行安装,以使得nginx服务支持php语言。
[root@server1 rhel7]# yum install * -y
2.源码编译nginx服务
(1)下载nginx对应的压缩包:
(2)安装nginx所需的依赖包
[root@server1 nginx-1.15.8]# yum install gcc -y
[root@server1 nginx-1.15.8]# yum install pcre-devel -y
[root@server1 nginx-1.15.8]# yum install zlib-devel -y
(3)在源码编译并安装之前,编辑配置文件(将debug关闭):
[root@server1 ~]# tar zxf nginx-1.15.8.tar.gz
[root@server1 ~]# cd nginx-1.15.8
[root@server1 nginx-1.15.8]# vim auto/cc/gcc
171 # debug
172 #CFLAGS="$CFLAGS -g" #对172行加注释
(4)源码编译并安装nginx:
[root@server1 nginx-1.15.8]# ./configure --prefix=/usr/local/nginx #预编译
[root@server1 nginx-1.15.8]# make && make install #编译并安装
3.配置nginx服务
<1>修改nginx服务对应的配置文件,以使得nginx服务支持php语言
[root@server1 nginx-1.15.8]# vim /usr/local/nginx/conf/nginx.conf #将65-71行的注释去掉
65 location ~ \.php$ {
66 root html;
67 fastcgi_pass 127.0.0.1:9000;
68 fastcgi_index index.php;
69 #fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; #将69行注释
70 include fastcgi.conf; #将70行该为fastcgi.conf
71 }
43 location / {
44 root html;
45 index index.php index.html index.htm; #在45行的前面添加index.php
46 }
<2>检测nginx服务
[root@server1 ~]# /usr/local/nginx/sbin/nginx -t
<3>启动nginx服务
[root@server1 ~]# /usr/local/nginx/sbin/nginx
在浏览器中输入172.25.83.1进行测试,以确保nginx服务已经搭建好
<4>编写redis服务对应的测试文件(test.php文件),并将该文件拷贝到nginx服务的默认发布目录中,命名为index.php并进行测试
test.php文件的内容如下
[root@server1 ~]# cp test.php /usr/local/nginx/html/index.php
<5>修改nginx服务的默认发布目录下的index.php文件,使得该服务指向server2的redis服务,指向server3的mysql数据库
[root@server1 html]# vim index.php
#将第3行的ip改为server2的ip
#将第10行的ip改为server3的ip
#值的注意的是第10行的redis是mysql数据库需要创建的用户,westos是redis这个用户对应的密码
配置server2:(因为server2之前是做过redis主从切换的,而且server2是从机。所以需要修改配置文件,使得server2成为主机)
环境准备:
修改server2的redis服务对应的配置文件(/etc/redis/6379.conf文件),并重启redis服务,并进行测试
[root@server2 ~]# vim /etc/redis/6379.conf #需要将之前在最后一行写的slaveof 172.25.83.1 6379这行删掉;将458和459行注释掉
70 bind 0.0.0.0 #第70行的监听所有端口的内容不用动
458 #min-replicas-to-write 1 #注释458和459行
459 #min-replicas-max-lag 10
[root@server2 ~]# /etc/init.d/redis_6379 restart
[root@server2 ~]# netstat -antulep | grep 6379
[root@server2 ~]# redis-cli
127.0.0.1:6379>
配置server3:(因为server3之前是做过mysql的MHA架构的,所以要清空环境)
环境准备:
停掉mysqld服务,并删除/var/lib/mysql中的所有文件
[root@server3 ~]# systemctl stop mysqld
[root@server3 ~]# cd /var/lib/mysql
[root@server3 mysql]# rm -rf *
1.下载mariadb-server数据库,启动mariadb服务,并进行安全初始化
[root@server3 ~]# yum install mariadb-server -y
[root@server3 ~]# systemctl start mariadb
[root@server3 ~]# mysql_secure_installation #一路敲y
2.登陆mysql数据库,创建test数据库,创建用户redis并对redis用户进行授权
[root@server3 ~]# mysql -uroot -proot
MariaDB [(none)]> create database test;
MariaDB [(none)]> grant all on test.* to 'redis'@'%' identified by 'westos';
MariaDB [(none)]> flush privileges;
3.编写test数据库的测试文件(test.sql),并将其导入到test数据库中
test.sql文件的内容(这个实验只用到1-3行,5-9行是下个实验的测试内容。所以这里将5-9行注释)
[root@server3 ~]# mysql -uroot -proot < test.sql
[root@server3 ~]# mysql -uroot -proot
测试一:在浏览器中输入172.25.83.1进行测试
结论:
看到了test数据库中的内容,宣告实验成功
测试二:为了查看浏览器,看到的数据是随着redis服务中的数据的设置而改变,还是随着数据库中的数据的改变而改变
1.在server3登陆数据库,修改数据(将id为1对应的数据改为linux)
[root@server3 ~]# mysql -uroot -proot
MariaDB [(none)]> use test;
MariaDB [test]> update test set name='linux' where id=1;
2.在server2修改数据(将id为2对应的数据改为redhat)
从上图中,我们可以看到id为1对应的数据,仍然是test1,而并不是数据库中显示的linux。
3.在浏览器中输入172.25.83.1进行查看数据
结论:
浏览器,看到的数据是随着redis服务中的数据的设置而改变,而不是随着数据库中的数据的改变而改变。
到这里,我们已经实现了redis作为mysql的缓存服务器,但是如果更新了mysql,redis中仍然会有对应的key,数据就不会更新。
此时,就会出现mysql和redis数据不一致的情况。所以接下来就要通过mysql触发器将改变的数据同步到redis中
四.实现数据库更新,redis的数据也更新
Gearman+PHP+MySQL UDF的组合异步实现MySQL到Redis的数据复制。
用redis作为Mysql数据库的缓存,在查找的时候,首先查找redis缓存,如果找到则返回结果;如果在redis中没有找到,那么查找Mysql数据库,找到的花则返回结果并且更新redis;如果没有找到则返回空。对于写入的情况,直接写入mysql数据库,mysql数据库通过触发器及UDF机制自动把变更的内容更新到redis中。采用MySQL作为数据存储引擎,Redis则作为Cache。
mysql读写数据都需要从磁盘读取 。磁盘的容量,带宽的大小就影响了网站的访问速度,读取的方式,也就是sql语句,次数和效率也会影响读取效率。
redis和mc都是缓存,并且都是驻留在内存中运行的,这大大提升了高数据量web访问的访问速度。然而mc只是提供了简单的数据结构,比如 string存储;redis却提供了大量的数据结构,比如string、list、set、hashset、sorted set这些,这使得用户方便了好多,毕竟封装了一层实用的功能,同时实现了同样的效果,当然用redis而慢慢舍弃mc。
这个实验的实现需要使用新的工具gearmand
Gearman是一套用来把程式需求委派给机器,提供通用的程序框架来将任务分发在机器运算。它同时具备并行工作的能力、负载均衡处理的能力,以及在不同程序语言之间沟通的能力。
运行过程:
一个Gearman请求的处理过程涉及三个角色:Client -> Job -> Worker。
Client:请求的发起者,可以是 C,PHP,Perl,MySQL UDF 等等。
Job:请求的调度者,用来负责协调把 Client 发出的请求转发给合适的 Worker。
Worker:请求的处理者,可以是 C,PHP,Perl 等等。
因为 Client,Worker 并不限制用一样的语言,所以有利于多语言多系统之间的集成。
甚至我们通过增加更多的 Worker,可以很方便的实现应用程序的分布式负载均衡架构。
大致流程:
下面要编写的 mysql 触发器,就相当于 Gearman 的客户端。修改表,插入表就相当于直接下发任务。然后通过 lib_mysqludf_json UDF 库函数将关系数据映射为 JSON 格式,然后再通过 gearman-mysql-udf 插件将任务加入到 Gearman 的任务队列中,最后通过redis_worker.php,也就是 Gearman 的 worker 端来完成 redis 数据库的更新。
实际的工作流程:mysql(client)——>gearmand:4730(job server)——>worker(php/python/java)
配置server3:
1.下载lib_mysqludf_json的使用过程中,依赖的软件
[root@server3 ~]# yum install gcc -y
[root@server3 ~]# yum install mariadb-devel -y #因为数据库安装的是mariadb,所以这里安装的包是mariadb-devel,而不是,mysql-devel
2.安装 lib_mysqludf_json
使用lib_mysqludf_json的原因是因为Gearman只接受字符串作为入口参数,可以通过lib_mysqludf_json将MySQL中的数据编码为JSON字符串。
<1>下载lib_mysqludf_json对应的压缩包:lib_mysqludf_json-master.zip,并进行安装
[root@server3 ~]# yum install unzip -y
[root@server3 ~]# unzip lib_mysqludf_json-master.zip
[root@server3 ~]# cd lib_mysqludf_json-master
[root@server3 lib_mysqludf_json-master]# gcc $(mysql_config --cflags) -shared -fPIC -o lib_mysqludf_json.so lib_mysqludf_json.c
可以看到重新编译生成了 lib_mysqludf_json.so 文件
<2>查看 mysql 的模块目录:
[root@server3 lib_mysqludf_json-master]# mysql -uroot -proot
MariaDB [(none)]> show global variables like 'plugin_dir';
<3>拷贝 lib_mysqludf_json.so 模块到mysql的模块目录
[root@server3 lib_mysqludf_json-master]# cp lib_mysqludf_json.so /usr/lib64/mysql/plugin/
<3>注册 UDF 函数
[root@server3 lib_mysqludf_json-master]# mysql -uroot -proot
MariaDB [(none)]> CREATE FUNCTION json_object RETURNS STRING SONAME 'lib_mysqludf_json.so';
<4>查看函数
[root@server3 lib_mysqludf_json-master]# mysql -uroot -proot
MariaDB [(none)]> select * from mysql.func;
3.安装 gearman-mysql-udf
这个插件是用来管理调用 Gearman 的分布式的队列。
<1>下载gearman-mysql-udf对应的软件包:gearman-mysql-udf-0.6.tar.gz,及其依赖包(libgearman-1.1.12-18.el7.x86_64.rpm,libgearman-devel-1.1.12-18.el7.x86_64.rpm和libevent-devel-2.0.21-4.el7.x86_64.rpm)。并进行编译安装
[root@server3 ~]# yum install libevent-devel-2.0.21-4.el7.x86_64.rpm libgearman-1.1.12-18.el7.x86_64.rpm libgearman-devel-1.1.12-18.el7.x86_64.rpm -y #安装依赖包
[root@server3 ~]# tar zxf gearman-mysql-udf-0.6.tar.gz #解压gearman-mysql-udf的压缩包
[root@server3 ~]# cd gearman-mysql-udf-0.6
[root@server3 gearman-mysql-udf-0.6]# ls
aclocal.m4 ChangeLog config.h.in configure.ac libgearman_mysql_udf Makefile.am NEWS
AUTHORS config configure COPYING m4 Makefile.in README
[root@server3 gearman-mysql-udf-0.6]# ./configure --help #查看configure的帮助
--libdir=DIR object code libraries [EPREFIX/lib]
--with-mysql[=mysql_config]
Support for the MySQL.
[root@server3 gearman-mysql-udf-0.6]# ./configure --libdir=/usr/lib64/mysql/plugin/ --with-mysql #预编译
[root@server3 gearman-mysql-udf-0.6]# make && make install #编译与安装
<2>注册 UDF 函数
[root@server3 ~]# mysql -uroot -proot
MariaDB [(none)]> CREATE FUNCTION gman_do_background RETURNS STRING SONAME 'libgearman_mysql_udf.so';
MariaDB [(none)]> CREATE FUNCTION gman_servers_set RETURNS STRING SONAME 'libgearman_mysql_udf.so';
<3>查看函数
[root@server3 ~]# mysql -uroot -proot
MariaDB [(none)]> select * from mysql.func;
<4>指定 gearman 的服务信息
[root@server3 ~]# mysql -uroot -proot
MariaDB [(none)]> SELECT gman_servers_set('172.25.83.1:4730');
4. 编写 mysql 触发器(根据实际情况编写)——也就是下面的test.sql文件
test.sql文加的内容:(这里只用到1,5-9行;2-3行是上个实验需要的内容,所以这里将其注释掉)
<1>将test.sql文件导入到test数据库中
[root@server3 ~]# mysql -uroot -proot < test.sql
<2>查看触发器
[root@server3 ~]# mysql -uroot -proot
MariaDB [(none)]> SHOW TRIGGERS FROM test;
配置server1
1.安装 php 的 gearman 扩展(前面已经安装过),启动gearmand服务(对应的端口是470端口)
[root@server1 ~]# systemctl start gearmand
[root@server1 ~]# netstat -antulpe | grep 4730
2.查看php的支持,看php是否支持redis,mysql和gearman
[root@server1 ~]# php -m
gearman
mysql
redis
3.编写 gearman 的 worker 端——worker.php文件
worker.php文件的内容如下:(其中第7行的ip地址指向server2——redis服务器)
测试:
1.在server1端:后台运行 worker
2.在server3端:更新 mysql 中的数据
[root@server3 ~]# mysql -uroot -proot
MariaDB [(none)]> use test;
MariaDB [test]> update test set name='hello' where id=1;
MariaDB [test]> update test set name='world' where id=2;
3.在server2端:查看 redis
4.在浏览器端:刷新测试页面看数据数据同步
结论:
mysql数据库端的数据的修改,影响了redis端的数据,也影响了浏览器端的数据。即mysql数据库,redis端和nginx端的数据实现了同步。表示实验成功。