关注微信公众号:码农Share,更方便的获得知识
docker pull redis
docker image ls
redis官方提供了一个配置文件样例,通过wget工具下载下来。
wget http://download.redis.io/redis-stable/redis.conf
在此只做配置主从关系的必要修改
其中redis服务器的master和slave角色使用的配置文件还会有些不同,下面分别进行说明。
首先说明一下,正常情况下配置主从关系需要多台机器,但现实往往不允许。所以现在在一台机器上模拟。
将下载下来的redis.conf复制三份,分别命名为
redis-master.conf,redis-slave1.conf,redis-slave2.conf
cp redis.conf redis-master.conf
cp redis.conf redis-slave1.conf
cp redis.conf redis-slave2.conf
将三个配置文件我放在了/usr/local/docker-redis/目录下
首先修改master的配置文件
vim redis-master.conf
# 注释这一行,表示Redis可以接受任意ip的连接
# bind 127.0.0.1
# 关闭保护模式
protected-mode no
# 让redis服务后台运行
daemonize yes
# 设定主库的密码,用于认证,如果主库开启了requirepass选项这里就必须填相应的密码
masterauth <master-password>
# 设定密码(可选,如果这里开启了密码要求,slave的配置里就要加这个密码. 只是练习配置,就不使用密码认证了)
requirepass masterpassword
# 配置日志路径,为了便于排查问题,指定redis的日志文件目录
logfile "/var/log/redis/redis.log"
如果是服务器,redis密码很重要,因为redis默认没密码有漏洞,有很多人利用redis漏洞来使你的服务器挖矿,亲身体会。
其次修改slave配置。
vim redis-slave1.conf
# 注释这一行,表示Redis可以接受任意ip的连接
# bind 127.0.0.1
# 关闭保护模式
protected-mode no
# 让redis服务后台运行
daemonize yes
# 设定密码(可选,如果这里开启了密码要求,slave的配置里就要加这个密码)
requirepass masterpassword
# 设定主库的密码,用于认证,如果主库开启了requirepass选项这里就必须填相应的密码
masterauth <master-password>
# 设定master的IP和端口号,redis配置文件中的默认端口号是6379
# 低版本的redis这里会是slaveof,意思是一样的,因为slave是比较敏感的词汇,所以在redis后面的版本中不在使用slave的概念,取而代之的是replica
# 将35.236.172.131做为主,其余两台机器做从。ip和端口号按照机器和配置做相这里的IP地址往下看。
replicaof 198.18.0.2 6379
# 配置日志路径,为了便于排查问题,指定redis的日志文件目录
logfile "/usr/local/logs/redis.log"
上方提到的这个主节点地址为master的docker容器的地址,可以通过以下命令查看
docker inspect redis_master # 用来查看容器的详细信息
slave2配置与上述相同。
首先以后台模式运行master容器,注意文件的地址
docker run -it --name redis-master --network=dockercompose --ip 172.19.0.2 -v /data/docker_redis/redis-conf/redis-master.conf:/usr/local/redis/redis.conf -d -p 6380:6379 redis /bin/bash
首先以后台模式运行slave1容器,注意文件的地址和端口号,物理机的端口号不可冲突
$ docker run -it --name redis-master -v /usr/local/docker-redis/redis-slave1.conf:/usr/local/redis/redis.conf -d -p 6380:6379 redis /bin/bash
slave2启动同上
接下来进入容器里启动redis服务器。
docker exec -it redis-master bash
mkdir /usr/local/logs/
touch /usr/local/logs/redis.log
redis-server /usr/local/redis/redis.conf
redis-cli
127.0.0.1:6379> auth password
127.0.0.1:6379> info
如果是主,这里的role的值会是master,如果是从,这里的role的值会是slave
对于slave,还要查看master_link_status这个属性值。slave上这个属性值为up就说明主从复制是OK的,否者就有问题。如果从机状态不为up,首先排查主机的端口是否被限,然后查看redis日志排查原因
127.0.0.1:6379> quit
exit
主从搭建成功后,可以通过在master上写入一个key-value值,查看是否会同步到slave上,来验证主从同步是否能成功
redis-cli
auth password
set test hello
在任意slave机器上进入容器,也运行一个redis-cli,查询这个key的值。如果能查询到这个值,且与主机上的值相同,说明主从同步成功。经测试,主动同步成功。
redis-cli
auth password
get test
可以在主发生故障后,自动进行故障转移,从从机里选出一台升级为主机,并持续监听着原来的主机,当原来的主机恢复后,会将其作为新主的从机。
哨兵先监听主,通过对主发送info命令,获取到从的信息,然后也会监听到从。另外哨兵都会像主订阅__sentinel__:hello频道,当有新的哨兵加入时,会向这个频道发送一条信息,这条信息包含了该哨兵的IP和端口等信息,那么其他已经订阅了该频道的哨兵就会收到这条信息,就知道有一个新的哨兵加入。这些哨兵会与新加入和哨兵建立连接,选主是需要通过这个连接来进行投票。这个关系可以用下面这个图来描述
wget http://download.redis.io/redis-stable/sentinel.conf
vim sentinel.conf
# 让sentinel服务后台运行
daemonize yes
# 修改日志文件的路径
logfile "/var/log/redis/sentinel.log"
# 修改监控的主redis服务器
# 最后一个2表示,两台机器判定主被动下线后,就进行failover(故障转移)
sentinel monitor mymaster 192.18.0.2 6379 2
# 主数据库密码,需要将配置放在sentinel monitor master 127.0.0.1 6379 1下面
sentinel auth-pass mymaster 123456789
docker run -it --name sentinel -p 26379:26379 -v /usr/local/docker-redis/sentinel.conf:/usr/local/redis/sentinel.conf -d redis /bin/bash
进入容器
docker exec -it sentinel bash
创建日志目录和文件
mkdir /usr/local/logs
touch /usr/local/logs/sentinel.log
启动sentinel
redis-sentinel /usr/local/redis/sentinel.conf
查看是否生效
cat /usr/local/logs/sentinel.log
为了验证哨兵机制下的自动主从切换,我们将主上的redis进程kill掉。
doker top reedis-master
找到redisserver的PID
kill -9 PID
稍等几秒钟后,就有另外一台从升级为主机,实验时是第三台机器,也就是redis-3升级为了主,用info命令查询可以看到redis-3服务器的角色变成的master。说明自动主从切换成功。
pip install redis
from redis.sentinel import Sentinel
from redis import WatchError
MYSETINEL = None
MASTER = None
SLAVE = None # 1.redis 哨兵模式集群最少需要一主三从, 三哨兵
# 2.redis 哨兵集群所有主从节点都完整的保存了一份数据
SENTINEADDRESS = [('127.0.0.1', 6390), ('127.0.0.1', 6391), ('127.0.0.1', 6392)] def get_redis_conn(): global MYSETINEL
global MASTER
global SLAVE
# 如果哨兵连接实例已存在, 不重复连接, 当连接失效时, 重新连接
if not MYSETINEL:# 连接哨兵
MYSETINEL = Sentinel(SENTINEADDRESS, socket_timeout=2000) # 尝试连接最长时间单位毫秒, 1000毫秒为1秒
# 通过哨兵获取主数据库连接实例 参数1: 主数据库的名字(集群部署时在配置文件里指明)
MASTER = MYSETINEL.master_for('seckill', socket_timeout=2000)
# 通过哨兵获取从数据库连接实例 参数1: 从数据的名字(集群部署时在配置文件里指明)
SLAVE = MYSETINEL.slave_for('seckill', socket_timeout=2000) # 每次都先尝试生成连接实例
get_redis_conn() # 往 主数据库 写入数据
def setcache(key, time, value):
global MASTER
if MASTER:
return MASTER.setex(key, time, value)
else:
return False # 从 从数据库 读取数据
def getcache(key):
global SLAVE
if SLAVE:
return SLAVE.get(key)
else:
return False
from redis import WatchError # 使用事物修改商品库存
def update_stock(key):
global MASTER
with MASTER.pipeline() as pipe:
i = 0
while i < 10: # 尝试修改库存10次
try:
# watch库存键, multi后如果该key被其他客户端改变, 事务操作会抛出WatchError异常
pipe.watch(key)
count = int(pipe.get(key)) # 取库存
# 可以修改库存
if count > 0:
pipe.set(key, count-1) # 保存剩余库存
# 事务结束, 把命令推送过去
result = pipe.execute() # execute返回命令执行结果列表,
return True, result
# 库存不足
else:
pipe.unwatch()
return False
except WatchError as e:
print(e)
i += 1
continue
finally:
pipe.reset()
链接的时候,你可能遇到一些问题,见下一章博客
声明:部分内容来自网友整理,如有侵权,联系删除