互联网和 web 的蓬勃发展正在改变着我们的世界, 随着互联网的不断发展和壮大, 企业数据规模越来越大, 并发量越来越高, 关系数据库无法应对新的负载压力, 随着 Hadoop,Cassandra,MongoDB,Redis 等 NoSQL 数据库的兴起, 因其良好的可扩展性, 弱化数据库的设计范式, 弱化一致性要求, 在解决海量数据和高并发的问题上明显优于关系型数据库因而很快广泛应用于互联网业务中
Redis 作为基于 K-V 的 NoSQL 数据库, 具有高性能丰富的数据结构持久化高可用分布式支持复制等特性从 09 年至今, 经历 8 年多的锤炼, 已经非常稳定, 并且得到业界的广泛认可和使用, 同时社区非常活跃
今天我们有幸邀请到了 Redis 中国用户组主席张冬洪老师, 请他分享 Redis 的核心技术, 应用现状及发展方向等
遇见未来
自我介绍, 团队介绍
我是来自新浪微博研发中心的高级 DBA 张冬洪, 目前在微博带一个小组, 主要负责微博平台手机微博话题红包飞开放平台私信以及内容管控项目的数据库产品运维和服务保障工作工作中涉及的数据库产品主要包括 MySQLRedisMemcachedMCQKafkaPikaPostgresql 等
目前您的团队工作重心是什么呢?
微博研发中心数据库部门主要负责全微博平台的后端资源的托管和运维, 涉及的资源种类比较多, 数据量比较大, 业务线和资源实例数目也是非常之多, 并发量巨大而这些正是微博这种体量的公司应该具有的, 微博作为当今中文社交媒体的第一品牌, 拥有超过 3.76 亿的月活用户, 也是当前社会热点事件传播的最主要平台, 其中包括但不限制于大型活动(如: 里约奥运会朱日和沙场大点兵等), 春晚, 明星动态(如: 王宝强离婚事件女排夺冠乔任梁去世白百合出轨 TFBOYS 生日鹿晗关晓彤 CP 等)
而热点事件往往具有不可预见性和突发性, 并且伴随着极短时间内流量的数倍增长, 甚至更多, 有时持续时间较长如何快速应对突发流量的冲击, 确保线上服务的稳定性, 是一个非常巨大的挑战和有意义的事情为了达到这一目标, 需要有一个完善的, 稳定可靠的, 健壮的数据库运维体系来提供支撑和管理, 所以我们团队也是在领导的指导下, 有目标有计划的开展一些数据库自动化运维平台的建设工作
在业余的时间我和其他几大互联网公司的朋友一起发起了 Redis 中国用户组(简称 CRUG), 也欢迎大家加入我们
Redis 在过去的版本演进中, 比较重大的变化包括哪些呢? 在最新 4.0 版本上, 您认为最核心的变化是什么呢? 您关注的新特性有哪些, 可以简单介绍下吗?
我最早接触应该是在 12 年的时候, 当时最新的版本应该是 2.6.x 那个时候也没有在线上用, 只是学习 Linux 的时候了解过所以知道 Redis 的版本号命名规则借鉴了 Linux 的方式, 版本号第二位如果是奇数, 则为非稳定版本, 如果为偶数, 则为稳定版本
这里我说下稳定版本的一些主要改进吧:
Redis2.6
1)键的过期时间支持毫秒
2)从节点提供只读功能
3)服务端支持 Lua 脚本
4)放开客户端连接数的硬编码限制
5)去掉虚拟内存相关功能等
Redis2.8
1)完善主从复制功能, 实现增量复制
2)Redis 设置明显的进程名, 在系统中 ps 命令即可查看
3)发布 / 订阅添加 pub/sub 命令
4)Redis Sentinel 第二版发布, 较 Redis 2.6 更加完善, 可以线上使用
5)可以通过 config set 命令设置 maxclients 等
Redis3.0
1)推出 Redis 的分布式集群 Redis Cluster
2)全新的 embedded string 对象编码结果, 优化小对象的内存访问, 在特定的工作负载下能大幅度提升性能
3)LRU 算法提升
4)config set 设置 maxmemory 的时候可以设置不用的单位
5)新的 Client pause 命令, 在指定时间内停止处理客户端请求等
Redis3.2
1)添加 GEO 功能
2)新的 List 编码类型 quicklist
3)SDS 在速度和节省空间上都做了优化
4)Lua 脚本功能增强
5)新的 RDB 格式, 仍兼容旧版 RDB, 同时加载速度上也有提升
6)Cluster nodes 命令加速等
在 Redis4.0 版本上, 我认为最核心的功能应该是支持了 module, 这极大的丰富的 Redis 的功能, 使得许多 Redis 本身不具有的, 第三方开发者拓展的功能也能加载到 Redis 中当一个功能进行使用, 比如 RediSearchReJSONRedis-ML 等除此之外, 还看到有很多新特性:
1)psync2.0, 优化了之前版本主从节点切换必然引起全量复制的问题
2)提供全新的缓存剔除算法 LFU, 并对已有算法进行了优化
3)提供了非阻塞 del 和 flushall 和 flushdb 功能, 有效解决了删除 bigkey 可能造成的 Redis 阻塞
4)提供了 RDB-AOF 混合持久化格式
5)提供 memory 命令, 实现对内存的更为全面的监控统计
6)Redis Cluster 兼容 NAT 和 Docker
7)引入 Jemalloc 库, 优化内存访问等等
您能介绍一下 Redis 中的数据类型和它们的使用场景吗?
Redis 之所以能够被广泛的应用于企业的架构中, 而且是不可或缺的重要组成部分, 也可以说是标配吧, 其中很重要的一点就是得益于它具有丰富的数据结构, 这也是它逐渐替代 Memcached, 备受青睐的重要原因那么 Redis 都提供哪些数据类型呢?
相信对 Redis 有了解过的同学都知道, 它的数据类型有: StringHashListSetZsetBitmapsHyperLogLogGEO 等
随着互联网的兴起和 Redis 技术的不断完善和发展, 它已经被广泛应用于各行各业中, 应用场景也是百花齐放比如: 会话缓存 (Session cache) 全页缓存 (FPC) 手机验证码访问频率限制 / 黑白名单消息队列发布与订阅消息通知排名 / 排行榜 / 最新列表计数器 (比如微博的转评赞计数阅读数(浏览数, 视频播放计数) 博文数 (发帖数) 粉丝数关注数 (喜欢商品数) 未读数 (动态数)) 共同好友 / 喜好 / 标签推送下拉刷新私信商品库存管理 (限时的优惠活动信息) 证券指标实时计算, 发号器 / UUID 以及随着 LBS(基于位置服务)的发展, 加入的 GEO(地理信息定位)的功能和基于 Lua 自定义命令或功能等等大家在使用过程中, 需要结合自己的业务场景, 选择正确的数据类型
Redis 数据库有哪些主要的特点和优势? 使用时有什么需要关注的点, 可能会带来哪些问题, 可否通过实践案例详细描述一下?
Redis 作为基于 K-V 的 NoSQL 数据库, 具有高性能丰富的数据结构持久化高可用分布式支持复制等特性从 09 年至今, 经历 8 年多的锤炼, 已经非常稳定, 并且得到业界的广泛认可和使用, 同时社区非常活跃, 开发者又很严谨, 这使得 Redis 版本非常精简, bug fix 非常高效根据 similarweb.com 的统计, 中国 Redis 用户占全球 Redis 用户的 40.96%, 所以我们在使用的过程中遇到的问题, 大部分可能都有解决方案
需要关注的点比较多, 之前在 CRUG 深圳站活动的分享中也提到过一些, 下面举一些例子吧:
1)安全问题: Redis 用非 root 用户启动, 并且运行在内网, 尽可能不要暴露在外网, 配置认证 requirepass xxx, 减少被攻击的风险; 开启危险命令认证(keys-need-auth yes rename-command KEYS MY_KEYS)
2)容量问题: 合理评估; 合理使用内存分配策略(no-envictionallkeys-randomallkeys-lruvolatile-randomvolatile-ttlvolatile-lru); 检查是否有内存碎片; 选择合适的服务类型(Redis cluster 或者 pika); 水平拆分; 性能满足的条件下选择诸如 ziplist 类的内部编码
3)big-key 问题: 可能会引起慢查或者带宽瓶颈, 按照业务逻辑拆成小 key 或者业务解耦剥离 big-key 或直接改用其他存储方式
4)hot-key 问题: Redis 是单进程, 节点实例很容易成为系统的短板, 垂直扩容; 增加 local cache; 如果只是简单的 k-v 结构, 可以考虑使用 Memcached
5)使用姿势问题: 避免使用阻塞操作(如: flushallflushdbkeys * 等); 尽量使用 Pipeline, 减少 syscall 带来的网络 IO, 但要注意限制数据量大小; 对多个元素操作时, 像使用 SORTLREMSUNION, 计算复杂度为 O(N), 避免线上乱用; 尽可能使用最新的版本
6)Key 过期问题: 合理设置过期时间; 如果存在许多该过期的 key 而没被及时删除, 可以通过命令 scanhscansscanzscankeys * 遍历一遍 key 的方式实现
7)配置上: 建议开启 tcp-keepalive,tcp-backlog, 从库设置 readonly yes
8)系统设置: 关闭 NUMA; 关闭 transparent _hugepage; 关闭 swap
等等, 大家有问题的时候可以相互交流
Redis 如何做消息队列?
Redis 做消息队列, 有两种实现方式:
第一种: 通过数据结构 List 来实现
优点: 能够实现持久化; 支持集群; 接口使用简单
缺点:
如上图所示, 一条消息只会被一个消费者消费, 所以不存在有多个消费者消费一条消息
生产者和消费者的高可用或崩溃后的处理机制需要自己实现
当生产者消息写入太快, 消费者消费太慢, 则有可能会导致内存溢出问题, 导致进程 crash
第二种: 通过 pub/sub 来实现
优点:
一个生产者可以对应多个消费者, 但是必须保证消息发布者和消息的订阅者同时在线, 否则, 否则一旦消息订阅者由于各种异常情况而被迫断开连接, 在其重新连接后, 其离线期间的消息是无法被重新通知的 (即发即弃) 当然, 生产者不需要关心有多少的订阅者, 也不用关心订阅者的具体信息, 而订阅者可以根据需要自由选择订阅哪些频道: 支持集群; 接口使用简单等
缺点:
没有持久化机制, 属于即发即弃模式, 因此也不需要制定消息的备份和恢复机制
Redis 没有提供保证 pub/sub 消息性能的方案
当大量的消息到达 Redis 服务时, 如果订阅者不能及时完成消费, 则就会导致消息堆积, 引发上面一样的内存问题
您可以介绍下当前 Redis 的集群功能和实现吗?
要了解 Redis 的集群功能, 可以从数据分片数据迁移集群通讯故障检测以及故障转移等方面进行了解, Cluster 相关的代码也不是很多, 注释也很详细, 可自行查看, 地址是: https://github.com/antirez/redis/blob/unstable/src/cluster.c
这里由于篇幅的原因, 主要从数据分片和数据迁移两方面进行详细介绍:
数据分片
Redis cluster 在设计中没有使用一致性哈希 (consistency hashing), 而是使用数据分片(sharding), 引入哈希槽(hash slot) 来实现; 一个 redis cluster 包含 16384(0~16383)个哈希槽, 存储在 redis cluster 中的所有的键都会被映射到这些 slot 中, 集群中的每个键都属于这 16384 个哈希槽的其中一个, 集群使用公式 slot=CRC16(key)/16384 来计算 key 属于哪个槽, 其中 CRC16(key)语句用于计算 key 的 CRC16 校验和
集群中的每个主节点 (Master) 都负责处理 16384 个哈希槽中的一部分, 当集群处于稳定状态时, 每个哈希槽都只由一个主节点进行处理, 每个主节点可以有一个到 N 个从节点(Slave), 当主节点出现宕机或网络断线等不可用时, 从节点能自动提升为主节点进行处理
如上, clusterNode 数据结构中的 slots 和 numslots 属性记录了节点负责处理哪些槽其中, slot 属性是一个二进制位数组 (bitarray), 其长度为 16384/8=2048 Byte, 共包含 16384 个二进制位集群中的 master 节点用 bit(0 和 1) 来标识对于某个槽是否拥有比如, 对于编号为 1 的槽, master 只要判断序列的第二位 (索引从 0 开始) 的值是不是 1 即可, 时间复杂度为 O(1)
集群中所有槽的分配信息都保存在 clusterState 数据结构的 slots 数组中, 程序要检查槽 i 是否已经被分配或者找出处理槽 i 的节点, 只需要访问 clusterState.slots[i]的值即可, 复杂度也为 O(1)clusterState 数据结构如下所示:
查找关系如下图:
数据迁移
数据迁移可以理解为 slot 和 key 的迁移, 这个功能很重要, 极大的方便了集群做线性扩展, 实现平滑的扩容或缩容
那么它是一个怎样的实现过程呢
下面举个例子: 现在要将 Master A 节点中的编号为 123 的 slot 迁移到 Master B 节点中, 在 slot 迁移的中间状态下, slot 123 在 Master A 节点的状态表现为 MIGRATING, 在 Master B 节点的状态表现为 IMPORTING
MIGRATING 状态
这个状态如上图所示是被迁移 slot 在当前所在 Master A 节点中出现的一种状态, 预备迁移 slot 从 Mater A 到 Master B 的时候, 被迁移 slot 的状态首先变为 MIGRATING 状态, 当客户端请求的某个 key 所属的 slot 的状态处于 MIGRATING 状态的时候, 可能会出现以下几种情况:
1)如果 key 存在则成功处理
2)如果 key 不存在, 则返回客户端 ASK, 客户端根据 ASK 首先发送 ASKING 命令到目标节点, 然后发送请求的命令到目标节点
3)当 key 包含多个命令时:
如果都存在则成功处理
如果都不存在, 则返回客户端 ASK
如果一部分存在, 则返回客户端 TRYAGAIN, 通知客户端稍后重试, 这样当所有的 key 都 迁移完毕的时候客户端重试请求的时候回得到 ASK, 然后经过一次重定向就可以获取这批键
此时并不刷新客户端中 node 的映射关系
IMPORTING 状态
这个状态如上图所示是被迁移 slot 在目标 Master B 节点中出现的一种状态, 预备迁移 slot 从 Mater A 到 Master B 的时候, 被迁移 slot 的状态首先变为 IMPORTING 状态在这种状态下的 slot 对客户端的请求可能会有下面几种影响:
1)如果 key 不存在则新建
2)如果 key 不在该节点上, 命令会被 MOVED 重定向, 刷新客户端中 node 的映射关系
如果是 ASKING 命令则命令会被执行, 从而 key 没在被迁移的节点, 已经被迁移到目标节点的情况命令可以被顺利执行
键空间迁移
这是完成数据迁移重要的一步, 键空间迁移是指当满足了 slot 迁移前提的情况下, 通过相关命令将 slot 123 中的键空间从 Master A 节点转移到 Master B 节点, 这个过程由 MIGRATE 命令经过 3 步真正完成数据转移步骤示意如下:
经过上面三步可以完成键空间数据迁移, 然后再将处于 MIGRATING 和 IMPORTING 状态的槽变为常态即可, 从而完成整个重新分片的过程
请您简单介绍下 Redis 的高可用方案, 如果可以, 结合您的实践经验和案例进行分析
根据业务的规模以及 Redis 使用环境的不同, Redis 的高可用方案也比较多这里举一些例子说明一下业界比较常用的一些方案吧需要说明一下的是下面的这些方案不涉及到同城多活或异地多活的场景, 但是部分方案能够做到跨数据中心的灾备
Keepalive + Redis
Redis Sentinel
Twemproxy + Redis Sentinel + Redis
Redis Cluster
Redis Sentinel + Proxy + Zookeeper + Redis
Zookeeper + MySQL + Redis + DNS
Redis 数据库在向着自动化运维的方向发展的过程中, 面临的最大的挑战是什么? 如何克服?
如果不强调最大的话, 我知道有不少的挑战, 哈哈
我想最大的挑战应该是智能化吧现在业界都在追捧 DevOpsAIOps, 那么在 Redis 的自动化运维过程中, 也需要学习行业的先进思想, 结合部门自身的实际稳扎稳打, 逐一突破
首先在智能化实现之前, 我们要尽力实现下面的一些需求:
1)数据库运维自动化平台的建设, 为 RD 和 DBA 提供较全面的自助服务和数据库管理功能
2)工单事件关联任务系统, 一键完成自动安装部署, 添加产品线和报警
3)海量报警智能分类(比如按产品线或按 DBA 分类), 实现部分报警故障自愈 (比如: 从库 readonly 设置内存使用率超过 95% 自动扩容)
4)基于队列分布式批量部署, 可横向扩展, 任务异步调度, 满足大规模部署扩容的需求
5)日志实时展示, 监控数据实时采集, 图形化多维度展示, 满足可视化的需求
6)RedisHA 支持秒级响应, 实现故障无缝切换, 满足高可用的需求
7)缓存弹性扩缩容(利用私有云和公有云, 结合 Docker 容器化技术实现), 满足对热点的快速应对
8)内部开发了各种通用的管理和运维脚本, 化繁为简, 提高工作效率
9)根据历史 / 晚高峰资源的性能指标设置水位线, 和报警阈值, 提供决策支持
10)在 Redis 集群容灾异地多活 (跨数据中心数据同步) 微服务等等方面还需要花很大的力气去建设, 目前依旧比较欠缺
智能化的实现还需要持续的投入和迭代
近几年随着大数据时代的到来, NoSQL 数据库在处理海量数据上表现出越来越多的优势, 请问您如何看待数据库的未来, 会朝着什么样的方向发展?
是的, 这几年从运维的角度看, 明显能感觉到数据体量上的膨胀, 一个实例动不动就几十 G, 一个集群动不动几百 G 几 T, 甚至更多以 Redis 为代表的 NoSQL 数据库在处理这方面的表现还是令人非常满意的它的高性能表现得淋漓尽致, 从微博的业务来看, Redis 实例每天承载着千亿级的写 QPS 万亿级的读 QPS, 数据量 TB 级, 确实没有 Redis, 且不说能不能用关系型数据库存储, 单是硬件成本就几何倍增长了吧
未来, 随着硬件成本的降低, 硬件性能优化的极致, 比如 PCIE25GE 网络的升级, 一定是软硬结合, 会出现更多的 Redis 的相关产品和服务包括收费的 Redis Enterprise,Cloud Redis 等, 也包括开源的 PikaTiDB 等 NewSQL 正如阿里云的同学所说, 数据库终极是九九归一 -- 量子数据库, 一起期待吧
对于初学 Redis 的同学, 您有什么好的学习方法和技巧给他们吗?
首先当然还是需要多看官方文档, 多看看业界大牛的技术博客其次可以买几本书对比着学习下, 目前市面上的相关书籍也就 4,5 本的样子然后主要的还是要多动手, 实践出真知, 在使用的过程中, 还是要结合具体的业务场景, 灵活使用有能力的时候, 看看源码, 了解底层的实现原理最后, 多思考多总结, 好记性不如烂笔头, 每一次踩坑都是一次成长, 遇到解决不了的问题的时候多向业界大牛们请教学习, 平时多关注一些业界相关技术的最新动态
您如何看待 Redis 的未来? 从技术和非技术的多个维度, 您如何看待 Redis 的发展方向
纵观 Redis 的发展, 无独有偶的与互联网的发展浪潮紧紧相随, 从 web1.0 到 web2.0 的转变, 从博客贴吧论坛到社交媒体, 从文本到图文再到短视频的兴起, 从互联网到移动互联网, 从 3G 到 4G 到即将普及的 5G, 从异军突起的新兴产业, 如: 团购电商外卖旅游游戏互联网金融和证券出行和直播等等, 商业模式在不断的改变, 不断的在刷新人们的生活方式
但是在这些变化的背后, 不变的是 Redis 作为基础服务为企业的高可用架构保驾护航, 变化的是 Redis 的使用案例越来越丰富服务体验越来越好在 Redis 的发展过程中, 由于企业需求的多样化, 对 Redis 的要求越来越高, 许多场景 Redis 的功能显得相形见绌, 因此出现了诸如 CodisPikaCounterServiceApsaraCacheCacheCloudsmartClient(Redisson)等产品, 它们是对 Redis 的有益补充
随着 4.0 版本 module 功能的推出, 使得 Redis 拥有更多的想象和发展空间, 在全文索引 (RediSearch),AI(Redis-ML) 云计算大数据物联网人工智能 BlockChain 等领域, 模块化的融合能力将极大的丰富 Redis 的功能, 从而为企业构建更为多元化立体化的数据库使用方式
您还有什么想要分享的吗?
在使用 Redis 的过程中, 还需要保持关注官方的动态, 多看看 github 上的 changelog 和 issue, 因为随着 Redis 的用户群体的增多, 使用场景的复杂化, Redis 自身隐藏的问题或瓶颈也会暴露出来, 这样有助于我们避免踩一些不必要的坑, 及早规避一些风险
不仅仅是 Redis, 学习其他的数据库也是一样的另外, 我们在关注 Redis 本身以外, 还需要关注一些其他的 Redis 的替代产品 (比如: SSDBPikaCodisApsaraCacheTiDB 等),Redis 的周边工具(如: redis-migrate-toolredis-fainaredis-auditredis-rdb-toolsRedisMyAdmin 等) 中间件 (如: twemproxycorvusredis-cerberus) 等如果你想要从事 Redis 的开发, 那么你可能需要关注的更多, 比如各种锁的实现
来源: https://yq.aliyun.com/articles/431747