热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【技术分享】代晓磊:大街网Redis集群运维之路

本文对Redis集群进行了介绍,以及大街Redis集群运维之

本文整理自DTCC2016主题演讲内容,录音整理及文字编辑IT168@ZYY@老鱼。如需转载,请先联系本公众号获取授权!

演讲嘉宾
代晓磊
大街网数据库Cache负责人

曾就职于人人网,主要负责人人无线数据库维护、统计部门Inforbright数据仓库库维护。2013年-至今,大街网数据库Cache负责人。

分享内容

大家好,我是大街网的代晓磊,今天我演讲的主题是《Redis集群在大街网的应用实践》,我的分享主要分为以下几部分:


第一部分与大家分享“大街网Redis缓存架构之路”,主要经过了三个阶段,第一个阶段是单节点主从阶段,第二阶段是我们自建hash集群,最后一个也是最主要的阶段是Redis Cluster的应用。
 
早期的Redis使用是单节点的主从,并且所有的主节点都部署在同一台服务器,导致主服务器压力比较大,而从服务器没有任何请求。高可用是通过服务器级别的LVS+KeepAlive来实现,这种架构只有当主服务器宕机的时候,所有redis节点才能切换到备用服务器。因为高可用是基于服务器级别的,任何单事例的redis宕机都不会切换到备事例,会对业务造成较大的影响,并且Redis服务器的负载也不均衡。还有一个问题就是单Redis的容量和扩展性都没有。


基于单Redis主从的各种问题,我们就搭建了第二个架构——自建hash集群。优点是解决了单主从的性能或者扩展问题,但依然没有解决高可用问题,因为该hash集群没有挂载slave,也没有Redis实例宕机的切换逻辑。该架构主要有几个特点:引入ZooKeeper配置中心,程序访问的是配置中心的数据源,目的方便以后的迁移;引入封装好的中间层,该架构的优点是通过多个hash节点解决了单Redis带来的性能瓶颈, 封装好的中间层proxy做hash,通过一致性hash算法,使一个节点扩展到多个节点,这样的话它的并发,包括扩展性上都有一定的提升,最关键的是:依然没有解决高可用问题,任何一个hash节点的宕机,就会丢失1/N的线上请求(N是hash节点数)。


为了提供一个高可用、易维护的方案,我们推出了第三种架构:Redis Cluster。


我们首先对Redis Cluster进行简单的介绍,首先我们先说redis集群的优点:

(1)首先我们最关心的是高可用,Redis集群高可用是指在集群中master节点至少有1个slave节点存活的条件下,当master宕机,salve就会通过集群内部一半以上的节点投票选举为新的master节点。

(2)第二高性能,高性能是指集群不需要其他的中间件(比如proxy),降低了在中间件级别的性能消耗,并且没有了单节点中复杂的merge操作。

(3)扩展性好:当集群的空间以及性能出现瓶颈时,我们可以通过添加新的集群节点来水平扩展。注意集群并不是自动扩展,需要脚本支持。

(4)丰富的集群命令:redis cluster提供了丰富的集群命令,大家可以上官网(redis.io)上去把20个redis命令都熟悉和执行一遍就OK,这些命令足够redis集群的基本运维,涵盖了查看集群信息、hash slots分布、hash slots迁移等等操作。经常看到网上的博客说redis cluster缺点说需要依赖redis-trib.rb这个脚本才能维护,并且需要会ruby。我认为通过了解了20个redis命令,自己写脚本就可以实现redis集群的各种运维。

Redis集群缺点是:

(1)不支持多keys操作,通过查看官网文档可以了解,Redis集群主要担心多个大keys的merge会对性能带来较大的影响,所以最主要的问题是性能问题。但该操作也不能说的那么严格,如果两个keys在同一个Hash桶里,也可以进行多keys操作,但是为了避免问题,还是不要执行多keys操作。

(2)只能使用0号数据库

(3)还有一个缺点是缺乏大规模的线上使用,之前也有一些互联网的公司在用这个东西,但是有很多坑大家都没有测试出来,摸着石头过河,大家都不知道水有多深,不过随着redis cluster版本的更新,目前redis cluster已经在不少大互联网公司的推广使用。


