Redis 集群及将 Redis 作为 mysql 的缓存服务器实战

一、Redis简介

redis 是一个高性能的 key-value 数据库。 redis 的出现,很大程度补偿了memcached 这类 keyvalue 存储的不足,在部分场合可以对关系数据库起到很好的补充作用。它提供了 Python,Ruby,Erlang,PHP 客户端,使用很方便。Redis 的所有数据都是保存在内存中,然后不定期的通过异步方式保存到磁盘上(这称为“半持久化模式”);也可以把每一次数据变化都写入到一个 appendonly file(aof)里面(这称为“全持久化模式”)。

二、Redis 安装

本次实验所用所有安装的rpm包及源码资源均已上传,需要的可以下载下来
地址:
redis.tar.gz.0
redis.tar.gz.1
需要将这两个都下载下来,并放到同一目录下,然后执行

cat redis.tar.gz.* | tar -zxv

即可解开

1.下载安装

redis官网:https://redis.io/
下载:http://download.redis.io/releases/redis-4.0.2.tar.gz

[root@server2 ~]# yum install -y gcc
[root@server2 ~]# wget http://download.redis.io/releases/redis-4.0.2.tar.gz
[root@server2 ~]# tar -zxf redis-4.0.2.tar.gz
[root@server2 ~]# cd redis-4.0.2
[root@server2 redis-4.0.2]# make && make install
[root@server2 redis-4.0.2]# ls /usr/local/bin/
alien  redis-benchmark  redis-check-aof  redis-check-rdb  redis-cli  redis-sentinel  redis-server

这些可执行文件的作用如下:
redis-server: Redis 服务主程序。
redis-cli: Redis 客户端命令行工具,也可以用 telnet 来操作。
redis-benchmark: Redis 性能测试工具,用于测试读写性能。
redis-check-aof:检查 redis aof 文件完整性,aof 文件持久化记录服务器执行的所有写操作命令,用于还原数据。
redis-check-dump:检查 redis rdb 文件的完整性,rdb 就是快照存储, 即按照一定的策略周期性的将数据保存到磁盘,是默认的持久化方式。
redis-sentinel:redis-sentinel 是集群管理工具,主要负责主从切换。

这里写图片描述

2.配置并启动服务

[root@server2 redis-4.0.2]# cd utils/
[root@server2 utils]# ./install_server.sh

Welcome to the redis service installer
This script will help you easily set up a running redis server

Please select the redis port for this instance: [6379] 
Selecting default: 6379
Please select the redis config file name [/etc/redis/6379.conf] 
Selected default - /etc/redis/6379.conf
Please select the redis log file name [/var/log/redis_6379.log] 
Selected default - /var/log/redis_6379.log
Please select the data directory for this instance [/var/lib/redis/6379] 
Selected default - /var/lib/redis/6379
Please select the redis executable path [/usr/local/bin/redis-server] 
Selected config:
Port           : 6379
Config file    : /etc/redis/6379.conf
Log file       : /var/log/redis_6379.log
Data dir       : /var/lib/redis/6379
Executable     : /usr/local/bin/redis-server
Cli Executable : /usr/local/bin/redis-cli
Is this ok? Then press ENTER to go on or Ctrl-C to abort.
Copied /tmp/6379.conf => /etc/init.d/redis_6379
Installing service...
Successfully added to chkconfig!
Successfully added to runlevels 345!
Starting Redis server...
Installation successful!
[root@server2 utils]# netstat -antlp |grep redis
tcp        0      0 127.0.0.1:6379              0.0.0.0:*                   LISTEN      4733/redis-server 1

redis 主配置文件为/etc/redis/6379.conf
这里只在本机做测试,所以不做更改了,如果外部主机进行访问,需要设置bind 和port两个参数,默认监听本机所有网络接口,redis 服务的端口号是6379,可根据需要做相应修改

#bind 127.0.0.1
bind 0.0.0.0

#port 6379
port 6380

3.Redis 客户端使用

[root@server2 utils]# redis-cli 
127.0.0.1:6379> config get *
  1) "dbfilename"
  2) "dump.rdb"
  3) "requirepass"
  4) ""
  5) "masterauth"
  6) ""
  7) "cluster-announce-ip"
  8) ""

上面说的可以通过修改配置文件来修改配置,另外还可以使用 CONFIG set 命令来修改配置,但重启服务后会读取 redis.conf 文件配置。

127.0.0.1:6379> CONFIG GET loglevel
1) "loglevel"
2) "notice"
127.0.0.1:6379> CONFIG SET loglevel "debug"
OK

三、Redis集群

1.概述

  • 节点自动发现
  • slave->master 选举,集群容错
  • 所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.
  • 节点的fail是通过集群中超过半数的节点检测失效时才生效.
  • 客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可

redis-cluster选举:容错

  • 领着选举过程是集群中所有master参与,如果半数以上master节点与master节点通信超过(cluster-node-timeout),认为当前master节点挂掉.
  • 什么时候整个集群不可用(cluster_state:fail),当集群不可用时,所有对集群的操作做都不可用,收到((error) CLUSTERDOWN The cluster is down)错误
    • 如果集群任意master挂掉,且当前master没有slave.集群进入fail状态,也可以理解成进群的slot映射[0-16383]不完成时进入fail状态.
    • 如果进群超过半数以上master挂掉,无论是否有slave集群进入fail状态.

