Redis开发运维实践高可用和集群架构与实践(五)

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介:

11.1.5 其他问题

11.1.5.1 只读性

主从复制架构下,默认Slave是只读的,如果写入则会报错:

127.0.0.1:6379> set foo bar
(error) READONLY You can't write against a read only slave.

注意这个行为是可以修改的,虽然这样的修改没有意义:

127.0.0.1:6379> CONFIG SET slave-read-only no
OK
127.0.0.1:6379> set foo bar
OK
 

11.1.5.1 事件通知

在sentinel中,如果出现warning以上级别的事件发生, 是可以通过如下配置进行脚本调用的(对于该脚本redis启动用户需要有执行权限):

 

比如说,我们希望在发生这些事件的时候进行邮件通知,那么,notify.py就是一个触发邮件调用的东东,传入第一个参数为事件类型,第二个参数为事件信息:

 

有两个注意事项: 1) 这个时候如果集群发生了切换会产生很多事件,此脚本是在每一个事件发生时调用一次,那么你将短时间收到很多封邮件,加上很多的邮件网关是不允许在一个短时间内发送太多的邮件的,因此这个仅仅是一个示例,并不具备实际上的作用。 2) 一般我们会采用多个sentinel,只需在一个sentinel上配置即可,否则将同一个消息会被多个sentinel多次处理。

附sendmail模块代码:

 

最佳实践:采用ELK(Elastic+Logstash+Kibana)进行日志收集告警(ElastAlert用起来不错),不启用这个事件通知功能。如果你的环境中没有ELK,或者启动一个Tcp Server进程,notify脚本将事件通过tcp方式吐给这个server,该Server收集一批事件后再做诸如发邮件的处理。

11.1.5.2 虚拟IP切换

在sentinel进行切换时还会自动调用一个脚本(如果设置的话),做一些自动化操作,比如如果我们需要一个虚拟IP永远飘在Master上(这个VIP可不是被应用用来连接redis 的,用过的人都知道连接redis sentinel并不依赖于VIP的),那么可以在sentinel配置文件中配置:

 

在发生主从切换,Master发生变化时,该脚本会被sentinel进行调用,调用的参数如其配置文件所描述的:

 

因此,我们可以在failover.sh中进行判断,如果该脚本所运行的主机IP等于新的Master IP,那么将VIP加上,如果不等于,则该机器为Slave,就去掉VIP。通过这种方式进行VIP的切换:

 

最早这样的用法是一个日本人写的blog,请参见:http://blog.youyo.info/blog/2014/05/24/redis-cluster/

11.1.5.3 持久化动态修改

其实相对于VIP的切换,动态修改持久化则是比较常见的一个需求,一般在一主多从多Sentinel的HA环境中,为了性能常常在Master上关闭持久化,而在Slave上开启持久化,但是如果发生切换就必须有人工干预才能实现这个功能。可以利用client-reconfig-script自动化该进程,无需人工守护,我们就以RDB的动态控制为例: Sentinel配置文件如下:

 

rdbctl.sh源代码:

 

原理和VIP切换一节基本一致,不再赘述。

11.1.5.4 Sentinel最大连接数

1. 问题描述

某准生产系统,测试运行一段时间后程序和命令行工具连接sentinel均报错,报错信息为:

 

此时应用创建redis新连接由于sentinel已经无法响应而无法找到master的IP与端口,因此无法连接redis,并且此时如果发生redis宕机亦无法进行生产切换。

2. 问题初步排查过程

首先,通过netstat对sentinel所监听端口26379进行连接数统计,此时连接则报错。如下图:

通过sentinel服务器端统计发现,redis sentinel 的连接中大部分都是来自于两台非同网段(中间有防火墙)的应用服务器连接(均为Established状态),并且来自其的连接也大约半个小时后稳步增加一次,而同网段的应用服务器连接sentinel的连接数基本保持一致。排除了应用的特殊性(采用的jedis版本和封装的工具类都是一样的)后,初步判断此问题与网络有关,更详细的说是连接数增加与防火墙切断连接后的重连有关。

3. 问题查证过程

此问题分为两个子问题: 1) 防火墙将TCP连接设置为无效时sentinel服务器为何没有断开连接,保持Established状态? 2) 为何连接数还会不断增加?

