Redis作为缓存服务器,加快lnmp架构中数据库速度

一、背景

对一个关系型数据库进行调优以获得高查询性能可能会比较困难。如果对数据模型优化和对查询调优不起作用,DBA就可以使用缓存系统,比如Redis,它是一个可以提供内存和永久数据存储的键值数据存储系统。

由于Redis能够将数据快速读写至数据存储系统,比起关系型数据库它更具性能优势。但是键值数据存储比较简单,它们没有类似SQL那样的查询语言或是结构化数据模型。取而代之的是,它们包含用键作为标识符并与值相关联的一个简单字典或是哈希模型。DBA可以通过这些键来存储和检索值。

键值存储简单而又快速,这使得它们可以很好地匹配关系型数据库丰富的数据模型和查询功能。有时使用键值和关系型数据库的组合是更好的选择。另外,还有大量支持商业化的键值数据库,包括Redis,Riak和Areospike。

要运行Redis缓存来优化常用查询的性能,首先要对你想要缓存的查询结果进行识别。将注意力集中在那些最频繁使用和耗时的查询上,然后从你要缓存的查询中识别数据。简言之,就是缓存一个查询返回的所有字段值。

该集群中数据的流程为:client——>app——>redis——>mysql——>redis——>client

二.实验环境

1.selinux和firewalld状态为disabled

2.各主机信息如下:

主机 ip
server1(nginx服务器) 172.25.1.1
server2(redisl服务器) 172.25.1.2
server3(mysql数据库) 172.25.1.3

三.实验

配置server1
因为server1之前是做过redis cluster集群的。所以要将之前打开的redis-server的进程杀掉

前期准备:
杀掉redis-server的进程

(1)安装相应的软件,以提供killall命令(killall工具可以杀死所有关键字进程)

[root@server1 7007]# yum insstal psmisc-22.20-11.el7.x86_64 -y

(2)杀掉redis-server的所有进程

扫描二维码关注公众号,回复: 10197271 查看本文章
[root@server1 7007]# killall redis-server

此时再次查看进程,发现已经不存在redis-server的进程了
1.配置nginx服务
源码编译nginx服务

(1)下载nginx对应的压缩包:

[root@server1 ~]# tar zxf nginx-1.16.1.tar.gz
[root@server1 ~]# cd nginx-1.16.1

(2)安装nginx所需的依赖包

[root@server1 nginx-1.16.1]# yum install gcc pcre-devel zlib-devel -y

(3)源码编译并安装nginx:

[root@server1 nginx-1.16.1]# ./configure --prefix=/usr/local/nginx   #预编译
[root@server1 nginx-1.16.1]# make && make install

(4)修改nginx服务对应的配置文件,以使得nginx服务支持php语言

[root@server1 nginx-1.16.1]# cd /usr/local/nginx/
[root@server1 nginx]# ln -s /usr/local/nginx/sbin/nginx /usr/local/sbin/
[root@server1 nginx]# cd conf/
[root@server1 conf]# useradd -u 900 nginx
[root@server1 conf]# vim  nginx.conf
     
     2			user  nginx nginx;
     
     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         }

检测nginx服务并启动

[root@server1 conf]# 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@server1 conf]# nginx

在浏览器中输入172.25.1.1进行测试,以确保nginx服务已经搭建好
2.配置php
下载php对应的安装包及其对应的依赖包,并进行安装,以使得nginx服务支持php语言。

 [root@server1 rhel7]# yum install * -y

在这里插入图片描述
启动 php-fpm

[root@server1 rhel7]# systemctl start php-fpm

查看9000端口确认开启成功
在这里插入图片描述
3.编写redis服务对应的测试文件
编写redis服务对应的测试文件(test.php文件),并将该文件拷贝到nginx服务的默认发布目录中,命名为index.php并进行测试,修改index.php文件,使得该服务指向server2的redis服务,指向server3的mysql数据库

#将第3行的ip改为server2(redis服务器)的ip
#将第10行的ip改为server3(mysql数据库)的ip
#值的注意的是第10行的redis是mysql数据库需要创建的用户,redhat是redis这个用户对应的密码
 [root@server4 html]# ls
50x.html  index.html  test.php
[root@server4 html]# mv test.php index.php
[root@server4 html]# vim index.php

