Redis Sentinel高可用架构
Redis目前高可用的架构非常多,比如keepalived+redis,redis cluster,twemproxy,codis,这些架构各有优劣,今天暂且不说这些架构,今天主要说说redis sentinel高可用架构。
它的主要功能有以下几点
- 不时地监控redis是否按照预期良好地运行;
- 如果发现某个redis节点运行出现状况,能够通知另外一个进程(例如它的客户端);
- 能够进行自动切换。当一个master节点不可用时,能够选举出master的多个slave(如果有超过一个slave的话)中的一个来作为新的master,其它的slave节点会将它所追随的master的地址改为被提升为master的slave的新地址。
关于更加详细的配置以及介绍推荐看完以下文章,我在这里就不多说了,直接进行搭建:
http://segmentfault.com/a/1190000002680804
http://segmentfault.com/a/1190000002685515
redis sentinel的架构如下图:
当然Redis-Sentinel推荐使用3个或者3个以上节点,至于为什么这么做看完我上面给的文章链接。
环境介绍:
Redis Sentinel5台服务器:
10.36.30.203
10.36.30.204
10.37.124.202
10.37.124.203
10.37.124.204
这里不要觉得浪费,这样做是为了更加安全高效的监控redis,且redis Sentinel可以进行复用,也就是可以监控多个Redis实例,所以服务器不存在浪费。
Redis 服务器2台,1主1从:
10.69.25.173 master
10.69.30.170 slave
5台Sentinel的配置文件内容如下:
port
dir "/data/redis/sentinel/26379"
daemonize yes
logfile "/data/redis/sentinel/26379/sentinel.log" #
sentinel monitor master- 10.69.25.173
sentinel down-after-milliseconds master-
sentinel parallel-syncs master-
sentinel failover-timeout master-
sentinel client-reconfig-script master- /sh/redis/notify.py
其中sentinel client-reconfig-script master-6379 /sh/redis/notify.py是在主从切换以后发送告警邮件。其他参数的意义参考我给的文章链接。相关目录自己创建好。
notify.py脚本内容如下,5台服务器上面都需要存在,因为你不知道哪个节点会被选举为leader(网上还没有人提到切换发送告警邮件问题):
#!/usr/bin/python
#coding:utf8 import sys
import time
import smtplib
import logging
from email.mime.text import MIMEText
from email.message import Message
from email.header import Header alarm_mail =['xxxxxx@163.com'] def main(): failover_time=time.strftime("%Y-%m-%d %H:%M:%S") logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
filename='/sh/redis/failover.log',
filemode='a') console = logging.StreamHandler()
console.setLevel(logging.INFO)
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
console.setFormatter(formatter)
logging.getLogger('').addHandler(console) mail_host='xxxxx'
mail_port=25
mail_user='xxxxxxx'
mail_pass='xxxxxxxx'
mail_send_from = 'xxxxxxx' def send_mail(to_list,sub,content):
me=mail_send_from
msg = MIMEText(content, _subtype='html', _charset='utf-8')
msg['Subject'] = Header(sub,'utf-8')
msg['From'] = Header(me,'utf-8')
msg['To'] = ";".join(to_list)
try:
smtp = smtplib.SMTP()
smtp.connect(mail_host,mail_port)
smtp.login(mail_user,mail_pass)
smtp.sendmail(me,to_list, msg.as_string())
smtp.close()
return True
except Exception as error:
logging.error("邮件发送失败: %s" % (error))
return False try:
master_name = sys.argv[1]
role = sys.argv[2]
from_ip = sys.argv[4]
from_port = sys.argv[5]
to_ip = sys.argv[6]
to_port = sys.argv[7]
except Exception as error:
logging.error('从 Sentinel 获取参数错误: %s ' % (error))
sys.exit(1) sub='redis %s faiover' % (master_name)
nodify_message = "%s %s is failover end. sentinel find redis master %s:%s is down. failover to slave %s:%s" % (failover_time,master_name,from_ip,from_port,to_ip,to_port) if role == 'leader':
logging.info(nodify_message)
send_mail(alarm_mail,sub,nodify_message) if __name__ == "__main__":
main()
10.69.25.173 master
10.69.30.170 slave
自己安装完成redis,并且搭建好复制关系。
现在分别在5台Sentinel服务器上面启动Sentinel,有2种方式启动。哪两种自己看前面文章。
redis-sentinel sentinel.conf
启动以后随便找一台服务器查看日志,输出如下提示:
[] Dec ::47.161 # Sentinel runid is f3086fc39145cb3d832785899699050d2c7f3b08
[] Dec ::47.161 # +monitor master master- 10.69.25.173 quorum
[] Dec ::47.183 * +slave slave 10.69.30.170: 10.69.30.170 @ master- 10.69.25.173
这里的+slave就表示找到了一个从库。
再看看其他sentinel服务器的日志:
[] Dec ::37.250 # Sentinel runid is 812f9f8b860dcc73d4b587e3bdf85df13808a3cd
[] Dec ::37.250 # +monitor master master- 10.69.25.173 quorum
[] Dec ::38.252 * +slave slave 10.69.30.170: 10.69.30.170 @ master- 10.69.25.173
[] Dec ::38.304 * +sentinel sentinel 10.36.30.204: 10.36.30.204 @ master- 10.69.25.173
[] Dec ::38.388 * +sentinel sentinel 10.37.124.202: 10.37.124.202 @ master- 10.69.25.173
[] Dec ::38.461 * +sentinel sentinel 10.37.124.203: 10.37.124.203 @ master- 10.69.25.173
[] Dec ::39.423 * +sentinel sentinel 10.37.124.204: 10.37.124.204 @ master- 10.69.25.173
+sentinel表示发现了其他的sentinel服务器。现在整个集群就已经工作了。
首先进入sentinel查看现在的主节点是哪台服务器(随便哪台sentinel都可以):
redis-cli -p
127.0.0.1:> info Sentinel
# Sentinel
sentinel_masters:
sentinel_tilt:
sentinel_running_scripts:
sentinel_scripts_queue_length:
master0:name=master-,status=ok,address=10.69.25.173:,slaves=,sentinels=
127.0.0.1:>
可以看到现在的主库是10.69.25.173:6379。现在我们把这台服务器的redis进程kill掉,查看是否会进行切换:
pkill - redis
再次查看,发现主库已经是原来的从库了。
而且还会收到告警邮件,内容如下:
127.0.0.1:> info Sentinel
# Sentinel
sentinel_masters:
sentinel_tilt:
sentinel_running_scripts:
sentinel_scripts_queue_length:
master0:name=master-,status=ok,address=10.69.30.170:,slaves=,sentinels=
127.0.0.1:>
同样的,如果把刚才kill掉的reids重新启动,又会把启动的redis设置为10.69.30.170的从库。
[] Dec ::48.921 # +new-epoch
[] Dec ::48.933 # +vote-for-leader 92517289efcb4ae695eff3e064fde7f4e0e43a1f
[] Dec ::48.955 # +sdown master master- 10.69.25.173
[] Dec ::48.955 # +odown master master- 10.69.25.173 #quorum /
[] Dec ::48.955 # Next failover delay: I will not start a failover before Sat Dec ::
[] Dec ::50.067 # +config-update-from sentinel 10.37.124.203: 10.37.124.203 @ master- 10.69.25.173
[] Dec ::50.067 # +switch-master master- 10.69.25.173 10.69.30.170
[] Dec ::50.067 * +slave slave 10.69.25.173: 10.69.25.173 @ master- 10.69.30.170
[] Dec ::05.109 # +sdown slave 10.69.25.173: 10.69.25.173 @ master- 10.69.30.170
[] Dec ::19.241 # -sdown slave 10.69.25.173: 10.69.25.173 @ master- 10.69.30.170
[] Dec ::29.219 * +convert-to-slave slave 10.69.25.173:6379 10.69.25.173 6379 @ master-6379 10.69.30.170 6379
那么客户端如何知道主从进行切换了呢,如果是java那么有jedis客户端比较方便,如果是php,python语言呢,我们可以自己进行判断。当然还有另外一种方法就是采用dns,修改dns解析。
我这里用python简单写了一个daemon,不会php,哎。
#!/usr/bin/python
import redis
import os sentinel_server=['10.36.30.203:26379','10.36.30.204:26379','10.37.124.202:26379','10.37.124.203:26379','10.37.124.204:26379'] def queue(host,port):
str=''.join(map(lambda xx:(hex(ord(xx))[2:]),os.urandom(16)))
pool = redis.ConnectionPool(host=host, port=port, db=0)
r = redis.Redis(connection_pool=pool)
r.lpush('low_task_queue',str) def get_sentinel():
global master_host
global master_port for info in sentinel_server:
host=info.split(':')[0]
port=info.split(':')[1]
try:
r = redis.Redis(host=host, port=port)
info=r.info('sentinel')['master0']['address'].split(':')
master_host=info[0]
master_port=info[1]
except Exception as error:
print 'concat to sentinel error: %s' % (error)
pass
else:
break if __name__ == "__main__":
get_sentinel()
while True:
try:
queue(master_host,master_port)
except Exception as error:
print 'conct redis error %s' % (error)
get_sentinel()
continue
如果引入dns,那么架构图可以是下面这样:
以上就是简单的测试了,更多的测试交给大家了。
总结:
Redis Sentinel实现高可用还是比较靠谱的,后面线上也打算使用。需要注意的是Redis Sentinel节点推荐3个以上。相比keepalived+redis实现高可用更靠谱,且keepalived+redis还不能管理多个实例,这点是比较麻烦的。
参考资料:
http://segmentfault.com/a/1190000002680804
http://segmentfault.com/a/1190000002685515
http://redis.io/topics/sentinel-clients
https://pypi.python.org/pypi/redis/
Redis Sentinel高可用架构的更多相关文章
- Redis|Sentinel 高可用架构
一 前言 Redis-Sentinel是Redis官方推荐的高可用性(HA)解决方案,当用Redis做Master-slave的高可用方案时,假如master宕机了,Redis本身(包括它的很多客户端 ...
- Redis Sentinel 高可用实现说明
背景: 前面介绍了Redis 复制.Sentinel的搭建和原理说明,通过这篇文章大致能了解Sentinel的原理和实现方法以及相关的搭建.这篇文章就针对Redis Sentinel的搭建做 ...
- 【转载】Redis Sentinel 高可用服务架构搭建
作者:田园里的蟋蟀 出处:http://www.cnblogs.com/xishuai/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接. 阅读 ...
- Redis Sentinel 高可用服务搭建
阅读目录: 关于 Redis 的概念 关于 Redis Sentinel 的概念 搭建 Redis Server(master) 搭建 Redis Server(slave) 搭建 Redis Sen ...
- Redis Sentinel 高可用方案
redis 主从复制的问题 Redis主从复制可将主节点数据同步给从节点,从节点此时有两个作用: 1,一旦主节点宕机,从节点作为主节点的备份可以随时顶上来. 2,扩展主节点的读能力,分担主节点读压 ...
- Redis Sentinel 高可用部署实践集群
一.Redis Sentinel 介绍 1.Sentinel 数据库环境搭建,从单机版到主备.再到多数据库集群,我们需要一个高可用的监控:比如Mysql中,我们可能会采用MHA来搭建我们 ...
- redis sentinel 高可用(HA)方案部署,及python应用示例
redis sentinel(哨兵)高可用集群的部署方法,并通过 python 程序实例讲解如何使用 redis sentinel 简介 介绍 redis sentinel(哨兵)集群的部署,配置一主 ...
- Redis Sentinel 高可用机制
内容目录: Sentinel 如何工作的? 核心配置项 怎么选出新 master 的? Sentinel 有多个,具体谁来执行故障转移? Sentinel 是怎么发现 slave 和其他 sentin ...
- Redis+sentinel 高可用实践
1.环境规划 10.213.50.138(主) redis+sentinel 10.213.50.168(从) redis+sentinel 10.213.50.227 作为客户端测试插入数 2.r ...
随机推荐
- 网络方案 & HTTP状态码
在iOS中,常见的发送HTTP请求的方案包括: 苹果官方 名称 说明 NSURLConnection iOS 2.0 推出,用法简单,最古老最经典最直接的一种方案 NSURLSession iOS 7 ...
- nanosleep() -- 更精确的延迟 -----一个使用用例
[常规] nanosleep() -- 更精确的延迟 [复制链接] beyes 4220 主题 5152 帖子 3万 积分 GROAD 曲径通幽,安觅芳踪. 积分 30607 发消息 电梯直达 ...
- thinkphp- 许愿墙-1
控制器的方法, 要显示的模板默认的跟方法名相同. 也可以不同, 但应该 仍然是对应文件夹下的html模板文件: $this->display('其他的模板html文件名, 不用加html扩展名' ...
- R获取股票数据
R中好几个Pkg都提供了股票数据的在线下载方法,如果非得在其中找出一个最好的,那么quantmod当之无愧!举一个例子,譬如下载沪市大盘数据,代码可以是: library(quantmod)SSE & ...
- ASP 编码转换(乱码问题解决)
ASP 编码转换(乱码问题解决) 输出前先调用Conversion函数进行编码转换,可以解决乱码问题. 注,“&参数&”为ASP的连接符,这里面很多是直接调用的数据库表字段,实际使用请 ...
- tyvj1614 魔塔魔塔!
描述 百度noip贴吧管理组开发了一个小游戏,叫魔塔魔塔.虽然把魔塔重复了两次,但其实还只是个魔塔而已,还是简化版的.游戏在一个N*M大小的地图中进行,每一格都是正方形.对于某一格,有若干种可能的状态 ...
- 机器码call和jmp地址的计算
call和jmp都是跳转指令,但是call的同时会把pc地址压入堆栈,并且这两种方式都有远和近跳转.下面的分析不全,因为没有在网上找到足够的资料,个人创造这个情景还是有些困难. 1.例子中的call的 ...
- taglib
thinkphp中 taglib标签应用 原文出处:http://blog.csdn.net/a11085013/article/details/38172653 1.配置文件中加上: 'APP_AU ...
- tomcat JNDI 设置
一.在Spring配置文件中的配置 <bean id="dataSource" class="org.springframework.jndi.JndiObje ...
- 解决ubuntu每次重启屏幕亮度都重置为最高亮度问题
很多朋友都会碰到这个问题,Ubuntu系统,每次通过系统设置修改了屏幕亮度,重启系统都会将屏幕亮度调成最大值,很是苦恼. 上网搜索一番发现,修改屏幕亮度的文件是:/sys/class/backligh ...