2.实验环境

操作系统:redhat6.5

hostnameip服务
server2172.25.27.2redis
serer3172.25.27.3

测试我们选择2台服务器,分别为:192.168.1.237,192.168.1.238.每分服务器有3个节点。

2.redis cluster安装

刚才我们已经安装好了,接下来创建节点

3.创建redis节点

[root@server2 ~]# /etc/init.d/redis_6379 stop
[root@server2 ~]# cp redis-4.0.2/src/redis-trib.rb /usr/local/bin/    ##从刚才解压的文件里将redis-trib.rb拷贝到/usr/local/bin/目录下,或者将其添加进系统环境变量即可

[root@server2 ~]# mkdir -p /usr/local/redis-cluster/3000{1..8}     ##需要多少节点就添加多少个,我这里添加了8个
[root@server2 ~]# cp /etc/redis/6379.conf /usr/local/redis-cluster/30001/
[root@server2 ~]# vim /usr/local/redis-cluster/30001/redis.conf

daemonize yes       ##redis后台运行
pidfile /usr/local/redis-cluster/30001/redis.pid
logfile /usr/local/redis-cluster/30001/redis.log
port 30001
dir /usr/local/redis-cluster/30001/
cluster-enabled yes     ##开启集群
cluster-config-file cluster.conf        ##集群的配置,配置文件cluster.conf首次启动自动生成,分别在对应的3000*目录下
cluster-node-timeout 10000      ##请求超时
appendonly yes      ##aof日志开启  有需要就开启,它会每次写操作都记录一条日志

[root@server2 ~]# sed 's/30001/30002/g' /usr/local/redis-cluster/30001/redis.conf >/usr/local/redis-cluster/30002/redis.conf
[root@server2 ~]# sed 's/30001/30003/g' /usr/local/redis-cluster/30001/redis.conf >/usr/local/redis-cluster/30003/redis.conf
[root@server2 ~]# sed 's/30001/30004/g' /usr/local/redis-cluster/30001/redis.conf >/usr/local/redis-cluster/30004/redis.conf
[root@server2 ~]# sed 's/30001/30005/g' /usr/local/redis-cluster/30001/redis.conf >/usr/local/redis-cluster/30005/redis.conf
[root@server2 ~]# sed 's/30001/30006/g' /usr/local/redis-cluster/30001/redis.conf >/usr/local/redis-cluster/30006/redis.conf
[root@server2 ~]# sed 's/30001/30007/g' /usr/local/redis-cluster/30001/redis.conf >/usr/local/redis-cluster/30007/redis.conf
[root@server2 ~]# sed 's/30001/30008/g' /usr/local/redis-cluster/30001/redis.conf >/usr/local/redis-cluster/30008/redis.conf

[root@server2 ~]# redis-server /usr/local/redis-cluster/30001/redis.conf
[root@server2 ~]# redis-server /usr/local/redis-cluster/30002/redis.conf
[root@server2 ~]# redis-server /usr/local/redis-cluster/30003/redis.conf
[root@server2 ~]# redis-server /usr/local/redis-cluster/30004/redis.conf
[root@server2 ~]# redis-server /usr/local/redis-cluster/30005/redis.conf
[root@server2 ~]# redis-server /usr/local/redis-cluster/30006/redis.conf
##这里先起六个节点,另外两台暂时不起
[root@server2 ~]# ps -ef | grep 3000*
root      4797     1  0 20:46 ?        00:00:00 redis-server *:30001 [cluster]                        
root      4802     1  0 20:46 ?        00:00:00 redis-server *:30002 [cluster]                        
root      4807     1  0 20:46 ?        00:00:00 redis-server *:30003 [cluster]                        
root      4812     1  0 20:46 ?        00:00:00 redis-server *:30004 [cluster]                        
root      4817     1  0 20:46 ?        00:00:00 redis-server *:30005 [cluster]                        
root      4822     1  0 20:46 ?        00:00:00 redis-server *:30006 [cluster]                        
root      4827  1018  0 20:49 pts/0    00:00:00 grep 3000*

4.创建集群

官方提供了一个工具:redis-trib.rb(/usr/local/redis-3.2.1/src/redis-trib.rb) ,它是用ruby写的一个程序,所以我们需要安装ruby

[root@server2 ~]# wget http://mirror.centos.org/centos/6/os/x86_64/Packages/rubygems-1.3.7-5.el6.noarch.rpm
[root@server2 ~]# yum install rubygems-1.3.7-5.el6.noarch.rpm -y
[root@server2 ~]# gem install redis -v 3.3.5  ##需要联网,等一会就好了
[root@server2 ~]# gem list

*** LOCAL GEMS ***

redis (3.3.5)

[root@server2 ~]# redis-trib.rb create --replicas 1 127.0.0.1:30001 127.0.0.1:30002 127.0.0.1:30003 127.0.0.1:30004 127.0.0.1:30005 127.0.0.1:30006
##创建集群