<?php
        $redis = new Redis();
        $redis->connect('172.25.1.2',6379) or die ("could net connect redis server");
  #      $query = "select * from test limit 9";
        $query = "select * from test";
        for ($key = 1; $key < 10; $key++)
        {
                if (!$redis->get($key))
                {
                        $connect = mysql_connect('172.25.1.3','redis','redhat');
                        mysql_select_db(test);
                        $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 < 10; $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>";
        }
?>

配置server2
在 server2 上配置 redis 为 master,因为之前做了主从,关闭 server1与server3 的 redis

 [root@server2 ~]# vim /etc/redis/6379.conf   #需要将之前在最后一行写的slaveof 172.25.1.1 6379这行删掉;
  70 bind 0.0.0.0           #第70行的监听所有端口的内容不用动
 [root@server2 ~]# /etc/init.d/redis_6379 restart  #重新启动redis

删除原来的 key
在这里插入图片描述
配置server3
开启 server3,关闭原来的 mysql,若原来没有mysql则直接安装mariadb

[root@server3 ~]# rpm -qa | grep mysql

卸载原来的 mysql 命令

rpm -e `rpm -qa | grep mysql` --nodeps

安装 mariadb,这里试验用这个就行

[root@server3 ~]# yum install -y mariadb-server

清除原来数据目录里的内容

[root@server3 ~]# cd /var/lib/mysql
[root@server3 mysql]# rm -fr *

启动 mariadb

[root@server3 mysql]# systemctl start mariadb

安全初始化

[root@server3 ~]# mysql_secure_installation  设置mariadb密码,这里设为redhat

登录数据库,授权用户

[root@server3 ~]# mysql -uroot -predhat

MariaDB [(none)]> create database test;
Query OK, 1 row affected (0.00 sec)
MariaDB [(none)]> grant all on test.* to redis@'%' identified by 'redhat';
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> flush privileges;
Query OK, 0 rows affected (0.00 sec)

为 server3 上的 mysql 的 test 库加入一些数据

[root@server3 ~]# cat test.sql 
use test;
CREATE TABLE `test` (`id` int(7) NOT NULL AUTO_INCREMENT, `name` char(8) DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `test` VALUES (1,'test1'),(2,'test2'),(3,'test3'),(4,'test4'),(5,'test5'),(6,'test6'),(7,'test7'),(8,'test8'),(9,'test9');

#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 ;

注释掉的目前用不到,是创建查询的触发器的

导入数据

[root@server3 ~]# mysql -predhat < test.sql

测试一:
在浏览器中输入172.25.1.1进行测试

可以看到导入的数据
注意这里我在nginx中添加了域名解析
在这里插入图片描述

但是刷新一次后,可以看到后面就从 redis 读取数据
在这里插入图片描述
使用命令行也可以看到:

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

测试二:
为了查看浏览器,看到的数据是随着redis服务中的数据的设置而改变,还是随着数据库中的数据的改变而改变

1.在server3登陆数据库,修改数据(将id为1对应的数据改为westos)

 [root@server3 ~]# mysql -uroot -proot
    MariaDB [(none)]> use test;
    MariaDB [test]> update test set name='westos' where id=1;
    MariaDB [test]> select * from test;

在这里插入图片描述
2.在server2查看数据

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

我们可以看到id为1对应的数据,仍然是test1,而并不是数据库中显示的westos。
3.在浏览器中输入172.25.1.1进行查看数据
在这里插入图片描述
结论:

浏览器,看到的数据不是随着数据库中的数据的改变而改变。

到这里,我们已经实现了redis作为mysql的缓存服务器,但是如果更新了mysql,redis中仍然会有对应的key,数据就不会更新。

此时,就会出现mysql和redis数据不一致的情况。所以接下来就要通过mysql触发器将改变的数据同步到redis中

四、实现数据库更新,redis的数据也更新

1.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。

2.这个实验的实现需要使用新的工具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/

<4>注册 UDF 函数

 [root@server3 lib_mysqludf_json-master]# mysql -uroot -predhat
    MariaDB [(none)]> CREATE FUNCTION json_object RETURNS STRING SONAME 'lib_mysqludf_json.so';

在这里插入图片描述
<5>查看函数

[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]# ./configure --libdir=/usr/lib64/mysql/plugin/ --with-mysql     #预编译
[root@server3 gearman-mysql-udf-0.6]# make && make install   #编译与安装

<2>注册 UDF 函数

[root@server3 ~]# mysql -uroot -predhat
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 -predhhat
MariaDB [(none)]> SELECT gman_servers_set('172.25.1.1:4730');

注意:4730为gearmand的端口号
在这里插入图片描述
在这里插入图片描述
4. 编写 mysql 触发器(根据实际情况编写)
也就是家目录下面的test.sql文件
test.sql文件的内容:(这里只用到1,5-9行;2-3行是上个实验需要的内容,所以这里将其注释掉)
在这里插入图片描述
<1>将test.sql文件导入到test数据库中

[root@server3 ~]# mysql -predhat < test.sql  

<2>查看触发器

[root@server3 ~]# mysql -uroot -proot 
MariaDB [(none)]> SHOW TRIGGERS FROM test;

在这里插入图片描述
配置server4
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文件放到/usr/local目录中
在这里插入图片描述

worker.php文件的内容如下:(其中第7行的ip地址指向server2——redis服务器)
[root@server4 local]# cat worker.php 
<?php
$worker = new GearmanWorker();
$worker->addServer();
$worker->addFunction('syncToRedis', 'syncToRedis');
 
$redis = new Redis();
$redis->connect('172.25.1.2', 6379);				#redis服务器
 
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);
}
?>

测试:
1.在server4端:后台运行 worker

 [root@server4 ~]# nohup php /usr/local/worker.php &> /dev/null &
[1] 16450

2.在server3端:更新 mysql 中的数据

[root@server3 ~]# mysql -uroot -predhat
MariaDB [(none)]> use test;
MariaDB [test]> update test set name='redhat' where id=2;

在这里插入图片描述
3.在server2端:查看 redis

[root@server2 ~]# redis-cli 
127.0.0.1:6379> get 2
"redhat"

在这里插入图片描述
4.在浏览器端:刷新测试页面看数据数据同步
结论:
在这里插入图片描述
mysql数据库端的数据的修改,影响了redis端的数据,也影响了浏览器端的数据。即mysql数据库,redis端和nginx端的数据实现了同步。表示实验成功。

发布了148 篇原创文章 · 获赞 1 · 访问量 3000

猜你喜欢

转载自blog.csdn.net/qq_36417677/article/details/104906635