对于问题1) ,TCP在三次握手建立连接时OS会启动一个Timer来进行倒计时,经过一个设定的时间(这个时间建立socket的程序可以设置,如果没有设置则采用OS的参数tcp_keepalive_time,这个参数默认为7200s,即2小时)后这个连接还是没有数据传输,它就会以一定间隔(程序可以设定,如果没有设置则采用OS的参数tcp_keepalive_intvl,默认为75s)发出N(程序可以设定,如果没有设置则采用OS的参数tcp_keepalive_probes,默认为9次)次Keep Alive包。TCP连接就是通过上述的过程,在没有流量时是通过发送TCP Keep-Alive数据包,然后对方回应TCP Keep-Alive ACK来确定信道是否还在真实连接。通过查看Sentinel源代码,其默认是不开启Keepalive的(而jedis默认是开启的),并且默认对于不活动的连接也不会主动关闭的(timeout默认为0)。

对于防火墙,通过翻阅防火墙技术资料(详见下列描述,摘自:《Junos Enterprise Switching: A Practical Guide to Junos Switches and Certification》),我司采用的Juniper防火墙对于没有流量的TCP连接默认是30分钟,30分钟内没有流量就会断掉链路,而不会发送TCP Reset,同时在防火墙策略上并没有开长连接,使用的即为此默认设置。

因此在防火墙每半个小时将连接置为无效时,sentinel同时又禁止了Keepalive(因为默认设置Keepalive为0,即disable发送Keepalive包)。应用服务器的jedis虽然开启了keepalive,但是它发送的keepalive包由于防火墙已经将此链路标记为无效,而无法发送到sentinel端,而且jedis由于采用了OS默认参数,因此需要等待tcp_keepalive_time(2小时)后才启动发送Keep Alive包进行探活的,在tcp_keepalive_time+tcp_keepalive_intvl*tcp_keepalive_probes=7895s=131.58分钟后,jedis端才会认定这个连接断掉而清理掉这个连接。简单的说就是jedis会在很长一段时间后才会发keepalive包,并且这个包也是发不到sentinel上的,而sentinel本身也不会发送keepalive包,所以从sentinel这端看连接一直存在,而从jedis那端看7895s之后就会清理一次连接。这也解释了为什么防火墙将TCP连接断开后,sentinel端的连接并没有释放。

对于问题2) ,翻阅jedis源代码,jedis通过连接sentinel并pubsub来监听集群事件,以确定是否发生了切换,并且拿到新的master 地址和端口。如果断开则会5秒后尝试重连(JedisSentinelPool.java)。


因此,这是导致连接数不断上升的原因。 综上,防火墙相对频繁的断开和服务器不断重连导致在一个相对较短的时间内连接骤增,造成到达sentinel最大连接数,sentinel 的最大连接数在redis.h中定义,为10000:

4. 问题解决过程

此系统由于访问关系与网段规划间的安全问题,必须跨越防火墙,因此试图从配置角度解决此问题。

首先,联系网络相关同事,进行网络变更,开启从应用服务器到sentinel的链路相对的长连接,即无流量超时而断开的时间设置为8小时。以此手段降低断开频率,以便缓解短时间内不断重试连接造成的sentinel连接增长。

然后,通过阅读redis源代码(net.c),发现,sentinel也采用了redis 所有参数设置(通过config.c的函数void loadServerConfigFromString(char *config))。因此,通过设置redis 的下列两个参数可以解决这个问题,第一个参数是TCP Keepalive参数,此参数默认为0,也就是不发送keepalive。也就是改变OS默认的tcp_keepalive_time参数(在Unix C的socket编程中TCP_KEEPIDLE参数对应OS 的tcp_keepalive_time参数)。

该参数的官方解释为:

 

我们设置为tcp-keepalive 60,加快回收连接速度,从网络断开到连接清理时间缩短为60+75*9=12.25分钟。

同时,通过设置maxclients为65536,增大sentinel最大连接数,使得在上述12.25分钟即使有某种异常导致sentinel连接数增加也不至于到达最大限制。此参数的官方解释为:

 

对于redis 的timeout参数,由于启用这个参数有程序微小开销(会调用redis.c中的int clientsCronHandleTimeout(redisClient *c, mstime_t now_ms)),决定保持默认为0,而通过上述参数使用OS进行连接断开。

5. 问题解决结果

通过开发、网络和数据库团队的协同努力,配置上述参数和修改防火墙策略后,手动增加sentinel进程,超过原默认最大连接数10000后sentinel可以正常访问操作,并且通过tcpdump进行抓包,在指定时间内(1分钟),就有KeepAlive包对每个sentinel TCP连接进行探活,经过观察sentinel连接稳定,再未出现短时间内暴涨的情况。