>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
127.0.0.1:30001
127.0.0.1:30002
127.0.0.1:30003
Adding replica 127.0.0.1:30004 to 127.0.0.1:30001
Adding replica 127.0.0.1:30005 to 127.0.0.1:30002
Adding replica 127.0.0.1:30006 to 127.0.0.1:30003
M: 7d285e51748c1683599dd31c6e27caf806867e2f 127.0.0.1:30001
   slots:0-5460 (5461 slots) master
M: 8504c51e42a572219cc95fb3510d8156ed274a69 127.0.0.1:30002
   slots:5461-10922 (5462 slots) master
M: 42d80140057ce31ec972b7079e9cb20d7f0f5ca6 127.0.0.1:30003
   slots:10923-16383 (5461 slots) master
S: 2382b55e7e8f2d4119ed265e1aa4e1d10e9c6a6d 127.0.0.1:30004
   replicates 7d285e51748c1683599dd31c6e27caf806867e2f
S: e9e0cd3990840c29ae279ddc20b3f946b72a383b 127.0.0.1:30005
   replicates 8504c51e42a572219cc95fb3510d8156ed274a69
S: e185c034df6eb0b5e513d15e30777463ceef82a8 127.0.0.1:30006
   replicates 42d80140057ce31ec972b7079e9cb20d7f0f5ca6
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join..
>>> Performing Cluster Check (using node 127.0.0.1:30001)
M: 7d285e51748c1683599dd31c6e27caf806867e2f 127.0.0.1:30001
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
S: e9e0cd3990840c29ae279ddc20b3f946b72a383b 127.0.0.1:30005
   slots: (0 slots) slave
   replicates 8504c51e42a572219cc95fb3510d8156ed274a69
M: 42d80140057ce31ec972b7079e9cb20d7f0f5ca6 127.0.0.1:30003
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
S: e185c034df6eb0b5e513d15e30777463ceef82a8 127.0.0.1:30006
   slots: (0 slots) slave
   replicates 42d80140057ce31ec972b7079e9cb20d7f0f5ca6
S: 2382b55e7e8f2d4119ed265e1aa4e1d10e9c6a6d 127.0.0.1:30004
   slots: (0 slots) slave
   replicates 7d285e51748c1683599dd31c6e27caf806867e2f
M: 8504c51e42a572219cc95fb3510d8156ed274a69 127.0.0.1:30002
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

解释下参数含义
–replicas 1 表示自动为每一个master节点分配一个slave节点,上面有6个节点,程序会按照一定规则生成 3个master(主)3个slave(从)
如果不在同一台服务器上创建,防火墙一定要开放监听的端口,否则会创建失败。后面的ip和端口写对应的ip和端口就行了
需要注意的是在Can I set the above configuration? (type ‘yes’ to accept): yes 输入yes后提示 Waiting for the cluster to join……….
这个时候不要一直等,看提示Sending Cluster Meet Message to join the Cluster.
这里就需要去另一台服务器上做以下操作
redis-cli -c -p 7000* 分别进入redis各节点的客户端命令窗口, 依次输入 cluster meet 172.25.27.2 7000*

这里写图片描述

5.测试

1.无中心化测试

[root@server2 ~]# redis-trib.rb info 127.0.0.1:30001
127.0.0.1:30001 (7d285e51...) -> 0 keys | 5461 slots | 1 slaves.
127.0.0.1:30003 (42d80140...) -> 0 keys | 5461 slots | 1 slaves.
127.0.0.1:30002 (8504c51e...) -> 0 keys | 5462 slots | 1 slaves.
[OK] 0 keys in 3 masters.
0.00 keys per slot on average.
[root@server2 ~]# redis-trib.rb info 127.0.0.1:30004
127.0.0.1:30001 (7d285e51...) -> 0 keys | 5461 slots | 1 slaves.
127.0.0.1:30003 (42d80140...) -> 0 keys | 5461 slots | 1 slaves.
127.0.0.1:30002 (8504c51e...) -> 0 keys | 5462 slots | 1 slaves.
[OK] 0 keys in 3 masters.
0.00 keys per slot on average.

[root@server2 ~]# redis-trib.rb check 127.0.0.1:30005
>>> Performing Cluster Check (using node 127.0.0.1:30005)
S: e9e0cd3990840c29ae279ddc20b3f946b72a383b 127.0.0.1:30005
   slots: (0 slots) slave
   replicates 8504c51e42a572219cc95fb3510d8156ed274a69
M: 42d80140057ce31ec972b7079e9cb20d7f0f5ca6 127.0.0.1:30003
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
S: e185c034df6eb0b5e513d15e30777463ceef82a8 127.0.0.1:30006
   slots: (0 slots) slave
   replicates 42d80140057ce31ec972b7079e9cb20d7f0f5ca6
M: 8504c51e42a572219cc95fb3510d8156ed274a69 127.0.0.1:30002
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
S: 2382b55e7e8f2d4119ed265e1aa4e1d10e9c6a6d 127.0.0.1:30004
   slots: (0 slots) slave
   replicates 7d285e51748c1683599dd31c6e27caf806867e2f
