对一个关系型数据库进行调优以获得高查询性能可能会比较困难。如果对数据模型优化和对查询调优不起作用,DBA就可以使用缓存系统,比如Redis,它是一个可以提供内存和永久数据存储的键值数据存储系统。
由于Redis能够将数据快速读写至数据存储系统,比起关系型数据库它更具性能优势。但是键值数据存储比较简单,它们没有类似SQL那样的查询语言或是结构化数据模型。取而代之的是,它们包含用键作为标识符并与值相关联的一个简单字典或是哈希模型。DBA可以通过这些键来存储和检索值。
键值存储简单而又快速,这使得它们可以很好地匹配关系型数据库丰富的数据模型和查询功能。有时使用键值和关系型数据库的组合是更好的选择。另外,还有大量支持商业化的键值数据库,包括Redis,Riak和Areospike。
要运行Redis缓存来优化常用查询的性能,首先要对你想要缓存的查询结果进行识别。将注意力集中在那些最频繁使用和耗时的查询上,然后从你要缓存的查询中识别数据。简言之,就是缓存一个查询返回的所有字段值。
该集群中数据的流程为:
client——>app——>redis——>mysql——>redis——>client
1.selinux和firewalld状态为disabled
2.各主机信息如下:
主机 | ip |
---|---|
server2(redis服务器) | 172.25.63.2 |
server3(mysql数据库) | 172.25.63.3 |
server4(nginx服务器) | 172.25.63.4 |
因为server4之前是做过redis cluster集群的。所以要将之前打开的redis-server的进程杀掉
杀掉redis-server的进程
(1)安装相应的软件,以提供killall命令(killall工具可以杀死所有关键字进程)
[root@server4 7008]# yum install psmisc-22.20-11.el7.x86_64 -y
(2)杀掉redis-server的所有进程
[root@server4 7008]# killall redis-server
此时再次查看进程,发现已经不存在redis-server的进程了
源码编译nginx服务
(1)下载nginx对应的压缩包:
[root@server4 ~]# tar zxf nginx-1.16.1.tar.gz
[root@server4 ~]# cd nginx-1.16.1
(2)安装nginx所需的依赖包
[root@server4 nginx-1.16.1]# yum install gcc pcre-devel zlib-devel -y
(4)源码编译并安装nginx:
[root@server4 nginx-1.16.1]# ./configure --prefix=/usr/local/nginx #预编译
[root@server4 nginx-1.16.1]# make && make install
(5)修改nginx服务对应的配置文件,以使得nginx服务支持php语言
[root@server4 nginx-1.16.1]# cd /usr/local/nginx/
[root@server4 nginx]# ln -s /usr/local/nginx/sbin/nginx /usr/local/sbin/
[root@server4 nginx]# cd conf/
[root@server4 conf]# useradd -u 900 nginx
[root@server4 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 }
(6)检测nginx服务
[root@server4 conf]# nginx -t
(7)启动nginx服务
[root@server4 conf]# nginx
在浏览器中输入172.25.63.4进行测试,以确保nginx服务已经搭建好
下载php对应的安装包及其对应的依赖包,并进行安装,以使得nginx服务支持php语言。
[root@server4 rhel7]# yum install * -y
[root@server4 rhel7]# systemctl start php-fpm
查看9000端口确认开启成功
[root@server4 rhel7]# netstat -antlupe | grep 9000
tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN 0 68512 21269/php-fpm: mast
编写redis服务对应的测试文件(test.php文件),并将该文件拷贝到nginx服务的默认发布目录中,命名为index.php并进行测试,修改index.php文件,使得该服务指向server2的redis服务,指向server3的mysql数据库
#将第3行的ip改为server2的ip
#将第10行的ip改为server3的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.63.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.63.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 "
";
for ($key = 1; $key < 10; $key++)
{
echo "number is $key";
echo "
";
echo "name is $data[$key]";
echo "
";
}
?>
在 server2 上配置 redis 为 master,因为之前做了主从,关闭 server4 的 redis
[root@server2 ~]# vim /etc/redis/6379.conf #需要将之前在最后一行写的slaveof 172.25.63.4 6379这行删掉;
70 bind 0.0.0.0 #第70行的监听所有端口的内容不用动
删除原来的 key
[root@server2 ~]# redis-cli
127.0.0.1:6379> get name
“dd”
127.0.0.1:6379> DEL name
(integer) 1
127.0.0.1:6379> get name
(nil)
开启 server3,关闭原来的 mysql,若原来没有mysql则直接安装mariadb
[root@server3 ~]# rpm -qa | grep mysql
mysql-community-libs-5.7.24-1.el7.x86_64
mysql-community-server-5.7.24-1.el7.x86_64
mha4mysql-node-0.58-0.el7.centos.noarch
mysql-community-common-5.7.24-1.el7.x86_64
mysql-community-client-5.7.24-1.el7.x86_64
mysql-community-libs-compat-5.7.24-1.el7.x86_64
卸载原来的 mysql
[root@server3 ~]# 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
## 这 里 密 码 可 以 设 置 为 简 单 的 , 如redhat
登录数据库,授权用户
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.63.4进行测试
可以看到导入的数据
使用命令行也可以看到:
[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;
2.在server2查看数据
[root@server2 ~]# redis-cli
127.0.0.1:6379> get 1
"test1"
我们可以看到id为1对应的数据,仍然是test1,而并不是数据库中显示的westos。
3.在浏览器中输入172.25.63.4进行查看数据
结论:
浏览器,看到的数据不是随着数据库中的数据的改变而改变。
到这里,我们已经实现了redis作为mysql的缓存服务器,但是如果更新了mysql,redis中仍然会有对应的key,数据就不会更新。
此时,就会出现mysql和redis数据不一致的情况。所以接下来就要通过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。
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)
[root@server3 ~]# yum install gcc -y
[root@server3 ~]# yum install mariadb-devel -y #因为数据库安装的是mariadb,所以这里安装的包是mariadb-devel,而不是,mysql-devel
使用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 -predhat
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;
这个插件是用来管理调用 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.63.4:4730');
也就是家目录下面的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;
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服务器)
[root@server4 local]# cat worker.php
<?php
$worker = new GearmanWorker();
$worker->addServer();
$worker->addFunction('syncToRedis', 'syncToRedis');
$redis = new Redis();
$redis->connect('172.25.63.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] 2087
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端的数据实现了同步。表示实验成功。