1.读写分离的背景

实际的生产环境当中,客户端对数据库的读操作都是直接找redis拿数据的
如果redis缓存里面没有数据,那么就会去找mysql拿数据,并且给redis中缓存一份
redis中的数据有两种情况不能使用:数据过期了或者mysql中的数据更新了 用户读的时候访问redis,用户写的时候访问mysql
实际上读的需求量是很大的,redis刚好是把数据缓存在内存当中,响应速度也快 也可以降低我们后台mysql数据库的压力

一般对于高并发的系统来说,搭建一个健壮的缓存系统是不可避免的。
单机的reids的QPS可能只能上万,如果有再高并发的场景,单机是不能搞定的,就会有它的系统瓶颈。
一般来说缓存是用来支撑高并发读,这时候我们可能就会想到读写分离;
读写分离是用来处理读的并发量大,而写的并发量小的场景。

redis配合mysql

数据访问流程:client -> app -> redis -> mysql -> redis -> client
客户端用app访问,先在redis里读数据,因为快,redis没有才去mysql读,读完保存在redis里,然后返回客户端,下次再读就快

此次实验是在上一篇redis的基础上做的

killall redis-server
#没有killall命令 yum whatprovides /usr/bin/killall
#[root@server1 ~]# yum install -y psmisc-22.20-11.el7.x86_64

在这里插入图片描述在这里插入图片描述
杀死之前做得集群
在这里插入图片描述

[root@server1 ~]# tar zxf nginx-1.17.4.tar.gz 
[root@server1 ~]# ls
nginx-1.17.4  nginx-1.17.4.tar.gz  redis
[root@server1 ~]# cd nginx-1.17.4
[root@server1 nginx-1.17.4]# ls
auto  CHANGES  CHANGES.ru  conf  configure  contrib  html  LICENSE  man  README  src
[root@server1 nginx-1.17.4]# vim auto/cc/gcc 
[root@server1 nginx-1.17.4]# ./configure --prefix=/usr/local/nginx
make && make install

在这里插入图片描述在这里插入图片描述在这里插入图片描述编译
在这里插入图片描述在这里插入图片描述在这里插入图片描述
单线程:当多个线程同时写,谁拿到锁谁就可以写,太麻烦了,,因此单线程可以解决。

#######中间件######
lnmp  

nginx 编译安装 不需要openssl
此处的rhel7=(php) 
php端口:9000
 nginx端口:80
server1 nginx php
server2 redis数据缓存
server3 mysql数据库

##首先在server1配置好nginx
        location / {
            root   html;
            index  index.php index.html index.htm;
        }

        ...

        location ~ \.php$ {
            root           html;
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            #fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
            include        fastcgi.conf;
        }

#启动并测试nginx





###启动php-fpm
[root@server1 ~]# systemctl start php-fpm

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

##在server2上配置redis为master,因为之前做了主从,关闭server1的redis,
因为不是主从了,所以需要把之前server2   /etc/redis/6379.conf最后一行删除,如果没有就算了。

在这里插入图片描述在这里插入图片描述server1的redis也停掉
在这里插入图片描述

#删除原来的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)

在这里插入图片描述

##配置测试页面
[root@server1 ~]# mv test.php /usr/local/nginx/html/   这样php才能和nginx.redis联系起来麻
[root@server1 html]# mv test.php index.php

在这里插入图片描述

##再开启server3,关闭原来的mysql(如果没有就直接yum安装即可)
[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)

构建一个库 前端用户获取 授权所有的人都可以在test数据库 redis用户可以来取
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)

在这里插入图片描述

server2 检查6379 是否开启(redis)
server1: 如果server2 6379 redis 没有就去后端 如果在redis获取不到就到后端数据库获取数据 注意密码  
server3: 上传一张表 test.sql
浏览器访问 第一次访问在后端,第二次就在redis缓存里面了  之后就都在redis

在这里插入图片描述

##修改server1上nginx的发布文件test.php
vim test.php

  3         $redis->connect('172.25.0.2',6379) or die ("could net connect r    edis server");
 10                         $connect = mysql_connect('172.25.0.3','redis','    redhat');

注意:我之前重命名了,所以此处是vim index.php哦
在这里插入图片描述

##为server3上的mysql的test库加入一些数据
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

发现test数据库里面没有任何表格

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

#浏览器访问测试
172.25.0.1
可以看到导入的数据

mysql
number is 1
name is
number is 2
name is
number is 3
name is
number is 4
name is
number is 5
name is
number is 6
name is
number is 7
name is
number is 8
name is
number is 9
name is 

因为再在上面我已经重命名为index.php所以此处应该访问172.25.63.1/index.php!!!
在这里插入图片描述
#但是刷新一次后,可以看到后面就从redis读取数据

redis
number is 1
name is test1
number is 2
name is test2
number is 3
name is test3
number is 4
name is test4
number is 5
name is test5
number is 6
name is test6
number is 7
name is test7
number is 8
name is test8
number is 9
name is test9
浏览器访问 第一次访问在后端,第二次就在redis缓存里面了  之后就都在redis

在这里插入图片描述在这里插入图片描述在这里插入图片描述