M: 7d285e51748c1683599dd31c6e27caf806867e2f 127.0.0.1:30001
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

可以看到30001-3是master,30004-5为slave,并且30004->30001,30005->30002,30006->30003,访问任何一个节点均可以取到集群的信息,即使slave也可以,也可以通过任何一个节点进行读写操作

[root@server2 ~]# redis-cli -c -p 30005        ##-c表示支持集群模式,不加-c是不可以对集群进行操作的
127.0.0.1:30005> get name
-> Redirected to slot [5798] located at 127.0.0.1:30002
(nil)
127.0.0.1:30002> get name
(nil)
127.0.0.1:30002> set name myname
OK
127.0.0.1:30002> get name
"myname"
127.0.0.1:30002> exit
[root@server2 ~]# redis-cli -c -p 30004
127.0.0.1:30004> get name
-> Redirected to slot [5798] located at 127.0.0.1:30002
"myname"
127.0.0.1:30002>exit
[root@server2 ~]# redis-cli -c -p 30001
127.0.0.1:30001> get name
-> Redirected to slot [5798] located at 127.0.0.1:30002
"myname"
127.0.0.1:30002>

2.模拟故障测试

[root@server2 ~]# redis-cli -p 30001 shutdown      ##master30001挂掉
[root@server2 ~]# redis-trib.rb check 127.0.0.1:30005
>>> Performing Cluster Check (using node 127.0.0.1:30005)
S: e9e0cd3990840c29ae279ddc20b3f946b72a383b 127.0.0.1:30005
   slots: (0 slots) slave
   replicates 8504c51e42a572219cc95fb3510d8156ed274a69
M: 42d80140057ce31ec972b7079e9cb20d7f0f5ca6 127.0.0.1:30003
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
S: e185c034df6eb0b5e513d15e30777463ceef82a8 127.0.0.1:30006
   slots: (0 slots) slave
   replicates 42d80140057ce31ec972b7079e9cb20d7f0f5ca6
M: 8504c51e42a572219cc95fb3510d8156ed274a69 127.0.0.1:30002
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
M: 2382b55e7e8f2d4119ed265e1aa4e1d10e9c6a6d 127.0.0.1:30004     ##30001slave30004自动提升为master,这个时候集群还是正常工作的
   slots:0-5460 (5461 slots) master
   0 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
##测试能否正常工作
[root@server2 ~]# redis-cli -c -p 30006
127.0.0.1:30006> get name
-> Redirected to slot [5798] located at 127.0.0.1:30002
"myname"
127.0.0.1:30002> set name qwe
OK
127.0.0.1:30002> get name
"qwe"
127.0.0.1:30002> exit
[root@server2 ~]# redis-cli -c -p 30002
127.0.0.1:30002> get name
"qwe"
127.0.0.1:30002> shutdown       ##在挂掉一台master30002
not connected> exit
[root@server2 ~]# redis-trib.rb check 127.0.0.1:30005
>>> Performing Cluster Check (using node 127.0.0.1:30005)
M: e9e0cd3990840c29ae279ddc20b3f946b72a383b 127.0.0.1:30005     ##30005提升为新的master
   slots:5461-10922 (5462 slots) master
   0 additional replica(s)
M: 42d80140057ce31ec972b7079e9cb20d7f0f5ca6 127.0.0.1:30003
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
S: e185c034df6eb0b5e513d15e30777463ceef82a8 127.0.0.1:30006
   slots: (0 slots) slave
   replicates 42d80140057ce31ec972b7079e9cb20d7f0f5ca6
M: 2382b55e7e8f2d4119ed265e1aa4e1d10e9c6a6d 127.0.0.1:30004
   slots:0-5460 (5461 slots) master
   0 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

此时集群有半数以上(>=3)节点活着,并且没有挂掉一对主从,集群可以正常工作的,即使挂掉30003,集群仍可工作,但是如果挂掉30004或30005,则集群不能正常工作,为体现测是效果,我们将30001启动,启动即自动加入集群

[root@server2 ~]# redis-server /usr/local/redis-cluster/30001/redis.conf 
[root@server2 ~]# redis-trib.rb check 127.0.0.1:30005
>>> Performing Cluster Check (using node 127.0.0.1:30005)
M: e9e0cd3990840c29ae279ddc20b3f946b72a383b 127.0.0.1:30005
   slots:5461-10922 (5462 slots) master
   0 additional replica(s)
M: 42d80140057ce31ec972b7079e9cb20d7f0f5ca6 127.0.0.1:30003
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
S: e185c034df6eb0b5e513d15e30777463ceef82a8 127.0.0.1:30006
   slots: (0 slots) slave
   replicates 42d80140057ce31ec972b7079e9cb20d7f0f5ca6
M: 2382b55e7e8f2d4119ed265e1aa4e1d10e9c6a6d 127.0.0.1:30004
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
S: 7d285e51748c1683599dd31c6e27caf806867e2f 127.0.0.1:30001
   slots: (0 slots) slave
   replicates 2382b55e7e8f2d4119ed265e1aa4e1d10e9c6a6d
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