上图是我模拟的主结点被kill掉之后redis集群的自我恢复,我想看内部大概需要多久能够提升。这个failover主要有两个关键点:第一是Cluster node的timeout时间,就是nodes之间在多少微秒后仍然获取不到节点的请求反馈。当一个master结点被kill掉以后,集群中节点在设定的超时时间内获取不到该结点的反馈,这个探测结点就会把该结点标记为fail,当半数以上的集群结点都选举同一个结点为fall down时,就会启动failover过程。第二就是投票选举新master的时间较短,如log中所示,整个切换用时不到一秒钟,这就是集群的高可用性。
 
接下来看一下大街网Redis Cluster的现状。


以下是大街网目前使用的Redis集群架构。特点如下:

(1)还是基于ZooKeeper做配置管理,并且ZK的配置只在2种情况下会被程序访问,一是程序启动时,初始化集群连接。二是我们迁移或者下线节点,修改了ZK中数据源的配置。目的就是做到集群对开发是透明的,也就是说开发数据库使用Redis集群时,只需要在程序中配置一个数据源就可以了。数据源中“种子节点“的配置也是可选的,比如一个6主6从的Redis集群,可以给它配4个结点也可以配6个结点,在程序启动的时候,它会取里面的数据源配置,检测种子结点。我们能够保证在至少一个种子节点可用的情况下,程序可以启动并正常使用(PS:程序启动时会报一些错误,但不影响使用)。

(2)中间层封装,目的是为了提供通用接口,原因是老的那套hash集群也是依赖接口,能够保证我推广Redis Cluster的时候,老的hash集群可以比较平滑的迁移到Redis Cluster上。二是基于通用的API,假如Jedis这个driver出现重大bug,我们可以对它进行替换,这样替换的成本也比较低。 


(3)按业务来划分集群的,避免不同业务的相互影响。如果集群混用就可能出现一个人存的key比较大,或者执行了keys *等危险命令,导致整个集群的速度慢,会影响其它业务,所以我们根据之前的业务划分集群。


关于我们遇到的坑,第一点内存相关的设定

(1)最大内存没有设定,如果再加上keys又没有设定过期时间,这样随着业务的增长,redis就会一直占用内存,直到被linux oom kill掉。

(2)keys的过期时间,在功能上可以分为持久化和缓存集群。持久化集群代表keys只在redis中存,mysql中没有,这种keys不能设定过期时间。另一种就是缓存集群,这种需求的集群占95%以上,这些集群keys需要设定过期时间,就算缓存失效,当用户访问到这个keys的时候还会从mysql中取,同时set到缓存集群中。

(3)keys的过期策略,这个主要是redis使用到最大内存后如何处置的问题,我主要讲3个策略,一是volatile-lru,这个是设定keys过期时间缓存集群默认配置,redis会根据lru算法淘汰数据。二是allkeys-lru,对于一些非核心、并且程序员忘记给keys设定过期时间的redis配置,就是keys在set到redis集群时,redis会给keys标记一个时间(可以使用object idletime命令来查看keys的空转时间),当内存使用到上限时,redis根据lru算法来淘汰keys。三是:no-enviction策略,这个是redis集群的默认策略,就是永不淘汰keys,这样一单redis使用到内存上限,集群就无法写入了。



接下来可以看一下内存碎片率的问题,由于redis没有内存回收的策略。我们可以通过Redis_fragmentation_ratio这个参数可以反映出内存使用情况,该参数是操作系统分配内存(used_memory_rss)除以redis使用内存(used_memory)所得.

首先看内存碎片率大于1的情况。在redis使用过程中,由于一些keys的过期或者被主动清理,导致redis系统分配比实际使用的内存要多的多,呈现大于1的情况,要解决这个问题,可以通过重启Redis实例解决。


