简介
项目中,MySQL数据库服务器有时会位于另外一台主机,需要通过网络来访问数据库;即使应用程序与MySQL数据库在同一个主机中,访问MySQL也涉及到磁盘IO操作(MySQL也有一些数据预读技术,能够减少磁盘IO读写,此部分后续继续研究),总之,直接从MySQL中读取数据不如直接从内存中读取数据来的效率高。为了提高数据库访问效率,人们采用了各种各样的方法,其中方法之一就是使用一个给予内存的缓存系统放置在数据库和应用程序之间。在查找数据的时候,首先从内存中查找,如果找到则使用,如果没有找到,那么再真正访问数据库。这种方法在一些场景下(例如:频繁查找相同数据)能够提高系统的整体效率。
读取步骤:
- client读取redis,如果命中返回结果,如果没有命中转到2.
- client读取数据库,在数据库中没有查到,返回空;在数据库中查到了,返回查到的结果并更新Redis。
写入步骤: - client修改/删除或者新增数据到MySQL。
- MySQL的触发器调用用户自定义的UDF。
- UDF把修改/删除或者新增的数据更新到redis中。
实验环境
主机 | ip | 服务 |
server1 | 172.25.62.1 | nginx |
server2 | 172.25.62.2 | redis |
server3 | 172.25.62.3 | mysql |
搭建步骤:
在server1
1.安装nginx
因为要进行缓存的测试,所以要用一台主机作为服务器的前端提供访问。
[root@server1 ~]# tar zxf nginx-1.16.0.tar.gz
[root@server1 nginx-1.16.0]# ./configure --prefix=/usr/local/nginx
[root@server1 nginx-1.16.0]# make && make install
进入目录进行编译安装。
2.修改配置
[root@server1 ~]# vim /usr/local/nginx/conf/nginx.conf
35 server {
36 listen 80;
37 server_name localhost;
38 location / {
39 root html;
40 index index.php index.html index.htm;
41 }
42 error_page 500 502 503 504 /50x.html;
43 location = /50x.html {
44 root html;
45 }
46
47 location ~ \.php$ {
48 root html;
49 fastcgi_pass 127.0.0.1:9000;
50 fastcgi_index index.php;
51 #fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
52 include fastcgi.conf;
53 }
修改nginx主配置文件,使浏览器默认访问php页面。
[root@server1 ~]#/usr/local/nginx/sbin/nginx -t
[root@server1 ~]#/usr/local/nginx/sbin/nginx
启动nginx。
3.编写php默认发布页
[root@server1 ~]# vim /usr/locacl/nginx/html/index.html
1 <?php
2 $redis = new Redis();
3 $redis->connect('172.25.62.2',6379) or die ("could net connect redis server"); ##安装redis的ip
4 # $query = "select * from test limit 9";
5 $query = "select * from test";
6 for ($key = 1; $key < 10; $key++)
7 {
8 if (!$redis->get($key))
9 {
10 $connect = mysql_connect('172.25.62.3','redis','redhat'); ##安装mysql的ip
11 mysql_select_db(test);
12 $result = mysql_query($query);
13 //如果没有找到$key,就将该查询sql的结果缓存到redis
14 while ($row = mysql_fetch_assoc($result))
15 {
16 $redis->set($row['id'],$row['name']);
17 }
18 $myserver = 'mysql';
19 break;
20 }
21 else
22 {
23 $myserver = "redis";
24 $data[$key] = $redis->get($key);
25 }
26 }
27
28 echo $myserver;
29 echo "<br>";
30 for ($key = 1; $key < 10; $key++)
31 {
32 echo "number is <b><font color=#FF0000>$key</font></b>";
33
34 echo "<br>";
35
36 echo "name is <b><font color=#FF0000>$data[$key]</font></b>";
37
38 echo "<br>";
39 }
40 ?>
4.安装php以及相关软件
[root@server1 rhel7]# ls
gearmand-1.1.12-18.el7.x86_64.rpm
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
libzip-0.10.1-8.el7.x86_64.rpm
openssl-1.0.2k-16.el7.x86_64.rpm
openssl-libs-1.0.2k-16.el7.x86_64.rpm
php-cli-5.4.16-46.el7.x86_64.rpm
php-common-5.4.16-46.el7.x86_64.rpm
php-fpm-5.4.16-46.el7.x86_64.rpm
php-mysql-5.4.16-46.el7.x86_64.rpm
php-pdo-5.4.16-46.el7.x86_64.rpm
php-pecl-gearman-1.1.2-1.el7.x86_64.rpm
php-pecl-igbinary-1.2.1-1.el7.x86_64.rpm
php-pecl-redis-2.2.8-1.el7.x86_64.rpm
php-process-5.4.16-46.el7.x86_64.rpm
php-xml-5.4.16-46.el7.x86_64.rpm
[root@server1 rhel7]# yum install -y *
安装上面所有软件。
[root@server1 rhel7]# systemctl start php-fpm
开启php。
在server2
1.安装redis
详见Redis的主从复制和高可用性中redis的安装部分。
安装后的redis不能作为主从复制的从节点,必须本身为master节点,如果设置了要修改文件。
[root@server2 ~]# vim /etc/redis/6379.conf
将主从复制的内容删除就可以了。
2.开启redis
[root@server2 ~]# redis-cli
开启redis,测试功能是否正常。
在server3
1.安装mariadb,进行安全初始化
[root@server3 ~]# yum install -y mariadb-server
[root@server3 ~]# systemctl start mariadb
安装并开启mysql。
[root@server3 ~]# mysql_secure_installation
安全初始化。
2.对数据库进行授权
[root@server3 ~]# mysql -p
MariaDB [(none)]> create database test;
MariaDB [(none)]> grant all on test.* to redis@'%' identified by 'redhat';
MariaDB [(none)]> flush privileges;
创建test库,对用户和test库进行授权。
3.将数据导入数据库
[root@server3 ~]# vim test.sql
1 use test;
2 CREATE TABLE `test` (`id` int(7) NOT NULL AUTO_INCREMENT, `name` char(8) D EFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
3 INSERT INTO `test` VALUES (1,'test1'),(2,'test2'),(3,'test3'),(4,'test4'), (5,'test5'),(6,'test6'),(7,'test 7'),(8,'test8'),(9,'test9');
4
5 #DELIMITER $$
6 #CREATE TRIGGER datatoredis AFTER UPDATE ON test FOR EACH ROW BEGIN
7 # SET @RECV=gman_do_background('syncToRedis', json_object(NEW.id as `id `, NEW.name as `name`));
8 # END$$
9 #DELIMITER ;
编写库文件。
[root@server3 ~]# mysql -predhat < test.sql
将数据导入数据库,下面是导入的内容。
这样就完成基本配置了。
测试:
输入做前端的server1的ip进行测试。
首先我们看到的是mysql中的数据,访问到mysql的数据之后,这些数据回被缓存到redis里,第二此访问就不再访问mysql,而是从redis缓存中取数据。
第二次访问的是redis中的数据。
redis和mysql的数据同步更新
虽然redis可以作为mysql的缓存,但是当mysql中的数据更新时,访问到的redis中的内容是没有更新的,所以要设置两个库的同步更新。
如图,将test表中的test1改为redhat,之后进行访问。
可以看到数据没有更新。
在server3
1.安装相关软件
[root@server3 ~]# yum install mariadb-devel -y
安装mariadb-devel。
[root@server3 ~]# unzip lib_mysqludf_json-master.zip
获取lib_mysqludf包并解压。
[root@server3 lib_mysqludf_json-master]# gcc $(mysql_config --cflags) \
-shared -fPIC -o lib_mysqludf_json.so lib_mysqludf_json.c
进入目录进行编译。
[root@server3 ~]# cp lib_mysqludf_json-master/lib_mysqludf_json.so /usr/lib64/mysql/plugin/
将编译出的模块放到mysql插件目录。
MariaDB [(none)]> show global variables like 'plugin_dir';
在数据库中查看插件是否加入。
[root@server3 ~]# tar zxf gearman-mysql-udf-0.6.tar.gz
[root@server3 gearman-mysql-udf-0.6]# pwd
/root/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
编译安装gearman插件。
[root@server3 rhel7]# yum install -y libevent-devel-2.0.21-4.el7.x86_64.rpm libgearman-*
安装libevent-devel,libgearman,libgearman-devel。
2.在数据库内进行操作
MariaDB [(none)]> CREATE FUNCTION json_object RETURNS STRING SONAME 'lib_mysqludf_json.so';
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';
注册udf函数。
MariaDB [(none)]> select * from mysql.func;
查看函数,指定german服务信息。
MariaDB [(none)]> SELECT gman_servers_set('172.25.62.1:4730');
3.编写mysql触发器
[root@server3 ~]# vim 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 -uroot -predhat
导入数据。
MariaDB [(none)]> show triggers from test;
查看状态,这样,在mysql端的操作就完成了。
在server1
1.安装gearmand
[root@server3 ~]# gearmand-1.1.12-18.el7.x86_64.rpm
获取gearmand-1.1.12-18.el7.x86_64.rpm包进行安装。
[root@server1 rhel7]# systemctl start gearmand
开启服务。
2.编写worker.php
[root@server1 local]# pwd
/usr/local
[root@server1 local]# vim worker.php
1 <?php
2 $worker = new GearmanWorker();
3 $worker->addServer();
4 $worker->addFunction('syncToRedis', 'syncToRedis');
5
6 $redis = new Redis();
7 $redis->connect('172.25.62.2', 6379); ##修改ip为redis端的ip
8
9 while($worker->work());
10 function syncToRedis($job)
11 {
12 global $redis;
13 $workString = $job->workload();
14 $work = json_decode($workString);
15 if(!isset($work->id)){
16 return false;
17 }
18 $redis->set($work->id, $work->name);
19 }
20 ?>
[root@server1 ~]# nohup php /usr/local/worker.php &> /dev/null &
开启worker.php进程。
测试:
在server3修改test表内容
MariaDB [test]> update test set name='Linux' where id=2;
在浏览器查看。
可以看到,test2的内容随着数据库更新了,由于test1是在设定之前就修改了,所以没有更新。