此时此时挂掉30005

[root@server2 ~]# redis-cli -c -p 30006 get name
"qwe"
[root@server2 ~]# redis-cli -p 30005 shutdown
[root@server2 ~]# redis-cli -c -p 30006 get name
Could not connect to Redis at 127.0.0.1:30005: Connection refused
Could not connect to Redis at 127.0.0.1:30005: Connection refused
[root@server2 ~]# redis-cli -c -p 30001 get name
(error) CLUSTERDOWN The cluster is down
[root@server2 ~]# redis-cli -c -p 30003 get name
(error) CLUSTERDOWN The cluster is down
[root@server2 ~]# redis-cli -c -p 30004 get name
(error) CLUSTERDOWN The cluster is down
[root@server2 ~]# redis-cli -c -p 30006 get name
(error) CLUSTERDOWN The cluster is down

[root@server2 ~]# redis-trib.rb check 127.0.0.1:30001
>>> Performing Cluster Check (using node 127.0.0.1:30001)
S: 7d285e51748c1683599dd31c6e27caf806867e2f 127.0.0.1:30001
   slots: (0 slots) slave
   replicates 2382b55e7e8f2d4119ed265e1aa4e1d10e9c6a6d
M: 2382b55e7e8f2d4119ed265e1aa4e1d10e9c6a6d 127.0.0.1:30004
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
M: 42d80140057ce31ec972b7079e9cb20d7f0f5ca6 127.0.0.1:30003
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
S: e185c034df6eb0b5e513d15e30777463ceef82a8 127.0.0.1:30006
   slots: (0 slots) slave
   replicates 42d80140057ce31ec972b7079e9cb20d7f0f5ca6
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[ERR] Not all 16384 slots are covered by nodes.

[root@server2 ~]# redis-server /usr/local/redis-cluster/30005/redis.conf       ##启动30005
[root@server2 ~]# redis-cli -c -p 30006 get name
"qwe"

因为我们停掉了一对主从(30002,30005),导致16384个槽位不满,集群就无法工作了
所以在实际应用中,要是有三台服务器,每台两个节点,则互相交叉配置主从,这样即使一台服务器挂了,集群仍可工作,切忌同一台服务器上是对应的主从节点

3.槽位分配

[root@server2 ~]# redis-server /usr/local/redis-cluster/30002/redis.conf 
[root@server2 ~]# redis-server /usr/local/redis-cluster/30007/redis.conf 
[root@server2 ~]# redis-server /usr/local/redis-cluster/30008/redis.conf 
[root@server2 ~]# redis-trib.rb add-node 127.0.0.1:30007 127.0.0.1:30001       ##将30007加入集群

[root@server2 ~]# redis-trib.rb check 127.0.0.1:30006
>>> Performing Cluster Check (using node 127.0.0.1:30006)
S: e185c034df6eb0b5e513d15e30777463ceef82a8 127.0.0.1:30006
   slots: (0 slots) slave
   replicates 42d80140057ce31ec972b7079e9cb20d7f0f5ca6
S: 7d285e51748c1683599dd31c6e27caf806867e2f 127.0.0.1:30001
   slots: (0 slots) slave
   replicates 2382b55e7e8f2d4119ed265e1aa4e1d10e9c6a6d
M: e9e0cd3990840c29ae279ddc20b3f946b72a383b 127.0.0.1:30005
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
M: e3529eb3ae9bc3b5c4f8d1b429c19751da371d2b 127.0.0.1:30007
   slots: (0 slots) master   ##新加入的30007为master,但是集群为奇数个,它没有slave,并且没有分配槽位
   0 additional replica(s)
M: 42d80140057ce31ec972b7079e9cb20d7f0f5ca6 127.0.0.1:30003
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
M: 2382b55e7e8f2d4119ed265e1aa4e1d10e9c6a6d 127.0.0.1:30004
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
S: 8504c51e42a572219cc95fb3510d8156ed274a69 127.0.0.1:30002
   slots: (0 slots) slave
   replicates e9e0cd3990840c29ae279ddc20b3f946b72a383b
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

[root@server2 ~]# redis-trib.rb reshard --from all --slots 100 --to e3529eb3ae9bc3b5c4f8d1b429c19751da371d2b 127.0.0.1:30001       ##给300007分配100个槽位,从master中平均分配
[root@server2 ~]# redis-trib.rb check 127.0.0.1:30006
>>> Performing Cluster Check (using node 127.0.0.1:30006)
S: e185c034df6eb0b5e513d15e30777463ceef82a8 127.0.0.1:30006
   slots: (0 slots) slave
   replicates 42d80140057ce31ec972b7079e9cb20d7f0f5ca6
S: 7d285e51748c1683599dd31c6e27caf806867e2f 127.0.0.1:30001
   slots: (0 slots) slave
   replicates 2382b55e7e8f2d4119ed265e1aa4e1d10e9c6a6d