当Redis事例跟大量程序共用服务器时,内存碎片经常会出现小于1的情况。比如本来要存10G,但是系统分配的只有3G,此时,内存碎片就小于1,当Redis申请不到足够的内存,这样就会使用swap,导致性能急剧下降。解决方式:删除redis中的一些keys来空出内存,或者停掉一些程序后(停掉程序目的是节省内存,为该实例搭建从库而空出bgsave的内存),对该节点进行迁移。


核心参数主要有两个,

一是redis集群nodes探测的超时时间:系统默认的结点之间的超时时间是十五秒,我们设定的是5秒,当然,这可以根据自己不同的环境来设定,比如在一些虚拟机上,可以把这个参数设大。如果你们的网络足够稳定,并且你想让集群更快的发现出问题的node,并且尽快的执行salve提升,那就将该参数设小。

二是cluster-require-full-coverage参数,默认的值是yes,该参数配置成no的主要目的是在集群某些hash slots不可用的情况下,其他的hash slots仍然能够接受请求。举个例子如果集群里是3主3从,其中一组主从全部宕掉,其它两组主从依然能够接受读写请求,但这之中有个限制,整个集群必须有半数以上的结点配置是可用的,也就是说,如果3主3从的集群挂掉2主2从,这个集群就无法用了,因为不满足半数以上节点可用的情况。


另外,很多年轻的程序员在开发程序时,经常会check一下,查找程序里的keys是否已经set到线上Redis中,他们会连接到redis,执行keys *命令,该命令会阻塞线上请求。我们已经将这些危险命令在配置文件中进行了rename。对于上面的需求可以使用redis-cli的—scan –pattern来实现。


接下来探讨Redis连接周期性异常的问题,问题就是每半小时的大量的连接,并且不是长连接,一般程序连接redis都是长连接,出现这种问题一般可能被攻击或者某些程序的异常,必须及时的解决,我们最后通过tcpflow来抓取问题时间段的连接数据包情况,最终定位到具体的IP,并且找到原因。


如图所示出现了线上官客、www、job同时又大量的5XX报警,时间点发现是下午4:04到4:14左右,一般基础业务的同时抖动肯定跟底层DB或者cache有关。通过查看DB监控发现这几个DB实例性能稳定,然后将问题定位到缓存,因为跟职位相关,所以直接找职位相关的集群,进行问题排查。


通过查看job集群的Redis log,发现在出问题的时间段有2条aof写入异常:disk is busy?,通过查看源码发现,对于aof持久化,如果在2秒内aof文件无法写入,redis就不再接受任何请求,直到写入成功,在高的硬盘IO情况下,aof出现无法写入。通过查看服务器的IO负载情况,发现两个峰值,跟5XX的时间段也能匹配的上。这时问题的关键点就在于:是什么导致硬盘IO的峰值出现的。


第三步进行问题定位,因为该服务是redis专用服务器,能够导致如此高IO的操作,只有2种情况,一是aof rewrite,另一种情况就是bgsave来存rdb快照。进入redis数据目录,发现在出问题的时间段内,集群执行了rdb备份操作,从而导致了这两个时间段内的高IO。
 
解决以上问题的方法:(1)财大气粗的可以直接上SSD硬盘(2)将aof持久化集群跟缓存集群隔离,避免相互影响。
 
对于出现的问题,我对Redis持久化比较纠结,到底是用AOF还是rdb?为了解决困惑,我们先来看一下AOF和RDB的区别。

AOF的优点一:从启动起来就有序保存了所有写入操作,而且是在文件尾追加的,aof本身对IO的消耗并不高。

AOF优点二、误操作能及时恢复数据:如果有类似flushdb等操作,只需要修改下aof文件,剔除fulshdb操作,然后重启redis即可。

缺点是aof文件比较大,需要一段时间后进行aof rewrite。

RDB优点:RDB二进制文件非常紧凑,非常适合备份以及快速恢复。

RDB缺点是rdb只是某一时刻的内存快照,适合缓存集群的备份,不适合存储集群。

所以总结来说,根据需求选择合适的备份方式,缓存集群使用RDB备份,存储集群使用AOF。如果适当提高机器配置,因为redis主要是基于内存,aof阻塞问题也是能够解决的。


