• redis 学习笔记三


    一、redis 复制

    数据库复制指的是发生在不同数据库实例之间,单向的信息传播的行为,通常由被复制方和复制方组成,被复制方和复制方之间建立网络连接,复制方式通常为被复制方主动将数据发送到复制方,复制方接收到数据存储在当前实例,最终目的是为了保证双方的数据一致、同步。

    Redis复制方式:

    一种是主(master)-从(slave)模式,一种是从(slave)-从(slave)模式,因此Redis的复制拓扑图会丰富一些,可以像星型拓扑,也可以像个有向无环:

    通过配置多个Redis实例独立运行、定向复制,形成Redis集群,master负责写、slave负责读。

    复制优点

    通过配置多个Redis实例,数据备份在不同的实例上,主库专注写请求,从库负责读请求,这样的好处主要体现在下面几个方面:

    1、高可用性

    在一个Redis集群中,如果master宕机,slave可以介入并取代master的位置,因此对于整个Redis服务来说不至于提供不了服务,这样使得整个Redis服务足够安全。

    2、高性能

    在一个Redis集群中,master负责写请求,slave负责读请求,这么做一方面通过将读请求分散到其他机器从而大大减少了master服务器的压力,另一方面slave专注于提供读服务从而提高了响应和读取速度。

    3、水平扩展性

    通过增加slave机器可以横向(水平)扩展Redis服务的整个查询服务的能力。

    复制缺点

    复制提供了高可用性的解决方案,但同时引入了分布式计算的复杂度问题,认为有两个核心问题:

    1. 数据一致性问题,如何保证master服务器写入的数据能够及时同步到slave机器上。

    2. 编程复杂,如何在客户端提供读写分离的实现方案,通过客户端实现将读写请求分别路由到master和slave实例上。

    上面两个问题,尤其是第一个问题是Redis服务实现一直在演变,致力于解决的一个问题。

    复制实时性和数据一致性矛盾

    Redis提供了提高数据一致性的解决方案,一致性程度的增加虽然使得我能够更信任数据,但是更好的一致性方案通常伴随着性能的损失,从而减少了吞吐量和服务能力。然而我们希望系统的性能达到最优,则必须要牺牲一致性的程度,因此Redis的复制实时性和数据一致性是存在矛盾的。

    Redis复制工作过程:

    1. slave向master发送sync命令。

    2. master开启子进程来讲dataset写入rdb文件,同时将子进程完成之前接收到的写命令缓存起来。

    3. 子进程写完,父进程得知,开始将RDB文件发送给slave。

    4. master发送完RDB文件,将缓存的命令也发给slave。

    5. master增量的把写命令发给slave。

     二、redis集群

    1、Redis Sharding集群,客户端分片

    客户端分片是把分片的逻辑放在Redis客户端实现,通过Redis客户端预先定义好的路由规则,把对Key的访问转发到不同的Redis实例中,最后把返回结果汇集

    优点:

    • 所有的逻辑都是可控的,不依赖于第三方分布式中间件。开发人员清楚怎么实现分片、路由的规则,不用担心踩坑。
    • 这种分片性能比代理式更好(因为少了分发环节),分发压力在客户端,无服务端压力增加

    缺点:

    • 静态的分片方案,需要增加或者减少Redis实例的数量,需要手工调整分片的程序。

    • 不能平滑地水平扩容,扩容/缩容时,必须手动调整分片程序,出现故障不能自动转移,难以运维

    2、Twemproxy

    优点:

    • 运维成本低。业务方不用关心后端 Redis 实例,跟操作 Redis 一样。Proxy 的逻辑和存储的逻辑是隔离的
    • 支持无效Redis实例的自动删除。
    • Twemproxy与Redis实例保持连接,减少了客户端与Redis实例的连接数。

    缺点:

    • a. 代理层多了一次转发,性能有所损耗

    • b. 进行扩容/缩容时候,部分数据可能会失效,需要手动进行迁移,对运维要求较高,而且难以做到平滑的扩缩容

    • c. 出现故障,不能自动转移,运维性很差

    3、Codis

    优点:

    • 支持平滑增加(减少)Redis Server Group(Redis实例),能安全、透明地迁移数据,这也是Codis 有别于Twemproxy等静态分布式 Redis 解决方案的地方

    缺点:

    • 需要更改redis的源代码(为了加入slot信息) 以及代理实现本身会有的问题

    codis改进了一下redis缺点:

    1 redis数据量太大的话(22G以上),他的处理性能就开始下降;

    2 无法区分冷热数据,内存浪费严重;

    3 RDB Block住整个服务;

    4 写操作太频繁,AOF刷盘太多,很容易rewrite

    4、Redis Cluster

    优点:

    •  无中心节点

    •  数据按照 Slot 存储分布在多个 Redis 实例上

    •  平滑的进行扩容/缩容节点

    •  自动故障转移(节点之间通过 Gossip 协议交换状态信息,进行投票机制完成 Slave 到 Master 角色的提升)

    •  降低运维成本,提高了系统的可扩展性和高可用性

    缺点:

    •  严重依赖外部 Redis-Trib
    •  缺乏监控管理
    •  需要依赖 Smart Client(连接维护, 缓存路由表, MultiOp 和 Pipeline 支持)
    •  Failover 节点的检测过慢,不如“中心节点 ZooKeeper”及时
    •  Gossip 消息的开销
    •  无法根据统计区分冷热数据
    •  Slave“冷备”,不能缓解读压力

    实际项目中该如何选型呢?

    方案 1 使用nginx开发(OpenResty方式)

    原因如下

    a. 单 Master 多 Work 模式,每个 Work 跟 Redis 一样都是单进程单线程模式,并且都是基

    于 Epoll 事件驱动的模式。

    b. Nginx 采用了异步非阻塞的方式来处理请求,高效的异步框架。

    c. 内存占用少,有自己的一套内存池管理方式,。将大量小内存的申请聚集到一块,能够比

    Malloc 更快。减少内存碎片,防止内存泄漏。减少内存管理复杂度。

    d. 为了提高 Nginx 的访问速度,Nginx 使用了自己的一套连接池。

    e. 最重要的是支持自定义模块开发。

    f. 业界内,对于 Nginx,Redis 的口碑可称得上两大神器。性能也就不用说了。

    方案 2 codis (豌豆荚采用的基于代理的redis集群方案)

    参考codis官方文档https://github.com/CodisLabs/codis

    Codis是一整套缓存解决方案,包含高可用、数据分片、监控、动态扩态 etc.。

    走的是 Apps->代理->redis cluster,一定规模后基本都采用这种方式。

    方案3 自己独立开发redis智能客户端

    主要实现redis slots管理,failover,一致性hash功能。

    三、sentinel

    Redis-Sentinel是Redis官方推荐的高可用性(HA)解决方案,当用Redis做Master-slave的高可用方案时,假如master宕机了,Redis本身(包括它的很多客户端)都没有实现自动进行主备切换,而Redis-sentinel本身也是一个独立运行的进程,它能监控多个master-slave集群,发现master宕机后能进行自懂切换。

    它的主要功能有以下几点

    • 不时地监控redis是否按照预期良好地运行;

    • 如果发现某个redis节点运行出现状况,能够通知另外一个进程(例如它的客户端);

    • 能够进行自动切换。当一个master节点不可用时,能够选举出master的多个slave(如果有超过一个slave的话)中的一个来作为新的master,其它的slave节点会将它所追随的master的地址改为被提升为master的slave的新地址。

    Sentinel支持集群

    很显然,只使用单个sentinel进程来监控redis集群是不可靠的,当sentinel进程宕掉后(sentinel本身也有单点问题,single-point-of-failure)整个集群系统将无法按照预期的方式运行。所以有必要将sentinel集群,这样有几个好处:

    • 即使有一些sentinel进程宕掉了,依然可以进行redis集群的主备切换;
    • 如果只有一个sentinel进程,如果这个进程运行出错,或者是网络堵塞,那么将无法实现redis集群的主备切换(单点问题);
    • 如果有多个sentinel,redis的客户端可以随意地连接任意一个sentinel来获得关于redis集群中的信息。

     Redis Sentinel节点推荐3个以上。相比keepalived+redis实现高可用更靠谱,且keepalived+redis还不能管理多个实例

    原理:

    ①sentinel集群通过给定的配置文件发现master,启动时会监控master。通过向master发送info信息获得该服务器下面的所有从服务器。
    ②sentinel集群通过命令连接向被监视的主从服务器发送hello信息(每秒一次),该信息包括sentinel本身的ip、端口、id等内容,以此来向其他sentinel宣告自己的存在。
    ③sentinel集群通过订阅连接接收其他sentinel发送的hello信息,以此来发现监视同一个主服务器的其他sentinel;集群之间会互相创建命令连接用于通信,因为已经有主从服务器作为发送和接收hello信息的中介,sentinel之间不会创建订阅连接。
    ④sentinel集群使用ping命令来检测实例的状态,如果在指定的时间内(down-after-milliseconds)没有回复或则返回错误的回复,那么该实例被判为下线。 
    ⑤当failover主备切换被触发后,failover并不会马上进行,还需要sentinel中的大多数sentinel授权后才可以进行failover,即进行failover的sentinel会去获得指定quorum个的sentinel的授权,成功后进入ODOWN状态。如在5个sentinel中配置了2个quorum,等到2个sentinel认为master死了就执行failover。
    ⑥sentinel向选为master的slave发送SLAVEOF NO ONE命令,选择slave的条件是sentinel首先会根据slaves的优先级来进行排序,优先级越小排名越靠前。如果优先级相同,则查看复制的下标,哪个从master接收的复制数据多,哪个就靠前。如果优先级和下标都相同,就选择进程ID较小的。
    ⑦sentinel被授权后,它将会获得宕掉的master的一份最新配置版本号(config-epoch),当failover执行结束以后,这个版本号将会被用于最新的配置,通过广播形式通知其它sentinel,其它的sentinel则更新对应master的配置。

    ①到③是自动发现机制:

    • 10秒一次的频率,向被监视的master发送info命令,根据回复获取master当前信息。
    • 1秒一次的频率,向所有redis服务器、包含sentinel在内发送PING命令,通过回复判断服务器是否在线。
    • 2秒一次的频率,通过向所有被监视的master,slave服务器发送当前sentinel,master信息的消息。

    ④是检测机制,⑤和⑥是failover机制,⑦是更新配置机制。

    注意:因为redis采用的是异步复制,没有办法避免数据的丢失。但可以通过以下配置来使得数据不会丢失:min-slaves-to-write 1 、 min-slaves-max-lag 10。一个redis无论是master还是slave,都必须在配置中指定一个slave优先级。要注意到master也是有可能通过failover变成slave的。如果一个redis的slave优先级配置为0,那么它将永远不会被选为master,但是它依然会从master哪里复制数据。

  • 相关阅读:
    算法复杂度(Algorithmic Complexity)
    Javascript引用指针
    树(Trees)
    什么是数据挖掘(What is Data Mining?)
    Javascript的声明
    Javascript继承(下)——干嘛要继承
    Linux 中使用 OpenCV
    Java集合类(Java Collections classes)
    哈希查找(Hashing)
    Javascript继承(上)——对象构建
  • 原文地址:https://www.cnblogs.com/qiuhong10/p/7552317.html
Copyright © 2020-2023  润新知