M: e9e0cd3990840c29ae279ddc20b3f946b72a383b 127.0.0.1:30005
   slots:5495-10922 (5428 slots) master
   1 additional replica(s)
M: e3529eb3ae9bc3b5c4f8d1b429c19751da371d2b 127.0.0.1:30007
   slots:0-32,5461-5494,10923-10955 (100 slots) master
   0 additional replica(s)
M: 42d80140057ce31ec972b7079e9cb20d7f0f5ca6 127.0.0.1:30003
   slots:10956-16383 (5428 slots) master
   1 additional replica(s)
M: 2382b55e7e8f2d4119ed265e1aa4e1d10e9c6a6d 127.0.0.1:30004
   slots:33-5460 (5428 slots) master
   1 additional replica(s)
S: 8504c51e42a572219cc95fb3510d8156ed274a69 127.0.0.1:30002
   slots: (0 slots) slave
   replicates e9e0cd3990840c29ae279ddc20b3f946b72a383b
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

[root@server2 ~]# redis-trib.rb rebalance --threshold 1 127.0.0.1:30001        ##平均分配槽位,如果新加入集群的节点没有像上面那样手动分配槽位(即槽位为空)的时候,要加上--use-empty-masters 参数

[root@server2 ~]# redis-trib.rb check 127.0.0.1:30006
>>> Performing Cluster Check (using node 127.0.0.1:30006)
S: e185c034df6eb0b5e513d15e30777463ceef82a8 127.0.0.1:30006
   slots: (0 slots) slave
   replicates 42d80140057ce31ec972b7079e9cb20d7f0f5ca6
S: 7d285e51748c1683599dd31c6e27caf806867e2f 127.0.0.1:30001
   slots: (0 slots) slave
   replicates 2382b55e7e8f2d4119ed265e1aa4e1d10e9c6a6d
M: e9e0cd3990840c29ae279ddc20b3f946b72a383b 127.0.0.1:30005
   slots:6827-10922 (4096 slots) master
   1 additional replica(s)
M: e3529eb3ae9bc3b5c4f8d1b429c19751da371d2b 127.0.0.1:30007
   slots:0-1364,5461-6826,10923-12287 (4096 slots) master
   0 additional replica(s)
M: 42d80140057ce31ec972b7079e9cb20d7f0f5ca6 127.0.0.1:30003
   slots:12288-16383 (4096 slots) master
   1 additional replica(s)
M: 2382b55e7e8f2d4119ed265e1aa4e1d10e9c6a6d 127.0.0.1:30004
   slots:1365-5460 (4096 slots) master
   1 additional replica(s)
S: 8504c51e42a572219cc95fb3510d8156ed274a69 127.0.0.1:30002
   slots: (0 slots) slave
   replicates e9e0cd3990840c29ae279ddc20b3f946b72a383b
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
[root@server2 ~]# redis-trib.rb add-node --slave --master-id e3529eb3ae9bc3b5c4f8d1b429c19751da371d2b 127.0.0.1:30008 127.0.0.1:30001      ##添加30008作为30007的从

[root@server2 ~]# redis-trib.rb check 127.0.0.1:30006
>>> Performing Cluster Check (using node 127.0.0.1:30006)
S: e185c034df6eb0b5e513d15e30777463ceef82a8 127.0.0.1:30006
   slots: (0 slots) slave
   replicates 42d80140057ce31ec972b7079e9cb20d7f0f5ca6
S: 7d285e51748c1683599dd31c6e27caf806867e2f 127.0.0.1:30001
   slots: (0 slots) slave
   replicates 2382b55e7e8f2d4119ed265e1aa4e1d10e9c6a6d
S: 52a505926e07fb62bf6019627c64ef334734b587 127.0.0.1:30008
   slots: (0 slots) slave
   replicates e3529eb3ae9bc3b5c4f8d1b429c19751da371d2b
M: e9e0cd3990840c29ae279ddc20b3f946b72a383b 127.0.0.1:30005
   slots:6827-10922 (4096 slots) master
   1 additional replica(s)
M: e3529eb3ae9bc3b5c4f8d1b429c19751da371d2b 127.0.0.1:30007
   slots:0-1364,5461-6826,10923-12287 (4096 slots) master
   1 additional replica(s)
M: 42d80140057ce31ec972b7079e9cb20d7f0f5ca6 127.0.0.1:30003
   slots:12288-16383 (4096 slots) master
   1 additional replica(s)
M: 2382b55e7e8f2d4119ed265e1aa4e1d10e9c6a6d 127.0.0.1:30004
   slots:1365-5460 (4096 slots) master
   1 additional replica(s)
S: 8504c51e42a572219cc95fb3510d8156ed274a69 127.0.0.1:30002
   slots: (0 slots) slave
   replicates e9e0cd3990840c29ae279ddc20b3f946b72a383b
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

四、Redis 作为 mysql 的缓存服务器

1.角色分配

hostnameip服务
server2172.25.27.2web客户端,需要lnmp
server3172.25.27.3redis
server4172.25.27.4mysql

2.安装lnmp环境