下面讲一下自动化,要做自动化之前必须有一个规范,目录,文件命名,keys使用,只要有了规范,自动化也不是非常难。二是自动化部署和配置,比如可能经常手动加内存,手误设定内存太小会导致写入问题。三是自动化监控,监控Redis性能,包括内存使用等。四是Redis自动迁移,五是集群扩容,六是自动化备份,七是分析包括slowlog分析、keys分布。
 

keys命名规范:命名之前应该想好要简单明确。一个好的命名对分析Redis节点的keys分布非常有帮助,比如命名一个job集群,可以用job_invite_*的方式来表示职位邀约的keys。这样做的好处是,当我需要对keys分布分析时,可以通过”_”来截取分析不同业务的keys。


Redis使用规范,是将我们遇到的坑加以规避。比如禁止将大量成员存储到一个hash key中,因为执行hgetall性能非常的差;禁止连接线上redis执行keys *dxl这种方式来过滤keys;keys建议设定过期时间,除非把redis当存储使用;合理使用Redis的数据类型:list、set、hash,因为合适的类型对性能和内存使用都能带来好处。


二是自动化部署Redis Cluster,创建集群的时候,只需要在配置表填写集群节点的相应信息,然后我们程序会调用配置信息自动建立集群。


其次集群配置,比如为集群扩展内存,之前线上Redis集群需添加内存是手工操作,在为最后一个结点设定内存时时,内存值少拷贝了一位,本来是几十G的东西弄成了几个G,redis可以设定成功,并不报错,但是程序访问会出问题,并且redis log中也会提示内存设置过小。解决方式,通过程序来自动设定,程序会检查线上redis已经使用的内存,跟DBA设定的内存进行比对后,只有DB设定的数值大才设定到线上redis。


自动化监控:Redis的命中率是所有人都关心的。可以写一个脚本,每十分钟通过info stats来采集计算,通过这个命中率就会反映出集群的使用情况。


自动化监控之内存使用—基于内存监控统计表,所有基于内存的报警都出自这个表,比如通过采的内存数据看出集群内存增长情况,是否是正常的增长,并且为内存自动添加提供数据支持。

自动化监控之连接监控:每十分钟抓链接请求情况,前面PPT提到的链接异常就是靠下面的统计表而来,对于异常的大量请求都会及时报警,然后DBA跟进分析,看是推广带来的连接还是被攻击。


自动化迁移工具:

在推广redis cluster的过程中,经常有程序员经常会说:这个单redis节点的keys必须全部给我导到集群里,否则我的程序会有各种问题。之前没有迁移工具,只能迁移那些缓存redis节点或者集群(因为这些集群keys在mysql中都有,他们只需要凌晨跑一遍全量数据,新redis集群中就有keys了),Redis集群推进比较缓慢。自从发现Redis-port这个工具之后,就不会产生由于无法迁移旧集群keys所无法迁移了。

Redis-port模拟了redis slave的角色。大致分为如图所示的七步。

1、rsync  2、fork进程 3、更新入buffer 4、dump rdb 5、fork进程exit 6、send rds 7、将buffer更新到集群


五是集群扩容

集群扩容主要分2种方式:

(1)如果之前集群分配的内存较少,现在集群所在的服务器内存也比较充裕,解决扩容可以直接扩大内存就搞定


(2)第二种方式是增加新结点,我的建议是直接增加1倍,因为这样避免了hash slots的零散,比如一个3主3从的redis集群扩展到换到6主6从,只需要把原来主节点上一半的hash slots分别分配到新加入的3个master上就OK,迁移程序好控制,slots分布也均匀。

增加新节点的扩容方式需要自己写脚本来实现,具体迁移的细节,redis官网上有,参考下面的连接:http://redis.io/commands/cluster-setslot


六是自动化备份,我们是根据配置表做的,只需要将配置表中:是否备份置为1即可,并且备份过程是自动化的。


性能分析之slow log,slowlog可以发现集群中执行时间长的命令,通过命令行:slowlog get 的输出是比较规整的,但如果需要存到统计表里还是需要花一些心思的,我们会将慢SQL统一整理分析后发给相应的负责人优化。