6. 问题后续

在redis中默认不开启keepalive就是为了尽可能减小网络负载,榨干网络性能,尽可能达到redis的。在后续的程序运行中,如果发现网络是瓶颈时(在相当长的一段时间内不会),可以加大sentinel的keepalive参数,减小keepalive数据包的传输,这个修改是不影响redis对外服务的。

参考文档: http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/

附录:如何用TCPDUMP进行keep alive抓包

 

7. 问题再后续

我们后来在这个应用上发现一旦网络有抖动,sentinel的连接增加就回大幅度增加,后来通过jmap查看sentinelpool的实例竟然多达200多个,也就是说这个就是程序的问题,在sentinelpool上不应该多次实例化,而是采用已有连接进行重连。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
2月前
|
存储 缓存 NoSQL
蚂蚁金服P7私藏的Redis原理与实践内部笔记
Redis 是完全开源免费的,是一个高性能的key-value类型的内存数据库。整个数据库统统加载在内存当中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。因为是纯内存操作,Redis的性能非常出色,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB。
59 1
|
2月前
|
负载均衡 关系型数据库 应用服务中间件
高可用系列文章之二 - 传统分层架构技术方案
高可用系列文章之二 - 传统分层架构技术方案
|
28天前
|
人工智能 运维 监控
构建高性能微服务架构:现代后端开发的挑战与策略构建高效自动化运维系统的关键策略
【2月更文挑战第30天】 随着企业应用的复杂性增加,传统的单体应用架构已经难以满足快速迭代和高可用性的需求。微服务架构作为解决方案,以其服务的细粒度、独立性和弹性而受到青睐。本文将深入探讨如何构建一个高性能的微服务系统,包括关键的设计原则、常用的技术栈选择以及性能优化的最佳实践。我们将分析微服务在处理分布式事务、数据一致性以及服务发现等方面的挑战,并提出相应的解决策略。通过实例分析和案例研究,我们的目标是为后端开发人员提供一套实用的指南,帮助他们构建出既能快速响应市场变化,又能保持高效率和稳定性的微服务系统。 【2月更文挑战第30天】随着信息技术的飞速发展,企业对于信息系统的稳定性和效率要求
|
28天前
|
人工智能 JSON 运维
AI大模型运维开发探索第三篇:深入浅出运维智能体
大模型出现伊始,我们就在SREWorks开源社区征集相关的实验案例。玦离同学提供了面向大数据HDFS集群的智能体案例,非常好地完成了运维诊断的目标。于是基于这一系列的实验和探索。本文详细介绍智能体在运维诊断中的应用探索。
|
1月前
|
存储 监控 NoSQL
Redis 架构深入:主从复制、哨兵到集群
大家好,我是小康,今天我们来聊下 Redis 的几种架构模式,包括主从复制、哨兵和集群模式。
Redis 架构深入:主从复制、哨兵到集群
|
1月前
|
弹性计算 NoSQL 测试技术
倚天使用|Redis性能高30%,阿里云倚天ECS性能摸底和迁移实践
Redis在倚天ECS环境下与同规格的基于 x86 的 ECS 实例相比,Redis 部署在基于 Yitian 710 的 ECS 上可获得高达 30% 的吞吐量优势。成本方面基于倚天710的G8y实例售价比G7实例低23%,总性价比提高50%;按照相同算法,相对G8a,性价比为1.4倍左右。
137500 3
|
1月前
|
分布式计算 API 数据处理
Flink【基础知识 01】(简介+核心架构+分层API+集群架构+应用场景+特点优势)(一篇即可大概了解flink)
【2月更文挑战第15天】Flink【基础知识 01】(简介+核心架构+分层API+集群架构+应用场景+特点优势)(一篇即可大概了解flink)
56 1
|
2月前
|
缓存 负载均衡 监控
从零开始搭建一个高可用的后端架构
【2月更文挑战第6天】本文将介绍如何从零开始搭建一个高可用的后端架构,包括架构设计、技术选型、部署和监控等方面。通过对各种技术的分析和实践,帮助读者深入理解高可用架构的实现和优化。
|
2月前
|
Kubernetes Linux 开发工具
容器开发运维人员的 Linux 操作机配置优化建议
容器开发运维人员的 Linux 操作机配置优化建议
|
2月前
|
消息中间件 运维 应用服务中间件
容器化运维:构建高可用RabbitMQ集群的Docker Compose指南
容器化运维:构建高可用RabbitMQ集群的Docker Compose指南
154 0