热门标签 | 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余名,为数据库人群、大数据从业人员、广大互联网人士及行业相关人士提供了极具价值的交流平台。



推荐阅读
  • Python 数据可视化实战指南
    本文详细介绍如何使用 Python 进行数据可视化,涵盖从环境搭建到具体实例的全过程。 ... [详细]
  • 本文深入探讨了NoSQL数据库的四大主要类型:键值对存储、文档存储、列式存储和图数据库。NoSQL(Not Only SQL)是指一系列非关系型数据库系统,它们不依赖于固定模式的数据存储方式,能够灵活处理大规模、高并发的数据需求。键值对存储适用于简单的数据结构;文档存储支持复杂的数据对象;列式存储优化了大数据量的读写性能;而图数据库则擅长处理复杂的关系网络。每种类型的NoSQL数据库都有其独特的优势和应用场景,本文将详细分析它们的特点及应用实例。 ... [详细]
  • 美团优选推荐系统架构师 L7/L8:算法与工程深度融合 ... [详细]
  • 综合实训 201521440015
    Chinesepeople’publicsecurityuniversity网络对抗技术实验报告实验五综合渗透学生姓名常泽远年级15区队4指导教师高见信息技术与网络安全学院2018 ... [详细]
  • 本文探讨了 TypeScript 中泛型的重要性和应用场景,通过多个实例详细解析了泛型如何提升代码的复用性和类型安全性。 ... [详细]
  • 面试题总结_2019年全网最热门的123个Java并发面试题总结
    面试题总结_2019年全网最热门的123个Java并发面试题总结 ... [详细]
  • 本文详细介绍了 Java 网站开发的相关资源和步骤,包括常用网站、开发环境和框架选择。 ... [详细]
  • RocketMQ在秒杀时的应用
    目录一、RocketMQ是什么二、broker和nameserver2.1Broker2.2NameServer三、MQ在秒杀场景下的应用3.1利用MQ进行异步操作3. ... [详细]
  • 高端存储技术演进与趋势
    本文探讨了高端存储技术的发展趋势,包括松耦合架构、虚拟化、高性能、高安全性和智能化等方面。同时,分析了全闪存阵列和中端存储集群对高端存储市场的冲击,以及高端存储在不同应用场景中的发展趋势。 ... [详细]
  • 网站访问全流程解析
    本文详细介绍了从用户在浏览器中输入一个域名(如www.yy.com)到页面完全展示的整个过程,包括DNS解析、TCP连接、请求响应等多个步骤。 ... [详细]
  • MySQL的查询执行流程涉及多个关键组件,包括连接器、查询缓存、分析器和优化器。在服务层,连接器负责建立与客户端的连接,查询缓存用于存储和检索常用查询结果,以提高性能。分析器则解析SQL语句,生成语法树,而优化器负责选择最优的查询执行计划。这一流程确保了MySQL能够高效地处理各种复杂的查询请求。 ... [详细]
  • 浏览器作为我们日常不可或缺的软件工具,其背后的运作机制却鲜为人知。本文将深入探讨浏览器内核及其版本的演变历程,帮助读者更好地理解这一关键技术组件,揭示其内部运作的奥秘。 ... [详细]
  • 作为140字符的开创者,Twitter看似简单却异常复杂。其简洁之处在于仅用140个字符就能实现信息的高效传播,甚至在多次全球性事件中超越传统媒体的速度。然而,为了支持2亿用户的高效使用,其背后的技术架构和系统设计则极为复杂,涉及高并发处理、数据存储和实时传输等多个技术挑战。 ... [详细]
  • LVS-DR数据包流向分析介绍
    下文给大家带来LVS-DR数据包流向分析介绍,希望能够给大家在实际运用中带来一定的帮助,负载均衡涉及的东西比较多,理论也不多,网上有很多书籍, ... [详细]
  • 【Linux332】LVS的DR配置详解(ipvsadm+arptables)
    文章目录1.DR简 ... [详细]
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社区 版权所有