最后是keys分布,如果一个基础业务集群在1天内内存翻了一倍,谁能告诉我是哪些keys增加导致的?这时就需要keys分布工具来分析每一类keys的数量、占用内存大小等等,通过跟历史数量以及内存使用的对比可以找出问题的答案。我们采用RDB tools实现Keys分布。


今天的分享到此结束,希望我们的经验能给大家一定的帮助,谢谢大家!

关于DTCC
中国数据库技术大会(DTCC)是目前国内数据库与大数据领域最大规模的技术盛宴,于每年春季召开,迄今已成功举办了七届。大会云集了国内外顶尖专家,共同探讨MySQL、NoSQL、Oracle、缓存技术、云端数据库、智能数据平台、大数据安全、数据治理、大数据和开源、大数据创业、大数据深度学习等领域的前瞻性热点话题与技术,吸引IT人士参会5000余名,为数据库人群、大数据从业人员、广大互联网人士及行业相关人士提供了极具价值的交流平台。



推荐阅读
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 浏览器中的异常检测算法及其在深度学习中的应用
    本文介绍了在浏览器中进行异常检测的算法,包括统计学方法和机器学习方法,并探讨了异常检测在深度学习中的应用。异常检测在金融领域的信用卡欺诈、企业安全领域的非法入侵、IT运维中的设备维护时间点预测等方面具有广泛的应用。通过使用TensorFlow.js进行异常检测,可以实现对单变量和多变量异常的检测。统计学方法通过估计数据的分布概率来计算数据点的异常概率,而机器学习方法则通过训练数据来建立异常检测模型。 ... [详细]
  • 本文介绍了使用Spark实现低配版高斯朴素贝叶斯模型的原因和原理。随着数据量的增大,单机上运行高斯朴素贝叶斯模型会变得很慢,因此考虑使用Spark来加速运行。然而,Spark的MLlib并没有实现高斯朴素贝叶斯模型,因此需要自己动手实现。文章还介绍了朴素贝叶斯的原理和公式,并对具有多个特征和类别的模型进行了讨论。最后,作者总结了实现低配版高斯朴素贝叶斯模型的步骤。 ... [详细]
  • Spring框架《一》简介
    Spring框架《一》1.Spring概述1.1简介1.2Spring模板二、IOC容器和Bean1.IOC和DI简介2.三种通过类型获取bean3.给bean的属性赋值3.1依赖 ... [详细]
  • 云原生应用最佳开发实践之十二原则(12factor)
    目录简介一、基准代码二、依赖三、配置四、后端配置五、构建、发布、运行六、进程七、端口绑定八、并发九、易处理十、开发与线上环境等价十一、日志十二、进程管理当 ... [详细]
  • Django + Ansible 主机管理(有源码)
    本文给大家介绍如何利用DjangoAnsible进行Web项目管理。Django介绍一个可以使Web开发工作愉快并且高效的Web开发框架,能够以最小的代价构建和维护高 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 本文介绍了在CentOS 6.4系统中更新源地址的方法,包括备份现有源文件、下载163源、修改文件名、更新列表和系统,并提供了相应的命令。 ... [详细]
  • 全面介绍Windows内存管理机制及C++内存分配实例(四):内存映射文件
    本文旨在全面介绍Windows内存管理机制及C++内存分配实例中的内存映射文件。通过对内存映射文件的使用场合和与虚拟内存的区别进行解析,帮助读者更好地理解操作系统的内存管理机制。同时,本文还提供了相关章节的链接,方便读者深入学习Windows内存管理及C++内存分配实例的其他内容。 ... [详细]
  • 程序员如何选择机械键盘轴体?红轴和茶轴对比
    本文介绍了程序员如何选择机械键盘轴体,特别是红轴和茶轴的对比。同时还介绍了U盘安装Linux镜像的步骤,以及在Linux系统中安装软件的命令行操作。此外,还介绍了nodejs和npm的安装方法,以及在VSCode中安装和配置常用插件的方法。最后,还介绍了如何在GitHub上配置SSH密钥和git的基本配置。 ... [详细]
author-avatar
范尼萧_659
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有