[root@server2 ~]# killall redis-server     ##停掉刚才的集群
[root@server2 ~]# yum install -y nginx php php-fpm php-cli php-common php-gd php-mbstring php-mysql php-pdo php-devel mysql mysql-server

3.安装 php 的 redis 扩展

下载地址:https://github.com/owlient/phpredis

[root@server2 ~]# unzip phpredis-master.zip
[root@server2 ~]# cd phpredis-master
[root@server2 phpredis-master]# phpize 
Configuring for:
PHP Api Version:         20090626
Zend Module Api No:      20090626
Zend Extension Api No:   220090626
[root@server2 phpredis-master]# ./configure

[root@server2 phpredis-master]# make && make install
[root@server2 ~]# vim /etc/nginx/conf.d/default.conf
server {
    listen       80;
    server_name  localhost;
    root         /usr/share/nginx/html;
    include /etc/nginx/default.d/*.conf;

    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  /usr/share/nginx/html$fastcgi_script_name;
           include        fastcgi_params;
       }
}

[root@server2 ~]# vim /etc/php.ini
;   extension=msql.so
extension=redis.so

[root@server2 ~]# /etc/init.d/php-fpm start
[root@server2 ~]# service nginx start
[root@server2 ~]# echo "<?php phpinfo() ?>" > /usr/share/nginx/html/index.php

网页访问:http://172.25.27.2
要看到加载redis模块
这里写图片描述

这里写图片描述

[root@server2 ~]# vim /usr/share/nginx/html/test.php
<?php
        $redis = new Redis();
        $redis->connect('172.25.27.3',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('173.25.27.4','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>";
        }
?>

4.配置 mysql

[root@server4 ~]# yum install -y mysql-server
[root@server4 ~]# /etc/init.d/mysqld start
[root@server4 ~]# 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@server4 ~]# mysql<test.sql
[root@server4 ~]# mysql
mysql> select * from test.test;
+----+-------+
| id | name  |
+----+-------+
|  1 | test1 |
|  2 | test2 |
|  3 | test3 |
|  4 | test4 |
|  5 | test5 |
|  6 | test6 |
|  7 | test7 |
|  8 | test8 |
|  9 | test9 |
+----+-------+
9 rows in set (0.00 sec)

mysql> grant all on test.* to redis@"%" identified by "redhat";

5.安装redis

再server3上安装,安装好修改bind之后直接启动即可

[root@server3 redis-4.0.2]# make && make install
[root@server3 redis-4.0.2]# ./utils/install_server.sh
[root@server3 redis-4.0.2]# vim /etc/redis/6379.conf
bind 0.0.0.0
[root@server3 redis-4.0.2]# /etc/init.d/redis_6379 restart

网页访问 http://172.25.27.2/test.php

这里写图片描述
这里写图片描述
到这里,我们已经实现了 redis 作为 mysql 的缓存服务器,但是如果更新了 mysql , redis中仍然会有对应的 KEY,数据就不会更新,此时就会出现 mysql 和 redis 数据不一致的情况。所以接下来就要通过 mysql 触发器将改变的数据同步到 redis 中。

五、配置 gearman 实现数据同步

1.Gearman简介

Gearman 是一个支持分布式的任务分发框架:
Gearman Job Server: Gearman 核心程序,需要编译安装并以守护进程形式运行在后台。
Gearman Client:可以理解为任务的请求者。
Gearman Worker:任务的真正执行者,一般需要自己编写具体逻辑并通过守护进程方式运行,Gearman Worker 接收到 Gearman Client 传递的任务内容后,会按顺序处理。
大致流程:下面要编写的 mysql 触发器,就相当于 Gearman 的客户端。修改表,插入表就相当于直接下发任务。然后通过 lib_mysqludf_json UDF 库函数将关系数据映射为 JSON 格式,然后在通过 gearman-mysql-udf 插件将任务加入到 Gearman 的任务队列中,最后通过redis_worker.php,也就是 Gearman 的 worker 端来完成 redis 数据库的更新。

2.安装 gearman 软件包

[root@server2 redis]# yum install gearmand-1.1.8-2.el6.x86_64.rpm libgearman-* libevent-*
[root@server1 redis]# /etc/init.d/gearmand start
[root@server2 redis]# tar -zxf gearman-1.1.2.tgz
[root@server2 redis]# cd gearman-1.1.2
[root@server2 gearman-1.1.2]# phpize
[root@server2 gearman-1.1.2]# ./configure --with-php-config=/usr/bin/php-config
[root@server1 gearman-1.1.2]# make && make instal
[root@server2 gearman-1.1.2]# cd /etc/php.d/
[root@server2 php.d]# sed 's/mysql/gearman/g' mysql.ini > gearman.ini
[root@server2 php.d]# /etc/init.d/php-fpm reload
[root@server2 php.d]#  php -m | grep gearman
gearman

3.安装 lib_mysqludf_json

[root@server4 ~]# yum install -y mysql-devel gcc
[root@server4 ~]# wget https://codeload.github.com/mysqludf/lib_mysqludf_json/zip/master
[root@server4 ~]# unzip master
[root@server4 ~]# cd lib_mysqludf_json-master/
[root@server4 lib_mysqludf_json-master]# gcc $(mysql_config --cflags) -shared -fPIC -o lib_mysqludf_json.so lib_mysqludf_json.c

[root@server4 lib_mysqludf_json-master]# mysql -e "show global variables like 'plugin_dir'" ##查看 mysql 的模块目录
+---------------+-------------------------+
| Variable_name | Value                   |
+---------------+-------------------------+
| plugin_dir    | /usr/lib64/mysql/plugin |
+---------------+-------------------------+

[root@server4 lib_mysqludf_json-master]# cp lib_mysqludf_json.so /usr/lib64/mysql/plugin/       ##拷贝 lib_mysqludf_json.so 模块

[root@server4 lib_mysqludf_json-master]# mysql
mysql> CREATE FUNCTION json_object RETURNS STRING SONAME 'lib_mysqludf_json.so';
mysql> select * from mysql.func;
+-------------+-----+----------------------+----------+
| name        | ret | dl                   | type     |
+-------------+-----+----------------------+----------+
| json_object |   0 | lib_mysqludf_json.so | function |
+-------------+-----+----------------------+----------+
1 row in set (0.00 sec)

4.安装 gearman-mysql-udf

这个插件是用来管理调用 Gearman 的分布式的队列。
https://launchpad.net/gearman-mysql-udf

[root@server4 ~]# wget http://dl.fedoraproject.org/pub/epel/6/x86_64//libgearman-1.1.8-2.el6.x86_64.rpm
[root@server4 ~]# wget http://dl.fedoraproject.org/pub/epel/6/x86_64//libgearman-devel-1.1.8-2.el6.x86_64.rpm
[root@server4 ~]# wget http://mirror.centos.org/centos/6/os/x86_64/Packages/libevent-devel-1.4.13-4.el6.x86_64.rpm
[root@server4 ~]# wget http://mirror.centos.org/centos/6/os/x86_64/Packages/libevent-doc-1.4.13-4.el6.noarch.rpm
[root@server4 ~]# wget http://mirror.centos.org/centos/6/os/x86_64/Packages/libevent-headers-1.4.13-4.el6.noarch.rpm

[root@server4 ~]# yum install -y libgearman-devel-1.1.8-2.el6.x86_64.rpm libgearman-1.1.8-2.el6.x86_64.rpm libevent-devel-1.4.13-4.el6.x86_64.rpm libevent-headers-1.4.13-4.el6.noarch.rpm

[root@server4 ~]# wget https://launchpadlibrarian.net/104246122/gearman-mysql-udf-0.6.tar.gz
[root@server4 ~]# tar -zxf gearman-mysql-udf-0.6.tar.gz
[root@server4 ~]# cd gearman-mysql-udf-0.6
[root@server4 gearman-mysql-udf-0.6]# ./configure --with-mysql --libdir=/usr/lib64/mysql/plugin/
[root@server4 gearman-mysql-udf-0.6]# make && make install

5.注册 UDF 函数

[root@server4 gearman-mysql-udf-0.6]# mysql

mysql> CREATE FUNCTION gman_do_background RETURNS STRING SONAME 'libgearman_mysql_udf.so';
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE FUNCTION gman_servers_set RETURNS STRING SONAME 'libgearman_mysql_udf.so';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT gman_servers_set('172.25.27.2:4730');     ##指定 gearman 的服务信息
+--------------------------------------+
| gman_servers_set('172.25.27.2:4730') |
+--------------------------------------+
| 172.25.27.2:4730                     |
+--------------------------------------+
1 row in set (0.00 sec)

mysql> 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 |
+--------------------+-----+-------------------------+----------+

6.编写 mysql 触发器(根据实际情况编写)

[root@server4 ~]# 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@server4 ~]# mysql<test.sql 
[root@server4 ~]# mysql -e 'SHOW TRIGGERS FROM test\G'
*************************** 1. row ***************************
             Trigger: datatoredis
               Event: UPDATE
               Table: test
           Statement: BEGIN
    SET @RECV=gman_do_background('syncToRedis', json_object(NEW.id as `id`, NEW.name as `name`));
  END
              Timing: AFTER
             Created: NULL
            sql_mode: 
             Definer: root@localhost
character_set_client: latin1
collation_connection: latin1_swedish_ci
  Database Collation: latin1_swedish_ci

7.编写 gearman 的 worker 端


[root@server2 ~]# vim /usr/local/worker.php

<?php
$worker = new GearmanWorker();
$worker->addServer();
$worker->addFunction('syncToRedis', 'syncToRedis');
$redis = new Redis();
$redis->connect('172.25.27.3', 6379);
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); #这条语句就是将 id 作 KEY 和name 作 VALUE 分开存储,需要和前面写的 php 测试代码的存取一致。
}
?>

[root@server2 ~]# nohup php /usr/local/worker.php &        ##后台运行 worker

8.测试

更新 mysql 中的数据

[root@server4 ~]# mysql -e "update test.test set name='hello' where id=1"

查看 redis

[root@server3 ~]# redis-cli get 1
"hello"

刷新测试页面数据同步
这里写图片描述

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值