• Redis哨兵(sentinel)


    前言

    背景:测试环境的redis集群被运维回收,无奈之下只能自己动手,Redis高可用集群架构的搭建。

    原理

    Redis的哨兵(sentinel)系统用于管理多个redis服务器,该系统执行以下三个任务:

    • 监控(Monitoring):哨兵(sentinel)会不断地检查你的Master和Slave是否运作正常。

    • 提醒(Notification):当被监控的某个Redis出现问题时,哨兵(sentinel)可以通过API向管理员或者其他应用程序发送通知。

    • 自动故障迁移(Automatic failover):当一个Master不能正常工作时,哨兵(sentinel)会开始一次自动故障迁移操作,它会将失效Master的其中一个Slave升级为新的Master,并让失效Master的其他Slave改为复制新的Master;当客户端试图连接失效的Master时,集群也会向客户端返回新Master的地址,使得集群可以使用Master代替失效Master,客户端实际获取的链接是哨兵返回的。

    哨兵(sentinel)是一个分布式系统,你可以在一个架构中运行多个哨兵(sentinel)进程,这些进程使用流言协议(gossipprotocols)来接收关于Master是否下线的信息,并使用投票协议(agreement protocols)来决定是否执行自动故障迁移,以及选择哪个Slave作为新的Master。

    每个哨兵(sentinel)会向其它哨兵(sentinel)、master、slave定时发送消息,以确认对方是否”活”着,如果发现对方在指定时间(可配置)内未回应,则暂时认为对方已挂(所谓的”主观认为宕机” Subjective Down,简称sdown).

    若“哨兵群”中的多数sentinel,都报告某一master没响应,系统才认为该master"彻底死亡"(即:客观上的真正down机,Objective Down,简称odown),通过一定的vote算法,从剩下的slave节点中,选一台提升为master,然后自动修改相关配置.

    虽然哨兵(sentinel)释出为一个单独的可执行文件redis-sentinel ,但实际上它只是一个运行在特殊模式下的Redis服务器,你可以在启动一个普通Redis服务器时通过给定--sentinel选项来启动哨兵(sentinel).

    哨兵(sentinel)的一些设计思路和zookeeper非常类似。

    架构图

    下载

    首页地址:http://redis.io/

    最新稳定版下载地址:http://download.redis.io/releases/redis-3.2.9.tar.gz

    # tar -xvf redis-3.2.9.tar.gz
    
    # cd redis-3.2.9
    
    # make install
    
    # make test
    

    命令

    redis-server    -h
    
    Usage: ./redis-server [/path/to/redis.conf] [options]
    
    ./redis-server - (read config from stdin)
    
    ./redis-server -v or --version
    
    ./redis-server -h or --help
    
    ./redis-server --test-memory
    
    Examples:
    
    ./redis-server (run the server with default conf)
    
    ./redis-server /etc/redis/6379.conf
    
    ./redis-server --port 7777
    
    ./redis-server --port 7777 --slaveof 127.0.0.1 8888
    
    ./redis-server /etc/myredis.conf --loglevel verbose
    
    Sentinel mode:
    
    ./redis-server /etc/sentinel.conf --sentinel
    

    配置

    daemonize yes        ###daemon后台运行模式
    
    pidfile /var/run/redis.pid  ###pidfile
    
    port 6379  ###默认6379端口
    
    tcp-backlog 511  ###tcp三次握手等待确认ack最大的队列数
    
    bind 192.168.65.128 127.0.0.1  ###绑定的监听的ip,可同时写多个ip,不写默认监控0.0.0.0
    
    timeout 0  ###关闭空闲客户端,0为disable
    
    tcp-keepalive 0 ###是否开启tcp长连接,定义socket连接timeout时长
    
    loglevel notice  ###定义日志级别为notice(输出必要的日志)
    
    logfile "/var/log/redis/redis.log" ###定义日志输出目录
    
    databases 16  ###允许redis定义的最大的db簇
    
    ###开启rdb并应用如下数据保存策略,aof和rdb可同时启用,aof强烈建议开启
    
    save 900 1
    
    save 300 10
    
    save 60 10000
    
    stop-writes-on-bgsave-error yes  ###有任何问题导致的bgsave失败都停止redis的对外服务
    
    rdbcompression yes  ###rdb写压缩
    
    rdbchecksum yes  ###rdb文件正确性检查
    
    dbfilename dump.rdb  ###rdb文件名称(dump.rdb可任意起)
    
    dir /var/lib/redis/    ###rdb文件写目录
    
    # slaveof     ###如果是slave需要写明master
    
    # masterauth     ###master密码验证(因为redis基于内存,作用不大)
    
    slave-serve-stale-data no  ###如果master宕机,slave是否还正常对外服务no->停止服务
    
    slave-read-only yes    ###salve是否只读(默认只读)
    repl-diskless-sync no  ### Disk-backed 启动新进程写rdb到disk,然后增量传输到salves 方式二:Diskless 直接写salve sockers,而不用写disk,当网络好的时候建议使用,但因为用到的是M/S+哨兵的架构,随时可能会进行主从切换,这个方式暂时不用
    
    repl-diskless-sync-delay 5  ##每5s传输一次diskless开启后生效
    
    repl-ping-slave-period 3  ###slave每3s ping测试master是否存活
    
    repl-timeout 10      ###定义replicationtxuq  timeout时间,这里的时间要大于repl-ping-slave-period里的时间,不然后一直发生low traffic between the master and the slave问题
    
    repl-disable-tcp-nodelay no  ###yes 一条线40milliseconds发送一次数据包,意识着更小的tcp packets和更小的带宽去发送到slave,但在slave会有相应的数据延迟. No,刚相反.一般上我们期望是低延迟,所以最选择no是个不错的选择,但如果在复杂的网络情况或m/s之间有很多中继网络,这里建议修改为yes
    
    slave-priority 100  ###slave优先级别,数字越小优先级别越高,当master宕机时优先选取slave
    
    # min-slaves-to-write 3  ###当最少有3个slave延迟<= 10s时,master才正常提供服务
    
    # min-slaves-max-lag 10  ###当最少有3个slave延迟<= 10s时,master才正常提供服务
    
    maxmemory  1536000000  #1.5G  ###单位 ,redis最大占用内存数,当超过1.5G时redis会根据策略清理内存key
    
    #############6种清理策略
    
    # volatile-lru -> remove the key with an expire set using an LRU algorithm ##推荐使用
    
    # allkeys-lru -> remove any key according to the LRU algorithm
    
    # volatile-random -> remove a random key with an expire set
    
    # allkeys-random -> remove a random key, any key
    
    # volatile-ttl -> remove the key with the nearest expire time (minor TTL)
    
    # noeviction -> don't expire at all, just return an error on write operations
    
    maxmemory-policy volatile-lru  ###使用LRU算法清理过期key
    
    # maxmemory-samples 3  ###LRU算法和TTL算法均为模糊算法,该精确算法redis会选择3个keys选择最少使用的一个key进行删除, 个人不建议使用
    
    appendonly yes  ###aof持久化,增量写disk,比aof慢,但更可靠.企业的默认选择,有的会两者均开启
    
    appendfilename "appendonly.aof"  ###aof文件名
    
    # appendfsync always
    
    appendfsync everysec  ###建议使用该方式
    
    # appendfsync no
    
    no-appendfsync-on-rewrite no  ##建议no, 主要用来缓和redis调用fsync()写数据时间长的问题.当BGSAVE或BGREWRITEAOF被调用期间,fsync()进程将阻止被调用,即相当于
    
    auto-aof-rewrite-percentage 100  ###当文件大小达到64mb的100%大小时开始rewrite aof文件
    
    auto-aof-rewrite-min-size 64mb  ###当文件大小达到64mb的100%大小时开始rewrite aof文件
    
    aof-load-truncated yes  ###当aof文件被损坏时,redis将返回错误并退出
    
    lua-time-limit 5000  ###LUA scripts最大执行时间,单位(milliseconds),超出后返回查询错误并写日志
    
    slowlog-log-slower-than 10000 ###单位microseconds(毫秒) 1000000 microseconds=1 s,记录执行时长超过10000 microseconds的执行命令
    
    slowlog-max-len 128  ###最大长度为128
    
    latency-monitor-threshold 0  ###监控相关,关闭就好
    
    notify-keyspace-events ""  ###空表示关闭,发布相关key的操作记录到所有 client
    
    ######下面是高级设置,个人保持为默认配置
    
    hash-max-ziplist-entries 512
    
    hash-max-ziplist-value 64
    
    list-max-ziplist-entries 512
    
    list-max-ziplist-value 64
    
    set-max-intset-entries 512
    
    zset-max-ziplist-entries 128
    
    zset-max-ziplist-value 64
    
    hll-sparse-max-bytes 3000
    
    activerehashing yes
    
    client-output-buffer-limit normal 0 0 0
    
    client-output-buffer-limit slave 256mb 64mb 60
    
    client-output-buffer-limit pubsub 32mb 8mb 60
    
    hz 10
    
    aof-rewrite-incremental-fsync yes
    

    启动

    # redis-server /etc/redis/redis.conf
    

    查看

    # redis-cli -h Mrds
    
    Mrds:6379> info
    
    # Server
    
    redis_version:2.8.19    ###redis版本号
    
    redis_git_sha1:00000000  ###git SHA1
    
    redis_git_dirty:0  ###git dirty flag
    
    redis_build_id:78796c63e58b72dc
    
    redis_mode:standalone  ###redis运行模式
    
    os:Linux 2.6.32-431.el6.x86_64 x86_64  ###os版本号
    
    arch_bits:64  ###64位架构
    
    multiplexing_api:epoll  ###调用epoll算法
    
    gcc_version:4.4.7  ###gcc版本号
    
    process_id:25899  ###服务器进程PID
    
    run_id:eae356ac1098c13b68f2b00fd7e1c9f93b1c6a2c  ###Redis的随机标识符(用于sentinel和集群)
    
    tcp_port:6379  ###Redis监听的端口号
    
    uptime_in_seconds:6419 ###Redis运行时长(s为单位)
    
    uptime_in_days:0  ###Redis运行时长(天为单位)
    
    hz:10
    
    lru_clock:10737922  ###以分钟为单位的自增时钟,用于LRU管理
    
    config_file:/etc/redis/redis.conf  ###redis配置文件
    
    # Clients
    
    connected_clients:1  ###已连接客户端的数量(不包括通过从属服务器连接的客户端)
    
    client_longest_output_list:0  ###当前连接的客户端中最长的输出列表
    
    client_biggest_input_buf:0  ###当前连接的客户端中最大的输出缓存
    
    blocked_clients:0  ###正在等待阻塞命令(BLPOP、BRPOP、BRPOPLPUSH)的客户端的数量 需监控
    
    # Memory
    
    used_memory:2281560  ###由 Redis 分配器分配的内存总量,以字节(byte)为单位
    
    used_memory_human:2.18M  ###以更友好的格式输出redis占用的内存
    
    used_memory_rss:2699264  ###从操作系统的角度,返回 Redis 已分配的内存总量(俗称常驻集大小)。这个值和 top 、 ps 等命令的输出一致
    
    used_memory_peak:22141272  ### Redis 的内存消耗峰值(以字节为单位)
    
    used_memory_peak_human:21.12M  ###以更友好的格式输出redis峰值内存占用
    
    used_memory_lua:35840  ###LUA引擎所使用的内存大小
    
    mem_fragmentation_ratio:1.18  ###used_memory_rss 和 used_memory 之间的比率
    
    mem_allocator:jemalloc-3.6.0
    
    ###在理想情况下, used_memory_rss 的值应该只比 used_memory 稍微高一点儿。当 rss > used ,且两者的值相差较大时,表示存在(内部或外部的)内存碎片。内存碎片的比率可以通过 mem_fragmentation_ratio 的值看出。
    
    当 used > rss 时,表示 Redis 的部分内存被操作系统换出到交换空间了,在这种情况下,操作可能会产生明显的延迟。
    
    # Persistence
    
    loading:0  ###记录服务器是否正在载入持久化文件
    
    rdb_changes_since_last_save:0  ###距离最近一次成功创建持久化文件之后,经过了多少秒
    
    rdb_bgsave_in_progress:0  ###记录了服务器是否正在创建 RDB 文件
    
    rdb_last_save_time:1420023749  ###最近一次成功创建 RDB 文件的 UNIX 时间戳
    
    rdb_last_bgsave_status:ok  ###最近一次创建 RDB 文件的结果是成功还是失败
    
    rdb_last_bgsave_time_sec:0  ###最近一次创建 RDB 文件耗费的秒数
    
    rdb_current_bgsave_time_sec:-1  ###如果服务器正在创建 RDB 文件,那么这个域记录的就是当前的创建操作已经耗费的秒数
    
    aof_enabled:1  ###AOF 是否处于打开状态
    
    aof_rewrite_in_progress:0  ###服务器是否正在创建 AOF 文件
    
    aof_rewrite_scheduled:0  ###RDB 文件创建完毕之后,是否需要执行预约的 AOF 重写操作
    
    aof_last_rewrite_time_sec:-1  ###最近一次创建 AOF 文件耗费的时长
    
    aof_current_rewrite_time_sec:-1  ###如果服务器正在创建 AOF 文件,那么这个域记录的就是当前的创建操作已经耗费的秒数
    
    aof_last_bgrewrite_status:ok  ###最近一次创建 AOF 文件的结果是成功还是失败
    
    aof_last_write_status:ok
    
    aof_current_size:176265  ###AOF 文件目前的大小
    
    aof_base_size:176265  ###服务器启动时或者 AOF 重写最近一次执行之后,AOF 文件的大小
    
    aof_pending_rewrite:0  ###是否有 AOF 重写操作在等待 RDB 文件创建完毕之后执行
    
    aof_buffer_length:0  ###AOF 缓冲区的大小
    
    aof_rewrite_buffer_length:0  ###AOF 重写缓冲区的大小
    
    aof_pending_bio_fsync:0  ###后台 I/O 队列里面,等待执行的 fsync 调用数量
    
    aof_delayed_fsync:0    ###被延迟的 fsync 调用数量
    
    # Stats
    
    total_connections_received:8466  ###服务器已接受的连接请求数量
    
    total_commands_processed:900668  ###服务器已执行的命令数量
    
    instantaneous_ops_per_sec:1  ###服务器每秒钟执行的命令数量
    
    total_net_input_bytes:82724170
    
    total_net_output_bytes:39509080
    
    instantaneous_input_kbps:0.07
    
    instantaneous_output_kbps:0.02
    
    rejected_connections:0  ###因为最大客户端数量限制而被拒绝的连接请求数量
    
    sync_full:2
    
    sync_partial_ok:0
    
    sync_partial_err:0
    
    expired_keys:0  ###因为过期而被自动删除的数据库键数量
    
    evicted_keys:0  ###因为最大内存容量限制而被驱逐(evict)的键数量。
    
    keyspace_hits:0  ###查找数据库键成功的次数。
    
    keyspace_misses:500000  ###查找数据库键失败的次数。
    
    pubsub_channels:0  ###目前被订阅的频道数量
    
    pubsub_patterns:0  ###目前被订阅的模式数量
    
    latest_fork_usec:402  ###最近一次 fork() 操作耗费的毫秒数
    
    # Replication
    
    role:master  ###如果当前服务器没有在复制任何其他服务器,那么这个域的值就是 master ;否则的话,这个域的值就是 slave 。注意,在创建复制链的时候,一个从服务器也可能是另一个服务器的主服务器
    
    connected_slaves:2  ###2个slaves
    
    slave0:ip=192.168.65.130,port=6379,state=online,offset=1639,lag=1
    
    slave1:ip=192.168.65.129,port=6379,state=online,offset=1639,lag=0
    
    master_repl_offset:1639
    
    repl_backlog_active:1
    
    repl_backlog_size:1048576
    
    repl_backlog_first_byte_offset:2
    
    repl_backlog_histlen:1638
    
    # CPU
    
    used_cpu_sys:41.87  ###Redis 服务器耗费的系统 CPU
    
    used_cpu_user:17.82  ###Redis 服务器耗费的用户 CPU
    
    used_cpu_sys_children:0.01  ###后台进程耗费的系统 CPU
    
    used_cpu_user_children:0.01  ###后台进程耗费的用户 CPU
    
    # Keyspace
    
    db0:keys=3101,expires=0,avg_ttl=0  ###keyspace 部分记录了数据库相关的统计信息,比如数据库的键数量、数据库已经被删除的过期键数量等。对于每个数据库,这个部分都会添加一行以下格式的信息
    

    Sentinel(哨兵)配置

    vi sentinel.conf
    

    启动前:

    port 26379
    
    dir "/var/lib/redis/tmp"  ###定义目录存放
    
    sentinel auth-passmymaster vhreal   ##密码
    
    sentinel monitor mymaster 192.168.65.128 6379 2    ###监控mymaster(可自定义-但只能包括A-z 0-9和”._-”)
    
    sentinel down-after-milliseconds mymaster 30000  ###mymaster多久不响应认为SDOWN
    
    sentinel parallel-syncs mymaster 1  ###指定最大同时同步新maser配置的salve数量
    
    sentinel failover-timeout mymaster 180000  ###2次failover切换时间
    

    启动后(redis.con配置文件完全由sentinel控制,请不要再随意手动改动):

    port 26379
    
    dir "/var/lib/redis/tmp"
    
    sentinel monitor mymaster 192.168.65.128 6379 2
    
    sentinel config-epoch mymaster 18  ###确认mymater SDOWN时长
    
    sentinel leader-epoch mymaster 18  ###同时一时间最多18个slave可同时更新配置,建议数字不要太大,以免影响正常对外提供服务
    
    sentinel known-slave mymaster 192.168.65.129 6379  ###已知的slave
    
    sentinel known-slave mymaster 192.168.65.130 6379  ###已知的slave
    
    sentinel known-sentinel mymaster 192.168.65.130 26379 be964e6330ee1eaa9a6b5a97417e866448c0ae40    ###已知slave的唯一id
    
    sentinel known-sentinel mymaster 192.168.65.129 26379 3e468037d5dda0bbd86adc3e47b29c04f2afe9e6  ###已知slave的唯一id
    
    sentinel current-epoch 18  ####当前可同时同步的salve数最大同步阀值
    

    开启sentinel

    开启sentinel后会后redis.conf会由sentinel进行管理

    # redis-server /etc/redis/sentinel.conf --sentinel &> /var/log/redis/sentinel.log &
    

    常用命令

    redis-cli
    
    redis-server
    
    auth
    
    set key value
    
    get key
    

    Q&A

    Redis主从配置异常解决:Error condition on socket for SYNC: Connection refused

    Redis主从集群时,从服务器上的redis日志报错:

    32677:S08Feb16:14:38.947*ConnectingtoMASTER172.168.10.70:637932677:S08Feb16:14:38.948*MASTER<->SLAVEsyncstarted32677:S08Feb16:14:38.948#ErrorconditiononsocketforSYNC:Connectionrefused32677:S08Feb16:14:39.950*ConnectingtoMASTER172.168.10.70:637932677:S08Feb16:14:39.950*MASTER<->SLAVEsyncstarted32677:S08Feb16:14:39.950#ErrorconditiononsocketforSYNC:Connectionrefused32677:S08Feb16:14:40.952*ConnectingtoMASTER172.168.10.70:637932677:S08Feb16:14:40.952*MASTER<->SLAVEsyncstarted32677:S08Feb16:14:40.953#ErrorconditiononsocketforSYNC:Connectionrefused
    
    • 解决方案:

    在redis主服务器上的redis.conf中修改bind字段,将

    bind 127.0.0.1
    
    修改为
    
    bind 0.0.0.0
    

    又或者直接注释掉bind字段

    # bind 127.0.0.1
    
    • 原因:

    如果redis主服务器绑定了127.0.0.1,那么跨服务器IP的访问就会失败,从服务器用IP和端口访问主的时候,主服务器发现本机6379端口绑在了127.0.0.1上,也就是只能本机才能访问,外部请求会被过滤,这是Linux的网络安全策略管理的。如果bind的IP地址是172.168.10.70,那么本机通过localhost和127.0.0.1、或者直接输入命令redis-cli登录本机redis也就会失败了。只能加上本机ip才能访问到。

    所以,在研发、测试环境可以考虑bind 0.0.0.0,线上生产环境建议绑定IP地址。

    (DENIED Redis is running in protected mode)

    Java程序中使用JedisSentinelPool建立redis连接池

    
    Set sentinels = new HashSet();
    
    sentinels.add("172.17.16.7:26379");
    
    sentinels.add("172.17.16.8:26379");
    
    sentinels.add("172.17.16.9:26379");
    
    JedisSentinelPool sentinelPool = new JedisSentinelPool("mymaster", sentinels, "123456");
    

    报错:

    DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to    clients.......
    

    使用redis-cli -h 127.0.0.1 -p 26379连接sentinel可以执行命令,而使用redis-cli -h 172.17.16.7 -p 26379连接sentinel执行命令则会报同上的错误。

    查遍了网上没有找到相关的问题分析和解决的案例,所以只能自己猜测和排查,初步怀疑是通过172.17.16.7访问sentinel时受限。

    由于此错误和redis server的protect-mode为yes的访问错误颇为相似,官方在redis.conf的注释说明中有protected-mode这一配置项,但sentinel.conf的注释中完全没有提到过该配置项,我很疑惑,但还是尝试在sentinel.conf中加入

    protected-mode no
    

    之后保存并重新启动sentinel,之后用Java程序建立连接池,没有报错,且可以对redis server进行数据处理,问题解决。

    定位问题原因* 根据原因思考问题解决方案* 实践验证方案有效性* 提交验证结果
  • 相关阅读:
    A* Pathfinding for Beginners
    OpenGL Draw Mesh
    CentOS6.5下安装、配置SSH
    Ubuntu18.04下搭建LAMP环境
    滚动合集
    关闭页面触发事件
    在table中tr的display:block在firefox下显示布局错乱问题
    sharepoint添加模板及删除模板
    常用正则表达式
    javascript对象的property和prototype是这样一种关系
  • 原文地址:https://www.cnblogs.com/jimoliunian/p/12967024.html
Copyright © 2020-2023  润新知