一站式-满足您的所有-解决方案-需求-Redis-Redis (一站式满足您的资金需求让您用款无忧)
Introduction
Redis is an efficient in-memory database designed to store data invarious formats, such as strings, lists, sets, sorted sets, and hashes. It's commonly used for caching, real-time processing, and other applications that require fast data access.Key-Value Store
Redis operates as a key-value store, where data is accessed based on unique keys. These keys can be any string, and their corresponding values can be any of the supported data types.Advantages
Redis offers several advantages:- Simplicity and Deployability: Redis has a straightforward architecture, making it easy to deploy andmanage.
- Cost-Effectiveness: It's budget-friendly, especially when used as a cache, as it eliminates the need for backup nodes.
- High Performance: Redis delivers exceptional performance due to its in-memory nature and single-threaded architecture.
Disadvantages
However, there are also some limitations:- Data Reliability: Redis does not guarantee data persistence, so it's not suitable for applications that require reliable data storage.
- Data Loss: When used as a cache, data loss can occur when processes restart. Backup nodes can address high availability but not cache warm-up.
- Performance Limitations: Redis's performance is limited by the capabilities of a single CPU core, making it less effective for complex operations and intensive computation.
Alternatives
For scenarios where complex queries, pagination, or sorting are required, consider using a relational database management system (RDBMS) or a NoSQL database with support for secondary indexes. Memcached can also bean alternative for caching applications with simpler operations.Conclusion
Redis is a powerful tool for caching and other applications that demand fast data retrieval. While it offers high performance and cost-effectiveness, it's crucial to be aware of its limitations, such as data reliability and performance constraints. By understanding its strengths and weaknesses, you can effectively leverage Redis to improve the efficiency of your applications.Additional Resources
- Redis Official Website
- Redis Getting Started
- Redis Cookbook
如何实现高可用的 redis 集群
Redis 因具有丰富的数据结构和超高的性能以及简单的协议,使其能够很好的作为数据库的上游缓存层。 但在大规模的 Redis 使用过程中,会受限于多个方面:单机内存有限、带宽压力、单点问题、不能动态扩容等。 基于以上, Redis 集群方案显得尤为重要。 通常有 3 个途径:官方 Redis Cluster ;通过 Proxy 分片;客户端分片 (Smart Client) 。 以上三种方案各有利弊。 Redis Cluster( 官方 ) :虽然正式版发布已经有一年多的时间,但还缺乏最佳实践;对协议进行了较大修改,导致主流客户端也并非都已支持,部分支持的客户端也没有经过大规模生产环境的验证;无中心化设计使整个系统高度耦合,导致很难对业务进行无痛的升级。 Proxy :现在很多主流的 Redis 集群都会使用 Proxy 方式,例如早已开源的 Codis 。 这种方案有很多优点,因为支持原声 redis 协议,所以客户端不需要升级,对业务比较友好。 并且升级相对平滑,可以起多个 Proxy 后,逐个进行升级。 但是缺点是,因为会多一次跳转,平均会有 30% 左右的性能开销。 而且因为原生客户端是无法一次绑定多个 Proxy ,连接的 Proxy 如果挂了还是需要人工参与。 除非类似 Smart Client 一样封装原有客户端,支持重连到其他 Proxy ,但这也就带来了客户端分片方式的一些缺点。 并且虽然 Proxy 可以使用多个,并且可以动态增加 proxy 增加性能,但是所有客户端都是共用所有 proxy ,那么一些异常的服务有可能影响到其他服务。 为每个服务独立搭建 proxy ,也会给部署带来额外的工作。 而我们选择了第三种方案,客户端分片 (Smart Client) 。 客户端分片相比 Proxy 拥有更好的性能,及更低的延迟。 当然也有缺点,就是升级需要重启客户端,而且我们需要维护多个语言的版本,但我们更爱高性能。 下面我们来介绍一下我们的Redis集群:概貌:如图0所示,我们的 Redis 集群一共由四个角色组成:Zookeeper :保存所有 redis 集群的实例地址, redis 实例按照约定在特定路径写入自身地址,客户端根据这个约定查找 redis 实例地址,进行读写。 Redis 实例:我们修改了 redis 源码,当 redis 启动或主从切换时,按照约定自动把地址写到 zookeeper 特定路径上。 Sentinel : redis 自带的主从切换工具,我们通过 sentinel 实现集群高可用。 客户端( Smart Client ):客户端通过约定查找 redis 实例在 ZooKeeper 中写入的地址。 并且根据集群的 group 数,进行一致性哈希计算,确定 key 唯一落入的 group ,随后对这个 group 的主库进行操作。 客户端会在Z ooKeeper 设置监视,当某个 group 的主库发生变化时,Z ooKeeper 会主动通知客户端,客户端会更新对应 group 的最新主库。 我们的Redis 集群是以业务为单位进行划分的,不同业务使用不同集群(即业务和集群是一对一关系)。 一个 Redis 集群会由多个 group 组成 ( 一个 group 由一个主从对 redis 实例组成 ) 。 即 group 越多,可以部署在更多的机器上,可利用的内存、带宽也会更多。 在图0中,这个业务使用的 redis 集群由 2 个 group 组成,每个 group 由一对主从实例组成。 Failover 如图1所示,当 redis 启动时,会 把自己的 IP:Port 写入到 ZooKeeper 中。 其中的 主实例模式启动时会在 /redis/ 业务名 / 组名 永久节点写入自己的IP:Port (如果节点不存在则创建)。 由 主模式 变成 从模式 时,会创建 /redis/ 业务名 / 组名 /slaves/ip:port 临时节 点,并写入自己的IP:Port (如果相同节点已经存在,则先删除,再创建)。 而从实例 模式 启动时会创建 /redis/ 业务名 / 组名 /slaves/ip:port 临时节点,并写入自己的 ip:port (如果相同节点已经存在,则先删除,再创建)。 由 从模式 变成 主模式 时,先删除 /redis/ 业务名 / 组名 /slaves/ip:port 临时节点,并在 /redis/ 业务名 / 组名 永久节点写入自己的IP:Port 。 ZooKeeper 会一直保存当前有效的 主从实例 IP:Port 信息。 至于主从自动切换过程,使用 redis 自带的 sentinel 实现,现设置为超过 30s 主 server 无响应,则由 sentinel 进行主从实例的切换,切换后就会触发以主、从实例通过以上提到的一系列动作,从而完成最终的切换。 而客户端侧通过给定业务名下的所有 groupName 进行一致性哈希计算,确定 key 落入哪个组。 客户端启动时,会从 ZooKeeper 获取指定业务名下所有 group 的 主从 IP:Port ,并在 ZooKeeper 中设置监视(监视的作用是当 ZooKeeper 的节点发生变化时,会主动通知客户端)。 若客户端从 Zookeeper 收到节点变化通知,会重新获取最新的 主从 I:Port ,并重新设置监视( ZooKeeper 监视是一次性的)。 通过此方法,客户端可以实时获知当前可访问最新的 主从 IP:Port 信息。 因为我们的所有 redis 实例信息都按照约定保存在 ZooKeeper 上,所以不需要针对每个实例部署监控,我们编写了一个可以自动通过 ZooKeeper 获取所有 redis 实例信息,并且监控 cpu 、 qps 、内存、主从延迟、主从切换、连接数等的工具。 发展:现在 redis 集群在某些业务内存需求超过预期很多后,无法通过动态扩容进行扩展。 所以我们正在做动态扩容的支持。 原先的客户端我们是通过一致性哈希进行 key 的路由策略,但这种方式在动态扩容时会略显复杂,所以我们决定采用实现起来相对简单的预分片方式。 一致性哈希的好处是可以无限扩容,而预分片则不是。 预分片时我们会在初始化阶段指定一个集群的所有分片数量,这个数量一旦指定就不能再做改变,这个预分片数量就是后续可以扩容到最大的 redis 实例数。 假设预分片 128 个 slot ,每个实例 10G 也可以达到 TB 级别的集群,对于未来数据增长很大的集群我们可以预分片 1024 ,基本可以满足所有大容量内存需求了。 原先我们的 redis 集群有四种角色, Smart Client, redis , sentinel , ZooKeeper 。 为了支持动态扩容,我们增加了一个角色, redis_cluster_manager (以下简称 manager ),用于管理 redis 集群。 主要工作是初始化集群(即预分片),增加实例后负责修改Z ooKeeper 状态,待客户端做好准备后迁移数据到新增实例上。 为了尽量减少数据迁移期间对现性能带来的影响,我们每次只会迁移一个分片的数据,待迁移完成,再进行下一个分片的迁移。 如图2所示相比原先的方案,多了 slots 、M anager Lock 、 clients 、M igrating Clients 节点。 Slots: 所有分片会把自身信息写入到 slots 节点下面。 Manager 在初始化集群时,根据设置的分片数,以及集群下的 group 数,进行预分片操作,把所有分片均匀分配给已有 group 。 分片的信息由一个 json 串组成,记录有分片的状态 (stats) ,当前拥有此分片的 group(src) ,需要迁移到的 group(dst) 。 分片的状态一共有三种: online 、 pre_migrate 、 migrating 。 Online 指这个分片处于正常状态,这时 dst 是空值,客户端根据 src 的 group 进行读写。 Pre_migrate 是指这个分片被 manager 标记为需要迁移,此时 dst 仍然为空, manager 在等所有 client 都已经准备就绪,因为 ZooKeeper 回掉所有客户端有时间差,所以如果某些 client 没有准备就绪的时候 manager 进行了数据迁移,那么就会有数据丢失。 Migrating 是 manager 确认了所有客户端都已经做好迁移准备后,在 dst 写入此分片需要迁移的目标 group 。 待迁移完成,会在 src 写入目标 group_name , dst 设为空, stats 设为 online 。 Manager Lock: 因为我们是每次只允许迁移一个 slot ,所以不允许超过一个 manager 操作一个集群。 所以 manager 在操作集群前,会在M anager Lock 下注册临时节点,代表这个集群已经有 manager 在操作了,这样其他 manager 想要操作这个集群时就会自动退出。 Clients 和M igrating Clients 是为了让 manager 知道客户端是否已经准备就绪的节点。 客户端通过 uid 代表自己,格式是 客户端语言 _ 主机名 _pid 。 当集群没有进行迁移,即所有分片都是 online 的时候,客户端会在 clients 下创建 uid 的临时节点。 当某个 slot 从 online 变成 pre_migrate 后,客户端会删除 clients 下的 uid 临时节点,然后在M igrating Clients 创建 uid 临时节点。 注意,因为需要保证数据不丢失,从 pre_migrate 到 migrating 期间,这个 slot 是被锁定的,即所有对这个 slot 的读写都会被阻塞。 所以 mananger 会最多等待 10s ,确认所有客户端都已经切换到准备就绪状态,如果发现某个客户端一直未准备就绪,那么 mananger 会放弃此次迁移,把 slot 状态由 pre_migrate 改为 online 。 如果客户端发现 slot 状态由 pre_migrate 变成 online 了,那么会删除 migrating_clients 下的 uid 节点,在 clients 下重新创建 uid 节点。 还需要注意的一点是,有可能一个客户刚启动,并且正在往 clients 下创建 uid 节点,但是因为网络延迟还没创建完成,导致 manager 未确认到这个 client 是否准备就绪,所以 mananger 把 slot 改为 pre_migrate 后会等待 1s 再确认所有客户端是否准备就绪。 如果 Manager 看到 clients 下已经没有客户端的话(都已经准备就绪),会把 slot 状态改为 migrating 。 Slot 变成 migrating 后,锁定也随之解除, manager 会遍历 src group 的数据,把对应 slot 的数据迁移到 dst group 里。 客户端在 migrating 期间如果有读写 migrating slot 的 key ,那么客户端会先把这个 key 从 src group 迁移到 dst group ,然后再做读写操作。 即这期间客户端性能会有所下降。 这也是为什么每次只迁移一个 slot 的原因。 这样即使只有 128 个分片的集群,在迁移期间受到性能影响的 key 也只有 1/128 ,是可以接受的。 Manager 发现已经把 slot 已经迁移完毕了,会在 src 写入目标 group_name , dst 设为空, stats 设为 online 。 客户端也删除 migrating_clients 下的 uid ,在 clients 下创建 uid 节点。
redis集群方案有哪些
Redis数据量日益增大,而且使用的公司越来越多,不仅用于做缓存,同时趋向于存储这块,这样必促使集群的发展,各个公司也在收集适合自己的集群方案,目前行业用的比较多的是下面几种集群架构,大部分都是采用分片技术,解决单实例内存增大带来的一系列问题。 本篇文章简单介绍五种方案:官方cluster方案twemproxy代理方案哨兵模式codis客户端分片官方cluser方案从redis 3.0版本开始支持redis-cluster集群,redis-cluster采用无中心结构,每个节点保存数据和整个集群状态,每个节点都和其他节点连接。 redis-cluster是一种服务端分片技术。 redis-cluster架构图redis-cluster特点:每个节点都和n-1个节点通信,这被称为集群总线(cluster bus)。 它们使用特殊的端口号,即对外服务端口号加。 所以要维护好这个集群的每个节点信息,不然会导致整个集群不可用,其内部采用特殊的二进制协议优化传输速度和带宽。 redis-cluster把所有的物理节点映射到[0,]slot(槽)上,cluster负责维护node--slot--value。 集群预分好个桶,当需要在redis集群中插入数据时,根据CRC16(KEY) mod 的值,决定将一个key放到哪个桶中。 客户端与redis节点直连,不需要连接集群所有的节点,连接集群中任何一个可用节点即可。 脚本(rub语言)为集群的管理工具,比如自动添加节点,规划槽位,迁移数据等一系列操作。 节点的fail是通过集群中超过半数的节点检测失效时才生效。 整个cluster被看做是一个整体,客户端可连接任意一个节点进行操作,当客户端操作的key没有分配在该节点上时,redis会返回转向指令,指向正确的节点。 为了增加集群的可访问性,官方推荐的方案是将node配置成主从结构,即一个master主节点,挂n个slave从节点。 如果主节点失效,redis cluster会根据选举算法从slave节点中选择一个上升为master节点,整个集群继续对外提供服务。 twemproxy代理方案twemproxy代理架构图:Redis代理中间件twemproxy是一种利用中间件做分片的技术。 twemproxy处于客户端和服务器的中间,将客户端发来的请求,进行一定的处理后(sharding),再转发给后端真正的redis服务器。 也就是说,客户端不直接访问redis服务器,而是通过twemproxy代理中间件间接访问。 降低了客户端直连后端服务器的连接数量,并且支持服务器集群水平扩展。 twemproxy中间件的内部处理是无状态的,它本身可以很轻松地集群,这样可以避免单点压力或故障。 twemproxy又称nutcracker,起源于推特系统中redis、memcached集群的轻量级代理。 Github源码地址()从上面架构图看到twemproxy是一个单点,很容易对其造成很大的压力,所以通常会结合keepalived来实现twemproy的高可用。 这时,通常只有一台twemproxy在工作,另外一台处于备机,当一台挂掉以后,vip自动漂移,备机接替工作。 关于keepalived的用法可自行网上查阅资料。 哨兵模式Sentinel哨兵Sentinel(哨兵)是Redis的高可用性解决方案:由一个或多个Sentinel实例组成的Sentinel系统可以监视任意多个主服务器以及这些主服务器下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器。 例如:在Server1掉线后:升级Server2为新的主服务器:Sentinel的工作方式每个Sentinel以每秒钟一次的频率向它所知的Master、Slave以及其他Sentinel实例发送一个PING命令。 如果一个实例距离最后一次有效回复PING命令的时间超过down-after-milliseconds选项所指定的值,则这个实例会被Sentinel标记为主观下线。 如果一个Master被标记为主观下线,则正在监视这个Master的所有Sentinel要以每秒一次的频率确认Master的确进入了主观下线状态。 当有足够数量的Sentinel(大于等于配置文件指定的值)在指定的时间范围内确认Master的确进入了主观下线状态,则Master会被标记为客观下线。 在一般情况下,每个Sentinel会以每10秒一次的频率向它所知的所有Master、Slave发送INFO命令。 当Master被Sentinel标记为客观下线时,Sentinel向下线的Master的所有Slave发送INFO命令的频率会从10秒一次改为每秒一次。 若没有足够数量的Sentinel同意Master已经下线,Master的客观下线状态就会被移除。 若Master重新向Sentinel的PING命令返回有效值,Master的主观下线状态就会被移除。 codiscodis是一个分布式的Redis解决方案,由豌豆荚开源,对于上层的应用来说,连接codis proxy和连接原生的redis server没什么明显的区别,上层应用可以像使用单机的redis一样使用,codis底层会处理请求的转发,不停机的数据迁移等工作,所有后边的事情,对于前面的客户端来说是透明的,可以简单的认为后边连接的是一个内存无限大的redis服务。 客户端分片分区的逻辑在客户端实现,由客户端自己选择请求到哪个节点。 方案可参考一致性哈希,这种方案通常适用于用户对客户端的行为有完全控制能力的场景。 总结:没有最好的方案,只有最合适的方案。 更多Redis相关技术文章,请访问Redis教程栏目进行学习!
免责声明:本文转载或采集自网络,版权归原作者所有。本网站刊发此文旨在传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及版权、内容等问题,请联系本网,我们将在第一时间删除。同时,本网站不对所刊发内容的准确性、真实性、完整性、及时性、原创性等进行保证,请读者仅作参考,并请自行核实相关内容。对于因使用或依赖本文内容所产生的任何直接或间接损失,本网站不承担任何责任。