#使用命令行也可以看到
[root@server2 ~]# redis-cli 
127.0.0.1:6379> get 1
"test1"
127.0.0.1:6379> get 2
"test2"

##这个时候有个问题,如果此时mysql数据发生变更,redis会同步吗?
#在server3上
MariaDB [test]> update test set name='westos' where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

#变更后发现,redis里没有变,浏览器也看不到变化,但是在redis里做的变化能看到
127.0.0.1:6379> set 2 redhat
OK
#刷新浏览器,看到变化,这样显然不合理

在这里插入图片描述在这里插入图片描述

接下来实现Mysql更新自动触发redis进行修改,这样才能实现真正的读写分离 。

目前我们实现了简单的读写分离
客户端读的时候去找redis缓存;客户端写的时候去找mysql
但是存在一个问题:当mysql数据库中的数据有所变化的时候,redis缓存并不能实时同步
接下来我将实现一旦mysql有所变化,利马触发redis更新所缓存的数据

二.Redis 如何保持和MySQL数据一致

在数据库改了之后redis没有更新

钩子函数
server1 开启钩子函数
server3 进入钩子函数目录编译
在这里插入图片描述

配置gearmand

1.简介:

Gearmand是一个用来把工作委派给其它机器、分布式的调用更适合做某项工作的机器、并发的做某项工作在多个调用间做负载均衡、或用来调用其它语言的函数的系统。
简单来讲,就是客户端程序把请求提交给 gearmand,gearmand 会把请求转发给合适的 worker 来处理这个请求,最后还通过 gearmand 返回结果。

2.运行流程:

Client --> Job --> Worker

1、Client 请求发起者,客户端程序可以是任何一种语言,C 、PHP 、Perl 、Python 等。
2、Job 请求调度者,负载协调把 Client 发出的请求转发给合适的 Worker。
3、Worker 请求处理者,处理 Job 分发来的请求,可以是任何一种语言

在server1上启动
[root@server1 ~]# systemctl start gearmand

在server3上解压lib_mysqludf_json-master.zip
unzip lib_mysqludf_json-master.zip

在这里插入图片描述在这里插入图片描述

#安装mariadb-devel
[root@server3 lib_mysqludf_json-master]# yum install -y mariadb-devel.x86_64

在这里插入图片描述

#编译模块(文档上有)
[root@server3 lib_mysqludf_json-master]# gcc $(mysql_config --cflags) -shared -fPIC -o lib_mysqludf_json.so lib_mysqludf_json.c

在这里插入图片描述解决依赖性
在这里插入图片描述

#将模块放到mysql插件目录
[root@server3 ~]# cp lib_mysqludf_json-master/lib_mysqludf_json.so /usr/lib64/mysql/plugin/

#在server3上查看
MariaDB [(none)]> show global variables like 'plugin_dir';
+---------------+--------------------------+
| Variable_name | Value                    |
+---------------+--------------------------+
| plugin_dir    | /usr/lib64/mysql/plugin/ |
+---------------+--------------------------+
1 row in set (0.00 sec)

#注册udf函数
MariaDB [(none)]> CREATE FUNCTION json_object RETURNS STRING SONAME 'lib_mysqludf_json.so';

在这里插入图片描述然后select * from mysql.func 可以查看到模块lib_mysqludf_json.so

#安装插件管理gearman的分布式队列
[root@server3 ~]# tar zxf gearman-mysql-udf-0.6.tar.gz

#先安装libgearman,从server1上scp

[root@server3 ~]# yum install -y libevent-devel-2.0.21-4.el7.x86_64.rpm libgearman-*

#编译安装gearman插件
[root@server3 redis]# tar zxf gearman-mysql-udf-0.6.tar.gz
[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

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
#注册udf函数
mysql -p

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

##查看函数
MariaDB [(none)]> 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 |
+--------------------+-----+-------------------------+----------+
3 rows in set (0.00 sec)

##指定gman服务信息
MariaDB [(none)]> SELECT gman_servers_set('172.25.0.1:4730');

在这里插入图片描述

##编写mysql触发器
[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 -p < test.sql

在这里插入图片描述在这里插入图片描述在这里插入图片描述

##查看触发器
MariaDB [(none)]> SHOW TRIGGERS FROM test;


##编写gman的worker端
[root@server1 ~]# cp worker.php /usr/local/
[root@server1 local]# vim worker.php 
  7 $redis->connect('172.25.0.2', 6379);

在这里插入图片描述在这里插入图片描述

##后台运行worker
[root@server1 ~]# nohup php /usr/local/worker.php &> /dev/null &

在这里插入图片描述

##修改数据库内容
MariaDB [test]> update test set name='westos' where id=2;

在这里插入图片描述

##在redis上查看
127.0.0.1:6379> get 2
"westos"

在这里插入图片描述

##页面查看,数据同步
redis
number is 1
name is redhat
number is 2
name is westos
number is 3
name is test3
number is 4
name is test4
number is 5
name is test5
number is 6
name is test6
number is 7
name is test7
number is 8
name is test8
number is 9
name is test9

在这里插入图片描述
做完实验,停掉服务
在这里插入图片描述在这里插入图片描述在这里插入图片描述

小科普写简历
在这里插入图片描述


版权声明:本文为asufeiya原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/asufeiya/article/details/103019644