• Redis——分析主从复制,哨兵,cluster,分区,代理 (转)


    转自: https://www.it610.com/article/1297347757631152128.htm

    转自: https://www.it610.com/article/1297347757631152128.htm

    转自: https://www.it610.com/article/1297347757631152128.htm

    redis单实例可能会有啥问题

    1. 单点故障
    2. 容量有限
    3. 并发压力

    单实例问题的解决方案:AKF

    https://www.jianshu.com/p/d08d0c14810f

    • X轴: 部署多节点,每个节点都有全量的数据,可以主从备份,读写分离.解决单点故障的问题,同时也缓解一些压力,无法解决容量的问题;
    • Y轴: 从业务功能上分库,比如用户信息独立一个库,商品信息独立一个库,使用多个实例; 每个Y轴上的节点可以有自己的X轴;
    • Z轴: 按优先级,比如地域划分,有点类似于MySQL的横向分表;比如商品信息太多了,将编号1-1w的商品放入一个库,1w-2w放入另一个库;
      Y轴和Z轴的思想就是从业务上分隔数据,让一个库中的数据少一些,从而把压力平均到多个实例上;Y和Z轴有点客户端sharding的感觉
      Redis(五)redis的高可用理论推导,主从复制,哨兵,cluster,分区,代理,实操twemproxy/Predixy/cluster_第1张图片

    多实例的数据一致性的问题

    很多事情都是有两面性的,AKF会带来数据一致性的问题.

    以主从备份为例,一个主节点,两个备份节点;
    (这里说的就是主从模式,但是现在好像不让说slave这个词了,下面说的备份节点其实就是以前的slave节点)

    • 强一致性(破坏可用性)
      所有节点阻塞,直到数据全部一致;
      假设其中一个备份节点挂掉了,或者网络延迟,就会导致整个服务不可用,破坏可用性.
      这个成本太高,几乎不会这么做;
      反过来想,为什么要一变多,就是为了保证可用性
    • 容忍数据丢失一部分
      主节点写入数据后 马上返回成功响应;然后异步方式,把数据写到备份节点,同步数据
      假设备份节点挂了,就可能丢掉一部分数据
    • 最终一致性
      同步数据时引入消息中间件,比如Kafka
      主节点写入数据后 马上返回成功响应;然后把消息(同步阻塞)写入Kafka,备份节点从Kafka中读取信息,从而同步数据
      这要求Kafka高可用,响应速度够快
      这样即使备份节点挂掉了,最终仍会从Kafka中读取数据.
      其实这里有个小问题:
      当客户端读取数据时,假设备份节点还没来及消费同步数据,就有可能取到错误的数据

    CAP

    http://www.ruanyifeng.com/blog/2018/07/cap.html
    Consistency一致性,Availability可用性,Partition Tolerance分区容忍性 这仨条件不能同时满足,最多同时满足两点.

    先看 Partition tolerance,中文叫做"分区容错"。
    大多数分布式系统都分布在多个子网络。每个子网络就叫做一个区(partition)。分区容错的意思是,区间通信可能失败。比如,一台服务器放在中国,另一台服务器放在美国,这就是两个区,它们之间可能无法通信。

    一般来说,分区容错无法避免,因此可以认为 CAP 的 P 总是成立。CAP 定理告诉我们,剩下的 C 和 A 无法同时做到。

    一致性和可用性,为什么不可能同时成立?答案很简单,因为可能通信失败(即出现分区容错)。
    假设两个节点G1,G2,向G1写后,向G2读
    如果保证 G2 的一致性,那么 G1 必须在写操作时,锁定 G2 的读操作和写操作。只有数据同步后,才能重新开放读写。锁定期间,G2 不能读写,没有可用性不。
    如果保证 G2 的可用性,那么势必不能锁定 G2,所以一致性不成立。

    一般来说,网页的更新不是特别强调一致性。短时期内,一些用户拿到老版本,另一些用户拿到新版本,问题不会特别大。当然,所有人最终都会看到新版本。所以,这个场合就是可用性高于一致性。

    主从复制的模式,我们需要让master节点高可用;
    当master节点挂掉后,从replica节点中选举一个作为新的master节点,也就是自动故障转移;
    由程序去实现监控并故障转移,只要是程序就有单点故障问题,所以需要一变多的集群;
    假设有3个监控节点,这又涉及到数据一致性的问题,所以就以"大多数"(过半)的观点为准,因为有可能是监控节点自己有网络问题

    为啥要"大多数",“过半”:
    如果只看一个节点,统计不够准确,有可能不同的节点有不同的观点,因为网络分区的问题,就可能请求到不一样的数据,发生脑裂;
    如果看"大多数",只要过半的节点的观点是一致的,就认为这是对的结果,这就是分区容忍性.

    n台机器组成集群的话,"过半"的节点就是n/2 + 1, 即允许 n/2 - 1 台机器挂掉;所以一般n是个基数
    3台和4台组成的集群,都只允许一台挂掉,但是4台机器中挂掉1台的几率要大一些.

    复制(Redis Replication)

    http://redis.cn/topics/replication.html

    help slaveof 会提示,5.X开始,用replicaof代替
    所以,help replicaof
    常用命令:

    • replicaof ip port 追随某个master节点
    • replicaof no one 谁也不追,自己当master节点

    可以直接在从节点客户端中, replicaof ip port 指定主节点 (更多时候是通过配置文件)
    指定主节点后,首次同步时,会先把自己的数据删掉,然后从主节点拉取RDB重新加载;
    默认从节点不能写数据,只能读.

    如果主节点挂了,可以人工的从replica节点中选一个作为master节点,然后其他节点重新追随新的master节点,实现故障转移.

    如果从节点挂了,又启动回复时,是怎么恢复数据呢,重新从主节点拉取RDB吗?
    如果从节点没有开启AOF,使用RDB,则不会从主节点全量拉取RDB,因为本地的RDB文件记录了masterID,可以增量同步
    如果从节点开启了AOF,那么会重新拉取RDB,全量同步;因为AOF中的RDB部分,没有记录masterID,不知道出于啥考虑

    master节点可以知道有哪些replica节点

    配置文件

    • replicaof 指定主节点
    • masterauth 主节点的密码
    • replica-serve-stale-data yes/no 当从节点和主节点丢失联系,或者正在同步数据时,是否可以继续提读服务,默认是yes,可能读到老数据
    • replica-read-only yes 从节点是否只读,默认yes
    • repl-diskless-sync no 当有新的从节点,或者从节点重新连接时,不能增量复制了,需要一次全量同步(full synchronization),通过传输RDB实现;传输RDB时可以先写到磁盘上,然后再传输(yes);或者不用磁盘,直接从内存中传输(no);默认是no,即使用磁盘.
    • repl-backlog-size 1mb 主从之间日常会增量的同步数据,redis内部维护一个buffer队列,从节点通过上次更新的offset判断,只拉取最新的增量修改;这个参数指定队列的大小.如果buffer太小,从节点找不到上次的offset了,就会全量同步
    • min-replicas-to-write 3 最少有几个节点在线,否则就拒绝写操作,有点"同步阻塞" 强一致性的感觉;默认注释掉
    • min-replicas-max-lag 10 从节点的心跳间隔大于这个数时,就认为不在线了,单位是秒;默认注释掉

    高可用性(High Availability) 哨兵Sentinel

    http://redis.cn/topics/sentinel.html
    哨兵负责监控,提醒,自动故障转移;
    一套哨兵可以监控多套主从集群

    可以通过reisid-sentinel启动哨兵
    redis-sentinel 和 sentinel.conf 在redist源码src目录可以找到
    配置文件,重点看这个:
    sentinel monitor mymaster 127.0.0.1 6379 2 监控主节点,并指定2票通过

    哨兵其实是一个特殊的redis-server,可以启动redis-server时--sentinel 来启动哨兵

    哨兵只需要知道master节点信息即可,从master里可以知道从节点信息,通过发布订阅(pubsub)来发现其他哨兵
    可以通过PSUBSCRIBE * 订阅所有channel来观察一下

    哨兵通过监听主获取其他机器信息,然后通过发布订阅获取其他哨兵
    在这里插入图片描述

    分区

    http://redis.cn/topics/partitioning.html

    客户端的sharding方式(缓存)

    modula,random,ketama 参考https://github.com/twitter/twemproxy
    这三种都不适合做数据库,适合做缓存

    按模块/业务拆分

    很多人可能不认为这是分区,但是我觉得从宏观上来看,这也是sharding的思想
    把不同的业务存在不同的库中,从而减少每个库的压力(AKF中的Y轴)

    将数据 hash + 取模 (modula)

    弊端:取模的数是固定,去觉得当下redis的实例数,不易扩展

    生产者random lpush,消费者rpop (类似kafka的partition) (random)

    客户端a作为生产者,往N个redis实例中随机lpush数据;
    客户端b作为消费者,从N个redis实例中不停rpop取数据
    此时,这个list的key就相当于kafka的topic;只是Kafka是基于磁盘的,可以重复消费,redis不行

    一致性hash,规划一个哈希环 (只适合用于缓存) (ketama)

    假设刚开始有两个机器作为redis节点;
    我们规划一个哈希环,设这个环的offset范围是0~232
    把两个节点分别hash,几位n1hash,n2hash;
    当有数据进来时,对数据hash,得到的值和n1hash,n2hash比较,和谁的差小就存在哪里;
    这就是最简单的哈希环.

    当新增一个节点node3时,可能会有一部分的数据不能命中,这时可以去数据库里面查一次,再放入node3;
    其他节点有重复数据也无所谓,这种方式本就适合于缓存,一般都会用LRU回收掉

    为了防止数据倾斜,很多数据集中在一个节点的情况,可以设置很多虚拟节点;
    即使只有两个物理节点,让他们各自的ip加上一定数字 映射出多台机器;从而使两台物理节点在环上可以交替负责,很大概率防止数据倾斜.
    Redis(五)redis的高可用理论推导,主从复制,哨兵,cluster,分区,代理,实操twemproxy/Predixy/cluster_第2张图片

    客户端sharding的缺点

    每个客户端都要连接所有的redis-server
    假设有很多个客户端,将对server造成很大压力
    Redis(五)redis的高可用理论推导,主从复制,哨兵,cluster,分区,代理,实操twemproxy/Predixy/cluster_第3张图片

    所以就想,能不能像nginx那样,通过反向代理搞定:
    其实这相当于时把sharding逻辑算法,从客户端迁移到了代理层,代理层实现modula,random,ketama
    代理层时无状态的,满足了无状态才方便下面增加代理层节点
    如果考虑代理性能,代理也可以做个集群
    Redis(五)redis的高可用理论推导,主从复制,哨兵,cluster,分区,代理,实操twemproxy/Predixy/cluster_第4张图片

    或者加入LVS,keepalived:
    无论server端多复杂,对于客户端来说,只要请求那个LVS即可
    Redis(五)redis的高可用理论推导,主从复制,哨兵,cluster,分区,代理,实操twemproxy/Predixy/cluster_第5张图片
    但是这样的话,复杂度就太大了;
    不要因为技术而技术.遵循KISS原则,满足需求的情况下,越简单越好.

    cluster

    https://redis.io/topics/cluster-tutorial
    这是官方的解决方案

    预分区
    这个有点类似于虚拟节点,举个例子:
    刚开始一共两个redis节点,但是预分出10个分区(槽位),平均分给两个节点;
    当新添加一个节点时,从这两个节点中划分一些槽位给新节点,进行增量的数据传输(数据迁移),即可快速的完成扩展工作.
    数据迁移的同时也支持修改,类似于主从备份的首次全量同步,和后续的增量buffer同步

    cluster属于"无主"模式,也没有代理
    客户端连接的时候,可以连接cluster中任意一个server节点,每个节点都知道各个槽位和其他节点的映射关系
    节点收到请求后,会做个hash运算,找到对应的槽位,然后从映射关系找到对应的节点;
    如果数据不在本节点上,给客户端返回一个"重定向"的响应,由客户端再次请求对应的节点

    数据分治,分开后,有些东西很难实现:聚合操作,事务
    redis为了追求速度,没有移动数据的功能,所以没有实现这些玩意;(redis理念:计算向数据移动)
    如果一个事务需要的数据都在一个节点上,那就可以正常运行;所以可以通过hash tag解决这些问题
    客户端通过给key设置hash tag,然后server端通过hash tag 做hash运算,相同的hash tag一定会落在同一个节点上.

    实操

    https://blog.csdn.net/rebaic/article/details/76384028
    无论是为了解决redis的高可用问题、还是为了可扩展性、或者是为了维护方便,用一款redis代理都是上佳的选择。在github上有众多开源的redis代理,其中最流行的有这几个:(貌似predixy表现最好,但是作者比较神秘)

    • predixy : https://github.com/joyieldInc/predixy
    • twemproxy : https://github.com/twitter/twemproxy
    • codis
    • redis-cerberus
      Redis(五)redis的高可用理论推导,主从复制,哨兵,cluster,分区,代理,实操twemproxy/Predixy/cluster_第6张图片

    twemproxy

    按照github的readme即可,https://github.com/twitter/twemproxy

    这里注意有几个坑:
    autoreconf -fvi && ./configure needs automake and libtool to be installed
    需要先安装automake 和 libtool ,直接yum install 即可

    然后执行autoreconf -fvi可能会提示你autoreconf 版本太低,需要618以上版本;
    autoreconf是属于autoconf的命令,yum search autoconf发现最高到autoconf213.noarch,这就需要更换yum镜像了
    从阿里云镜像上找到Epel 镜像,按提示操作后,yum clean all
    yum search autoreconf 后发现多了个autoconf268,然后yum install autoconf268
    执行autoreconf -fvi时 把autoreconf替换为autoreconf268

    然后编译完成后,发现scrips下有个nutcracker.init,这就是启动脚本, 把它拷贝到/etc/init.d/twemproxy
    然后 chmod +x /etc/init.d/twemproxy
    然后准备启动需要的配置文件:
    查看启动脚本,它默认读取/etc/nutcracker/nutcracker.yml,
    我们就创建个文件夹 mkdir /etc/nutcracker
    然后进入源码目录的conf目录,把配置文件复制过去 cp ./nutcracker.yml /etc/nutcracker/

    准备可执行程序,默认prog=“nutcracker”,所以我们把编译后的可执行程序放入环境变量目录
    进入编译后的源码目录/src,cp nutcracker /usr/bin

    然后修改配置文件,vi /etc/nutcracker/nutcracker.yml (修改前做个备份),我们配置连接自己的6379 和 6380

    然后启动它,service twemproxy start
    然后客户端连接代理的端口 redis-cli -p 22121 ,随机写一些数据,代理会把数据分配到两个实例上
    代理层因为数据分治了,不支持keys * 和 事务(watch,multi)
    然后直接连接6379和6380,看看怎么分配的

    Predixy

    https://github.com/joyieldInc/predixy/blob/master/README_CN.md
    编译需要C++11 compiler,centOS6.X上比较麻烦
    可以直接使用他编译好的 https://github.com/joyieldInc/predixy/releases

    predixy支持Redis Sentinel和Redis Cluster来使用redis,一个配置里这两种形式只能出现一种。
    哨兵模式中,
    SentinelServerPool P{
    Sentinels {
    }
    Group xxx {
    }
    }
    一套Sentinel可以监控多套主从的,多套出从就要分多个Group;Group的名要和Sentinel监控的master逻辑名一致
    Predixy可以 将数据,根据指定算法 分发到各个Group中
    Predixy的事务只在单Group下支持

    改好配置文件后,启动: ./predixy …/conf/predixy.conf

    然后客户端连接predixy代理 redis-cli 7617
    set {xx}k1 v1
    set {xx}k2 v1
    会把这俩分发到同一个Group中,但是只在单Group下支持事务

    cluster

    https://redis.io/topics/cluster-tutorial
    cd {redis源码目录}/utils/create-cluster,
    这里有个脚本create-cluster和README
    create-cluster脚本默认NODES=6,REPLICAS=1 即三套主从,每套一个replica节点
    直接./create-cluster start
    ./create-cluster create 自动分槽位和建立主从关系,这个会在单机上分配,可以做实验用

    启动redis-cli时,如果直接redis-cli -p 30001,
    然后set k1 v1会提示 (error) MOVED 12706 127.0.01:30003 让我们换到30003的节点上做操作

    可以redis-cli -c -p 30001 (-c cluster模式),然后set k1 v1就没问题了,会自动跳转
    这时可以watch,multi等操作,但是如果执行的操作不在一套主从上,exec时会报错
    这事可以使用hash-tag, set {oo}k1 v1,set {oo}k2 v2,可以保证k1 k2在一套主从上,这时事务就不会报错了

    实验完毕后,可以./create-cluster stop , ./create-cluster clean

    生产中不会用./create-cluster create自动分配,因为都是分布在不同机器上的,所以可以在./create-cluster start后,手动分配,redis-cli --cluster help查看帮助命令
    redis-cli --cluster create ip:port ip:port ip:port… ip:port --cluster-replicas 1
    create前需要启动我们需要的redis-server,使用这个脚本可以不修改配置文件.
    还可以 add-node/del-node 添加/删除节点,
    redis-cli --cluster reshard ip:port , 新加节点后,从一个或多个或所有M节点中, 分一部分槽位给另一个M节点;不能控制具体哪个槽位;
    redis-cli --cluster info ip:port 查看一下各M节点的槽位分配情况
    redis-cli --cluster check ip:port 查看槽位分配详情,和个节点的ID
    rebalance,

    目前应该是需要手动添加节点,分配槽位

    目前对cluster最有好感,毕竟是官方的解决方案,而且更好的支持事务.

    cluster配置文件

    如果不想使用create-cluster 脚本的话(start),也可以开启cluster配置文件后,和普通redis-server一样启动.

      • cluster-enabled yes
      • cluster-config-file nodes.conf
      • cluster-node-timeout 5000
  • 相关阅读:
    SignalR 聊天室实例详解(服务器端推送版)
    一种解决图片防盗链的方法
    python3基础-数学运算
    测试开发之路
    页面加载时让其显示笼罩层与加载等待图片
    在SQL SERVER中获取表中的第二条数据
    html+js 的一些小问题
    数据库连接错误问题
    ObjectStateManager 中已存在具有同一键的对象。ObjectStateManager 无法跟踪具有相同键的多个对象。
    正则表达式实例
  • 原文地址:https://www.cnblogs.com/xingchong/p/14752600.html
Copyright © 2020-2023  润新知