一、介绍 1.1、简介 什么是redis集群： 由于数据量过大，单个Master复制集难以承担，因此需要对多个复制集进行集群，形成水平扩展每个复制集只负责存储整个数据集的一部分，这就是Redis的集群，其作用是提供在多个Redis节点间共享数据的程序集。 功能： redis集群支持多个master，每个master又可以挂在多个slave。具有读写分离、数据高可用的效果。 由于集群自带了哨兵的故障转移机制，内置了高可用的支持，所以使用集群无需再去使用哨兵功能。 客户端与redis的节点连接，不再需要连接集群中所有的节点，只需要任意连接集群中的一个可用节点即可。 槽位slot负责分配到各个物理服务节点，由对应的集群来负责维护节点，插槽和数据之间的关系。 Redis 集群的数据分片： Redis 集群没有使用一致性hash，而是引入哈希槽的概念。Redis 集群有16384个哈希槽，每个key通过CRC16校验后对16384取模来决定放置哪个槽，集群的每个节点负责部分hash槽，举个例子，比如当前集群有3个节点，那么: 分片是什么： 使用Redis集群时我们会将存储的数据分散到多台redis机器上，这称为分片。简言之，集群中的每个Redis实例都被认为是整个数据的一个分片。 如何找到给定key的分片： 为了找到给定key的分片，我们对key进行CRC16(key)算法处理并通过对总分片数量取模。然后，使用确定性哈希函数，这意味着 给定的key将多次始终映射到同一个分片，我们可以推断将来读取特定key的位置。 1.2、分片与槽位slot的优势 最大优势，方便扩缩容和数据分派查找： 这种结构很容易添加或者删除节点,比如如果我想新添加个节点D，我需要从节点 A,B,C中得部分槽到D上，如果我想移除节点A，需要将A中的槽移到B和C节点上，然后将没有任何槽的A节点从集群中移除即可，由于从一个节点将哈希槽移动到另一个节点并不会停止服务，所以无论添加删除或者改变某个节点的哈希槽的数量都不会造成集群不可用的状态。 1.3、为什redis集群的最大槽数时16384个 正常的心跳数据包带有节点的完整配置，可以用幂等方式用旧的节点替换旧节点，以便更新旧的配置。 这意味着它们包含原始节点的插槽配置，该节点使用2k的空间和16k的插槽，但是会使用8k的空间（使用65k的插槽）。 同时，由于其他设计折衷，Redis集群不太可能扩展到1000个以上的主节点。 因此16k处于正确的范围内，以确保每个主机具有足够的插槽，最多可容纳1000个矩阵，但数量足够少，可以轻松地将插槽配置作为原始位图传播。请注意，在小型群集中，位图将难以压缩，因为当N较小时，位图将设置的slot / N位占设置位的很大百分比。 (1)如果槽位为65536，发送心跳信息的消息头达8k，发送的心跳包过于庞大。 在消息头中最占空间的是myslots[CLUSTER_SLOTS/8]。 当槽位为65536时，这块的大小是: 65536÷8÷1024=8kb 在消息头中最占空间的是myslots[CLUSTER_SLOTS/8]。 当槽位为16384时，这块的大小是: 16384÷8÷1024=2kb 因为每秒钟，redis节点需要发送一定数量的ping消息作为心跳包，如果槽位为65536，这个ping消息的消息头太大了，浪费带宽。 (2)redis的集群主节点数量基本不可能超过1000个。 集群节点越多，心跳包的消息体内携带的数据越多。如果节点过1000个，也会导致网络拥堵。因此redis作者不建议redis cluster节点数量超过1000个。 那么，对于节点数在1000以内的redis cluster集群，16384个槽位够用了。没有必要拓展到65536个。 (3)槽位越小，节点少的情况下，压缩比高，容易传输 Redis主节点的配置信息中它所负责的哈希槽是通过一张bitmap的形式来保存的，在传输过程中会对bitmap进行压缩，但是如果bitmap的填充率slots / N很高的话(N表示节点数)，bitmap的压缩率就很低。 如果节点数很少，而哈希槽数量很多的话，bitmap的压缩率就很低。 1.4、槽位映射的发展 第一阶段：哈希取余分区 2亿条记录就是2亿个Kv，我们单机不行必须要分布式多机，假设有3台机器构成一个集群，用户每次读写操作都是根据公式hash(key)% N个机器台数，计算出哈希值，用来决定数据映射到哪一个节点上。 优点: 简单粗暴，直接有效，只需要预估好数据规划好节点，例如3台、8台、10台，就能保证一段时间的数据支撑。使用Hash算法让固定的-到同一台服务器上，这样每台服务器固定处理一部分请求(并维护这些请求的信息)，起到负载均衡+分而治之的作用。 缺点: 原来规划好的节点，进行扩容或者缩容就比较麻烦了额，不管扩缩，每次数据变动导致节点有变动，映射关系需要重新进行计算，在用定不变时没有问题，如果需要弹性扩容或故障停机的情况下，原来的取模公式就会发生变化:Hash(key)/3会变成Hash(key)/?。此时地址算的结果将发生很大变化，根据公式获取的服务器也会变得不可控。某个redis机器宕机了，由于台数数量变化，会导致hash取余全部数据重新洗牌。 第二阶段：一致性哈希算法分区 为了在节点数目发生改变时尽可能少的迁移数据 将所有的存储节点排列在收尾相接的Hash环上，每个key在计算Hash后会顺时针找到临近的存储节点存放。 而当有节点加入或退出时仅影响该节点在Hash环上顺时针相邻的后续节点。 优点： 加入和删除节点只影响哈希环中顺时针方向的相邻的节点，对其他节点无影响 缺点： 数据的分布和节点的位置有关，因为这些节点不是均匀的分布在哈希环上的，所以数据在进行存储时达不到均匀分布的效果。 第三阶段：哈希槽分区 1、为什么出现 致性哈希算法的数据倾斜问题 哈希槽实质就是一个数组，数组[0,2^14-1]形成hash slot空间。 2、能干什么 解决均匀分配的问题，在数据和节点之间又加入了一层，把这层称为哈希槽(slot) ，用于管理数据和节点之间的关系，现在就相当于节点上放的是槽，槽里放的是数据。 槽解决的是粒度问题，相当于把粒度变大了，这样便于数据移动。哈希解决的是映射问题，使用key的哈希值来计算所在的槽，便于数据分配 3、多少个hash槽 一个集群只能有16384个槽，编号0-16383(0-2^14-1)。这些槽会分配给集群中的所有主节点，分配策略没有要求。集群会记录节点和槽的对应关系，解决了节点和槽的关系后，接下来就需要对key求哈希值，然后对16384取模，余数是几kev就落入对应的槽里。HASH SLOT=CRC16(key) mod 16384。以槽为单位移动数据，因为槽的数目是固定的，处理起来比较容易，这样数据移动问题就解决了。 Redis集群中内置了16384个哈希槽，redis会根据节点数量大致均等的将哈希槽映射到不同的节点。当需要在 Redis集群中放置一个key-value时，redis先对key使用crc16算法算出一个结果然后用结果对16384求余数[CRC16(key)% 16384]，这样每个key都会对应一个编号在 0-16383之间的哈希槽，也就是映射到某个节点上。如下代码，key之A、B在Node2，key之C落在Node3上。 二、配置集群 前置条件： 三台虚拟机，各自新建：mkdir-p /myredis/cluster 配置6个独立redis服务，配置文件展示： bind 0.0.0.0 daemonize yes protected-mode no port 6381 logfile "/myredis/cluster/cluster6381.log" pidfile /myredis/cluster6381.pid dir /myredis/cluster dbfilename dump6381.rdb appendonly yes appendfilename "appendonly6381.aof" requirepass 111111 masterauth 111111 cluster-enabled yes cluster-config-file nodes-6381.conf cluster-node-timeout 5000 配置如上，记得修改端口。 遇到的报错： [root@192 cluster]# redis-server /myredis/cluster/redis-6381.conf *** FATAL CONFIG FILE ERROR (Redis 7.0.0) *** replicaof directive not allowed in cluster mode 哨兵在配置文件中追加了replicaof相关的内容，将哨兵追加的内容删除后重新启动。 三、构建集群 [root@192 cluster]# redis-cli -a 111111 --cluster create --cluster-replicas 1 192.168.1.11:6381 192.168.1.11:6382 192.168.1.12:6383 192.168.1.12:6384 192.168.1.13:6385 192.168.1.13:6386 # 1输入命令 Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. >>> Performing hash slots allocation on 6 nodes... Master[0] -> Slots 0 - 5460 Master[1] -> Slots 5461 - 10922 Master[2] -> Slots 10923 - 16383 Adding replica 192.168.1.12:6384 to 192.168.1.11:6381 Adding replica 192.168.1.13:6386 to 192.168.1.12:6383 Adding replica 192.168.1.11:6382 to 192.168.1.13:6385 M: 491bb2df7fa39bafd917f7aaa0a409e19e41b07f 192.168.1.11:6381 slots:[0-5460] (5461 slots) master S: cc9a9f6bad23314263e2b89e4beede4fc59c3ef3 192.168.1.11:6382 replicates 95d8800931e38739a85d6face5296d719a8d5bfa M: 3075d51754554aa421ee23ccbd8e263c0d5c4f0e 192.168.1.12:6383 slots:[5461-10922] (5462 slots) master S: 4a60743d7b067dfd03c6a0d4403c88ce173abb1c 192.168.1.12:6384 replicates 491bb2df7fa39bafd917f7aaa0a409e19e41b07f M: 95d8800931e38739a85d6face5296d719a8d5bfa 192.168.1.13:6385 slots:[10923-16383] (5461 slots) master S: 458cf2edf6cc3005cee4fc3aa93278efa86637ec 192.168.1.13:6386 replicates 3075d51754554aa421ee23ccbd8e263c0d5c4f0e Can I set the above configuration? (type 'yes' to accept): yes #2输入yes确认 >>> Nodes configuration updated >>> Assign a different config epoch to each node >>> Sending CLUSTER MEET messages to join the cluster Waiting for the cluster to join >>> Performing Cluster Check (using node 192.168.1.11:6381) M: 491bb2df7fa39bafd917f7aaa0a409e19e41b07f 192.168.1.11:6381 slots:[0-5460] (5461 slots) master 1 additional replica(s) S: 458cf2edf6cc3005cee4fc3aa93278efa86637ec 192.168.1.13:6386 slots: (0 slots) slave replicates 3075d51754554aa421ee23ccbd8e263c0d5c4f0e S: cc9a9f6bad23314263e2b89e4beede4fc59c3ef3 192.168.1.11:6382 slots: (0 slots) slave replicates 95d8800931e38739a85d6face5296d719a8d5bfa M: 95d8800931e38739a85d6face5296d719a8d5bfa 192.168.1.13:6385 slots:[10923-16383] (5461 slots) master 1 additional replica(s) S: 4a60743d7b067dfd03c6a0d4403c88ce173abb1c 192.168.1.12:6384 slots: (0 slots) slave replicates 491bb2df7fa39bafd917f7aaa0a409e19e41b07f M: 3075d51754554aa421ee23ccbd8e263c0d5c4f0e 192.168.1.12:6383 slots:[5461-10922] (5462 slots) master 1 additional replica(s) [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. ##3到这里构建成功。三主三从 [root@192 cluster]# 1638个槽位分别对应哪几个主机 四、场景演示 127.0.0.1:6381> cluster keyslot k1 # 查看“k1”这个key对应的槽位 (integer) 12706 # 12706对应的是6385这台主机 在6381上set k1 v1 127.0.0.1:6381> set k1 v1 (error) MOVED 12706 192.168.1.13:6385 ###报错 127.0.0.1:6381> 报错原因：需要路由到位 如何解决：连接redis时增加-c参数，优化路由 [root@192 cluster]# redis-cli -a 111111 -p 6381 -c ###连接时添加-c优化路由 Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. 127.0.0.1:6381> set k1 v1 # set成功 -> Redirected to slot [12706] located at 192.168.1.13:6385 OK 4.1、容错测试：6381这台master挂了，对应的slave是否会变成master 1、查看关系 127.0.0.1:6381> info replication # 查看关系 # Replication role:master connected_slaves:1 slave0:ip=192.168.1.12,port=6384,state=online,offset=17286,lag=0 #6384为6381的slave master_failover_state:no-failover master_replid:4d3c3673de89c3c84a199d59c70ae6cf245742fc master_replid2:0000000000000000000000000000000000000000 master_repl_offset:17286 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:17286 2、shutdown 6381 127.0.0.1:6381> shutdown not connected> quit 3、登录集群内任意主机，执行cluster nodes命令查看集群关系：6381已经fail，6384成为新的master 4.2、6381重新登录之后，是成为master还是slave？--slave身份 [root@192 cluster]# redis-server redis-6381.conf # 启动6381 [root@192 cluster]# redis-cli -a 111111 -p 6381 -c @登录 Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. 127.0.0.1:6381> cluster nodes # 查看集群关系 3075d51754554aa421ee23ccbd8e263c0d5c4f0e 192.168.1.12:6383@16383 master - 0 1706383916749 3 connected 5461-10922 4a60743d7b067dfd03c6a0d4403c88ce173abb1c 192.168.1.12:6384@16384 master - 0 1706383917558 7 connected 0-5460 95d8800931e38739a85d6face5296d719a8d5bfa 192.168.1.13:6385@16385 master - 0 1706383917558 5 connected 10923-16383 491bb2df7fa39bafd917f7aaa0a409e19e41b07f 192.168.1.11:6381@16381 myself,slave 4a60743d7b067dfd03c6a0d4403c88ce173abb1c 0 1706383917000 7 connected # 6381还是slave 458cf2edf6cc3005cee4fc3aa93278efa86637ec 192.168.1.13:6386@16386 slave 3075d51754554aa421ee23ccbd8e263c0d5c4f0e 0 1706383916000 3 connected cc9a9f6bad23314263e2b89e4beede4fc59c3ef3 192.168.1.11:6382@16382 slave 95d8800931e38739a85d6face5296d719a8d5bfa 0 1706383917759 5 connected 4.3、有主机宕机后，集群的关系与当初设计时不一致了。关系被打乱。如何恢复？ 以当前为例。6381的master被6384顶替了。需要登录6381之后命令：cluster failover 127.0.0.1:6381> cluster failover # 将当前主机置为master OK 127.0.0.1:6381> cluster nodes 3075d51754554aa421ee23ccbd8e263c0d5c4f0e 192.168.1.12:6383@16383 master - 0 1706384388767 3 connected 5461-10922 4a60743d7b067dfd03c6a0d4403c88ce173abb1c 192.168.1.12:6384@16384 slave 491bb2df7fa39bafd917f7aaa0a409e19e41b07f 0 1706384389000 8 connected 95d8800931e38739a85d6face5296d719a8d5bfa 192.168.1.13:6385@16385 master - 0 1706384389573 5 connected 10923-16383 491bb2df7fa39bafd917f7aaa0a409e19e41b07f 192.168.1.11:6381@16381 myself,master - 0 1706384389000 8 connected 0-5460 458cf2edf6cc3005cee4fc3aa93278efa86637ec 192.168.1.13:6386@16386 slave 3075d51754554aa421ee23ccbd8e263c0d5c4f0e 0 1706384388057 3 connected cc9a9f6bad23314263e2b89e4beede4fc59c3ef3 192.168.1.11:6382@16382 slave 95d8800931e38739a85d6face5296d719a8d5bfa 0 1706384389775 5 connected 4.4、扩容与缩容测试---扩容 1、复制两份配置文件，分别将端口号替换为6387和6388 2、启动两个新节点实例，此时他们都是master [root@192 cluster]# redis-server redis-6387.conf # 启动两个实例 [root@192 cluster]# redis-server redis-6388.conf [root@192 cluster]# redis-cli -a 111111 -p 6387 # 登录一个做演示 Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. 127.0.0.1:6387> info replication # 查看关系 # Replication role:master ###master connected_slaves:0 master_failover_state:no-failover master_replid:ccf0e3ef0a7ea4c965d4f1298518686b5e748a7c master_replid2:0000000000000000000000000000000000000000 master_repl_offset:0 second_repl_offset:-1 repl_backlog_active:0 repl_backlog_size:1048576 repl_backlog_first_byte_offset:0repl_backlog_histlen:0 3、将新增的6387（空槽号）作为master节点加入原来的集群：命令：redis-cli -a 密码 --cluster add-node 要加入的节点ip:端口 已经在集群中的节点ip:端口（相当于介绍人） [root@192 cluster]# redis-cli -a 111111 --cluster add-node 192.168.1.13:6387 192.168.1.11:6381 Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. >>> Adding node 192.168.1.13:6387 to cluster 192.168.1.11:6381 >>> Performing Cluster Check (using node 192.168.1.11:6381) M: 491bb2df7fa39bafd917f7aaa0a409e19e41b07f 192.168.1.11:6381 slots:[0-5460] (5461 slots) master 1 additional replica(s) M: 3075d51754554aa421ee23ccbd8e263c0d5c4f0e 192.168.1.12:6383 slots:[5461-10922] (5462 slots) master 1 additional replica(s) S: 4a60743d7b067dfd03c6a0d4403c88ce173abb1c 192.168.1.12:6384 slots: (0 slots) slave replicates 491bb2df7fa39bafd917f7aaa0a409e19e41b07f M: 95d8800931e38739a85d6face5296d719a8d5bfa 192.168.1.13:6385 slots:[10923-16383] (5461 slots) master 1 additional replica(s) S: 458cf2edf6cc3005cee4fc3aa93278efa86637ec 192.168.1.13:6386 slots: (0 slots) slave replicates 3075d51754554aa421ee23ccbd8e263c0d5c4f0e S: cc9a9f6bad23314263e2b89e4beede4fc59c3ef3 192.168.1.11:6382 slots: (0 slots) slave replicates 95d8800931e38739a85d6face5296d719a8d5bfa [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. >>> Getting functions from cluster >>> Send FUNCTION LIST to 192.168.1.13:6387 to verify there is no functions in it >>> Send FUNCTION RESTORE to 192.168.1.13:6387 >>> Send CLUSTER MEET to node 192.168.1.13:6387 to make it join the cluster. [OK] New node added correctly. [root@192 cluster]# 4、检查集群的情况 5、给新的节点匀一些槽号。命令：redis-cli -a 密码 --cluster reshard IP地址:端口号 [root@192 cluster]# redis-cli -a 111111 --cluster reshard 192.168.1.11:6381 # ip端口为集群内的任意实例 Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. >>> Performing Cluster Check (using node 192.168.1.11:6381) M: 491bb2df7fa39bafd917f7aaa0a409e19e41b07f 192.168.1.11:6381 slots:[0-5460] (5461 slots) master 1 additional replica(s) M: 3075d51754554aa421ee23ccbd8e263c0d5c4f0e 192.168.1.12:6383 slots:[5461-10922] (5462 slots) master 1 additional replica(s) M: 2f1ed0f391fa1e0a5b3fac8e5d3c669c811ac283 192.168.1.13:6387 slots: (0 slots) master S: 4a60743d7b067dfd03c6a0d4403c88ce173abb1c 192.168.1.12:6384 slots: (0 slots) slave replicates 491bb2df7fa39bafd917f7aaa0a409e19e41b07f M: 95d8800931e38739a85d6face5296d719a8d5bfa 192.168.1.13:6385 slots:[10923-16383] (5461 slots) master 1 additional replica(s) S: 458cf2edf6cc3005cee4fc3aa93278efa86637ec 192.168.1.13:6386 slots: (0 slots) slave replicates 3075d51754554aa421ee23ccbd8e263c0d5c4f0e S: cc9a9f6bad23314263e2b89e4beede4fc59c3ef3 192.168.1.11:6382 slots: (0 slots) slave replicates 95d8800931e38739a85d6face5296d719a8d5bfa [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. How many slots do you want to move (from 1 to 16384)? 4096 ###匀多少槽号，案例匀了4096个 What is the receiving node ID? 2f1ed0f391fa1e0a5b3fac8e5d3c669c811ac283 ###匀给谁，这里需要填目标节点ID（6387的ID） Please enter all the source node IDs. Type 'all' to use all the nodes as source nodes for the hash slots. Type 'done' once you entered all the source nodes IDs. Source node #1: all ###这里填all Ready to move 4096 slots. Source nodes: M: 491bb2df7fa39bafd917f7aaa0a409e19e41b07f 192.168.1.11:6381 slots:[0-5460] (5461 slots) master 1 additional replica(s) M: 3075d51754554aa421ee23ccbd8e263c0d5c4f0e 192.168.1.12:6383 slots:[5461-10922] (5462 slots) master 1 additional replica(s) M: 95d8800931e38739a85d6face5296d719a8d5bfa 192.168.1.13:6385 slots:[10923-16383] (5461 slots) master 1 additional replica(s) Destination node: M: 2f1ed0f391fa1e0a5b3fac8e5d3c669c811ac283 192.168.1.13:6387 slots: (0 slots) master Resharding plan: Moving slot 5461 from 3075d51754554aa421ee23ccbd8e263c0d5c4f0e Moving slot 5462 from 3075d51754554aa421ee23ccbd8e263c0d5c4f0e Moving slot 5463 from 3075d51754554aa421ee23ccbd8e263c0d5c4f0e Moving slot 5464 from 3075d51754554aa421ee23ccbd8e263c0d5c4f0e .......等 6、再次查看集群情况 问题：为什么6387是3个新的区间，以前的还是连续？ 重新分配成本太高，所以前3家各自匀出来一部分，从6381/6383/6385三个旧节点分别匀出1364个坑位给新节点6387 7、为6387分配从节点6388。命令：redis-cli -a 密码 --cluster add-node ip:新slave端口 ip:新master端口 --cluster-slave --cluster-master-id 新master主机节点ID [root@192 cluster]# redis-cli -a 111111 --cluster add-node 192.168.1.13:6388 192.168.1.13:6387 --cluster-slave --cluster-master-id 2f1ed0f391fa1e0a5b3fac8e5d3c669c811ac283 Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. >>> Adding node 192.168.1.13:6388 to cluster 192.168.1.13:6387 >>> Performing Cluster Check (using node 192.168.1.13:6387) M: 2f1ed0f391fa1e0a5b3fac8e5d3c669c811ac283 192.168.1.13:6387 slots:[0-1364],[5461-6826],[10923-12287] (4096 slots) master M: 491bb2df7fa39bafd917f7aaa0a409e19e41b07f 192.168.1.11:6381 slots:[1365-5460] (4096 slots) master 1 additional replica(s) M: 95d8800931e38739a85d6face5296d719a8d5bfa 192.168.1.13:6385 slots:[12288-16383] (4096 slots) master 1 additional replica(s) S: cc9a9f6bad23314263e2b89e4beede4fc59c3ef3 192.168.1.11:6382 slots: (0 slots) slave replicates 95d8800931e38739a85d6face5296d719a8d5bfa M: 3075d51754554aa421ee23ccbd8e263c0d5c4f0e 192.168.1.12:6383 slots:[6827-10922] (4096 slots) master 1 additional replica(s) S: 4a60743d7b067dfd03c6a0d4403c88ce173abb1c 192.168.1.12:6384 slots: (0 slots) slave replicates 491bb2df7fa39bafd917f7aaa0a409e19e41b07f S: 458cf2edf6cc3005cee4fc3aa93278efa86637ec 192.168.1.13:6386 slots: (0 slots) slave replicates 3075d51754554aa421ee23ccbd8e263c0d5c4f0e [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. >>> Send CLUSTER MEET to node 192.168.1.13:6388 to make it join the cluster. Waiting for the cluster to join >>> Configure node as replica of 192.168.1.13:6387. [OK] New node added correctly. [root@192 cluster]# 8、第三次检查集群情况 4.5、扩容与缩容测试---缩容 1、先查看集群的情况，获得6388的ID [root@192 cluster]# redis-cli -a 111111 --cluster check 192.168.1.13:6387 Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. 192.168.1.13:6387 (2f1ed0f3...) -> 1 keys | 4096 slots | 1 slaves. 192.168.1.11:6381 (491bb2df...) -> 0 keys | 4096 slots | 1 slaves. 192.168.1.13:6385 (95d88009...) -> 1 keys | 4096 slots | 1 slaves. 192.168.1.12:6383 (3075d517...) -> 0 keys | 4096 slots | 1 slaves. [OK] 2 keys in 4 masters. 0.00 keys per slot on average. >>> Performing Cluster Check (using node 192.168.1.13:6387) M: 2f1ed0f391fa1e0a5b3fac8e5d3c669c811ac283 192.168.1.13:6387 slots:[0-1364],[5461-6826],[10923-12287] (4096 slots) master 1 additional replica(s) S: cc9a9f6bad23314263e2b89e4beede4fc59c3ef3 192.168.1.11:6382 slots: (0 slots) slave replicates 95d8800931e38739a85d6face5296d719a8d5bfa M: 491bb2df7fa39bafd917f7aaa0a409e19e41b07f 192.168.1.11:6381 slots:[1365-5460] (4096 slots) master 1 additional replica(s) M: 95d8800931e38739a85d6face5296d719a8d5bfa 192.168.1.13:6385 slots:[12288-16383] (4096 slots) master 1 additional replica(s) S: 458cf2edf6cc3005cee4fc3aa93278efa86637ec 192.168.1.13:6386 slots: (0 slots) slave replicates 3075d51754554aa421ee23ccbd8e263c0d5c4f0e S: b01ff575c1e793617332d8786c61bb2a3d1bd290 192.168.1.13:6388 slots: (0 slots) slave replicates 2f1ed0f391fa1e0a5b3fac8e5d3c669c811ac283 S: 4a60743d7b067dfd03c6a0d4403c88ce173abb1c 192.168.1.12:6384 slots: (0 slots) slave replicates 491bb2df7fa39bafd917f7aaa0a409e19e41b07f M: 3075d51754554aa421ee23ccbd8e263c0d5c4f0e 192.168.1.12:6383 slots:[6827-10922] (4096 slots) master 1 additional replica(s) [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. [root@192 cluster]# 2、删除6388节点。命令：redis-cli -a 密码 --cluster del-node 被删ip:端口 被删节点ID [root@192 cluster]# redis-cli -a 111111 --cluster del-node 192.168.1.13:6388 b01ff575c1e793617332d8786c61bb2a3d1bd290 Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. >>> Removing node b01ff575c1e793617332d8786c61bb2a3d1bd290 from cluster 192.168.1.13:6388 >>> Sending CLUSTER FORGET messages to the cluster... >>> Sending CLUSTER RESET SOFT to the deleted node. [root@192 cluster]# 3、清空6387的槽号，重新分配。当前案例将槽号都分配给6381 [root@192 cluster]# redis-cli -a 111111 --cluster reshard 192.168.1.11:6381 ### Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. >>> Performing Cluster Check (using node 192.168.1.11:6381) M: 491bb2df7fa39bafd917f7aaa0a409e19e41b07f 192.168.1.11:6381 slots:[1365-5460] (4096 slots) master 1 additional replica(s) M: 3075d51754554aa421ee23ccbd8e263c0d5c4f0e 192.168.1.12:6383 slots:[6827-10922] (4096 slots) master 1 additional replica(s) M: 2f1ed0f391fa1e0a5b3fac8e5d3c669c811ac283 192.168.1.13:6387 slots:[0-1364],[5461-6826],[10923-12287] (4096 slots) master S: 4a60743d7b067dfd03c6a0d4403c88ce173abb1c 192.168.1.12:6384 slots: (0 slots) slave replicates 491bb2df7fa39bafd917f7aaa0a409e19e41b07f M: 95d8800931e38739a85d6face5296d719a8d5bfa 192.168.1.13:6385 slots:[12288-16383] (4096 slots) master 1 additional replica(s) S: 458cf2edf6cc3005cee4fc3aa93278efa86637ec 192.168.1.13:6386 slots: (0 slots) slave replicates 3075d51754554aa421ee23ccbd8e263c0d5c4f0e S: cc9a9f6bad23314263e2b89e4beede4fc59c3ef3 192.168.1.11:6382 slots: (0 slots) slave replicates 95d8800931e38739a85d6face5296d719a8d5bfa [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. How many slots do you want to move (from 1 to 16384)? 4096### What is the receiving node ID? 491bb2df7fa39bafd917f7aaa0a409e19e41b07f ###6381的ID Please enter all the source node IDs. Type 'all' to use all the nodes as source nodes for the hash slots. Type 'done' once you entered all the source nodes IDs. Source node #1: 2f1ed0f391fa1e0a5b3fac8e5d3c669c811ac283 # 6387的ID Source node #2: done ###这里填done不是all Ready to move 4096 slots. Source nodes: M: 3075d51754554aa421ee23ccbd8e263c0d5c4f0e 192.168.1.12:6383 slots:[6827-10922] (4096 slots) master 1 additional replica(s) M: 2f1ed0f391fa1e0a5b3fac8e5d3c669c811ac283 192.168.1.13:6387 slots:[0-1364],[5461-6826],[10923-12287] (4096 slots) master M: 95d8800931e38739a85d6face5296d719a8d5bfa 192.168.1.13:6385 slots:[12288-16383] (4096 slots) master 1 additional replica(s) Destination node: M: 491bb2df7fa39bafd917f7aaa0a409e19e41b07f 192.168.1.11:6381 slots:[1365-5460] (4096 slots) master 1 additional replica(s) Resharding plan: Moving slot 6827 from 3075d51754554aa421ee23ccbd8e263c0d5c4f0e Moving slot 6828 from 3075d51754554aa421ee23ccbd8e263c0d5c4f0e ........ 4、删除6387master.命令：redis-cli -a 密码 --cluster del-node ip:端口 6387节点ID [root@192 cluster]# redis-cli -a 111111 --cluster del-node 192.168.1.13:6387 2f1ed0f391fa1e0a5b3fac8e5d3c669c811ac283 Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. >>> Removing node 2f1ed0f391fa1e0a5b3fac8e5d3c669c811ac283 from cluster 192.168.1.13:6387 >>> Sending CLUSTER FORGET messages to the cluster... >>> Sending CLUSTER RESET SOFT to the deleted node. [root@192 cluster]# 注意点 集群也不能保证数据一致性，一定会存在数据丢失的情况。 五、相关命令 info replication：返回关于 Redis 主从复制的详细信息 cluster info：获取 Redis 集群的状态和统计信息 cluster nodes：获取关于集群中所有节点的详细信息。 cluster countkeysinslot <槽位数字编号>：该槽位是否被占用。1占用2未占用 cluster keyslot <keyname> 该key应该存放在哪个槽位上 cluster failover ： 将当前redis的身份从slave变成master，原来的master变成slave 不在同一个slot槽位下的多键操作支持不好，通识占位符登场： 不在同一个slot槽位下的键值无法使用mset、mget等多键操作。 可以通过{}来定义同一个组的概念，使key中{内相同内容的键值对放到一个stot槽位去，对照下图类似k1k2k3都映射为x，自然槽位一样。 设置集群是否完整才能提供服务： 默认YES，现在集群架构是3主3从的redis cluster由3个master平分16384个slot，每个master的小集群负责1/3的slot，对应一部分数据。cluster-require-ful-coverage:默认值yes,即需要集群完整性，方可对外提供服务 通常情况，如果这3个小集群中，任何一个(1主1从)挂了，你这个集群对外可提供的数据只有2/3了，整个集群是不完整的，redis 默认在这种情况下，是不会对外提供服务的。 如果你的诉求是，集群不完整的话也需要对外提供服务，需要将该参数设置为no，这样的话你挂了的那个小集群是不行了，但是其他的小集群仍然可以对外提供服务。
一、安装redis集群 cluster(集群)模式-docker版，哈希槽分区进行亿级数据存储。 1.1、问题 1~2 亿条数据需要缓存，请问如何设计这个存储案例。 单机单台 100% 不可能，肯定是分布式存储，用redis如何落地？ 1.2、哈希取余分区 2亿条记录就是2亿个 k,v，我们单机不行必须要分布式多机，假设有3台机器构成一个集群，用户每次读写操作都是根据公式： hash(key) % N个机器台数，计算出哈希值，用来决定数据映射到哪一个节点上。 优点： 简单粗暴，直接有效，只需要预估好数据规划好节点，例如3台、8台、10台，就能保证一段时间的数据支撑。使用Hash算法让固定的一部分请求落到同一台服务器上，这样每台服务器固定处理一部分请求（并维护这些请求的信息），起到负载均衡+分而治之的作用。 缺点： 原来规划好的节点，进行扩容或者缩容就比较麻烦了额，不管扩缩，每次数据变动导致节点有变动，映射关系需要重新进行计算，在服务器个数固定不变时没有问题，如果需要弹性扩容或故障停机的情况下，原来的取模公式就会发生变化：Hash(key)/3会变成Hash(key) /?。此时地址经过取余运算的结果将发生很大变化，根据公式获取的服务器也会变得不可控。某个redis机器宕机了，由于台数数量变化，会导致hash取余全部数据重新洗牌。 二、步骤 2.1、算法构建一致性哈希环 一致性哈希环： 一致性哈希算法必然有个hash函数并按照算法产生hash值，这个算法的所有可能哈希值会构成一个全量集，这个集合可以成为一个hash空间[0,2^32-1]，这个是一个线性空间，但是在算法中，我们通过适当的逻辑控制将它首尾相连(0 = 2^32),这样让它逻辑上形成了一个环形空间。 它也是按照使用取模的方法，前面笔记介绍的节点取模法是对节点（服务器）的数量进行取模。而一致性 Hash 算法是对2^32取模，简单来说，一致性 Hash 算法将整个哈希值空间组织成一个虚拟的圆环，如假设某哈希函数H的值空间为 0-2^32-1（即哈希值是一个32位无符号整形），整个哈希环如下图：整个空间按顺时针方向组织，圆环的正上方的点代表0，0点右侧的第一个点代表1，以此类推，2、3、4、……直到 2^32-1，也就是说0点左侧的第一个点代表 2^32-1， 0 和 2^32-1 在零点中方向重合，我们把这个由2^32个点组成的圆环称为Hash环。 2.2、服务器IP节点映射 节点映射： 将集群中各个IP节点映射到环上的某一个位置。 将各个服务器使用Hash进行一个哈希，具体可以选择服务器的IP或主机名作为关键字进行哈希，这样每台机器就能确定其在哈希环上的位置。假如4个节点NodeA、B、C、D，经过IP地址的哈希函数计算(hash(ip))，使用IP地址哈希后在环空间的位置如下： 2.3、key落到服务器的落键规则 当我们需要存储一个kv键值对时，首先计算 key 的 hash 值，hash(key)，将这个 key 使用相同的函数Hash计算出哈希值并确定此数据在环上的位置，从此位置沿环顺时针“行走”，第一台遇到的服务器就是其应该定位到的服务器，并将该键值对存储在该节点上。 如我们有Object A、Object B、Object C、Object D四个数据对象，经过哈希计算后，在环空间上的位置如下：根据一致性Hash算法，数据A会被定为到Node A上，B被定为到Node B上，C被定为到Node C上，D被定为到Node D上。 四、优点 4.1、一致性哈希算法的容错性 容错性： 假设Node C宕机，可以看到此时对象A、B、D不会受到影响，只有C对象被重定位到Node D。一般的，在一致性Hash算法中，如果一台服务器不可用，则受影响的数据仅仅是此服务器到其环空间中前一台服务器（即沿着逆时针方向行走遇到的第一台服务器）之间数据，其它不会受到影响。简单说，就是C挂了，受到影响的只是B、C之间的数据，并且这些数据会转移到D进行存储。 4.2、一致性哈希算法的扩展性 扩展性： 数据量增加了，需要增加一台节点NodeX，X的位置在A和B之间，那收到影响的也就是A到X之间的数据，重新把A到X的数据录入到X上即可，不会导致hash取余全部数据重新洗牌。 五、缺点 一致性哈希算法的数据倾斜问题 Hash环的数据倾斜问题 一致性Hash算法在服务节点太少时，容易因为节点分布不均匀而造成数据倾斜（被缓存的对象大部分集中缓存在某一台服务器上）问题，例如系统中只有两台服务器： 六、总结 为了在节点数目发生改变时尽可能少的迁移数据。 将所有的存储节点排列在收尾相接的Hash环上，每个key在计算Hash后会顺时针找到临近的存储节点存放。而当有节点加入或退出时仅影响该节点在Hash环上顺时针相邻的后续节点。 优点： 加入和删除节点只影响哈希环中顺时针方向的相邻的节点，对其他节点无影响。 缺点： 数据的分布和节点的位置有关，因为这些节点不是均匀的分布在哈希环上的，所以数据在进行存储时达不到均匀分布的效果。 七、哈希槽分区 7.1、为什么出现 一致性哈希算法的数据倾斜问题 哈希槽实质就是一个数组，数组[0,2^14 -1]形成hash slot空间。 7.2、能干什么 解决均匀分配的问题，在数据和节点之间又加入了一层，把这层称为哈希槽（slot），用于管理数据和节点之间的关系，现在就相当于节点上放的是槽，槽里放的是数据。 槽解决的是粒度问题，相当于把粒度变大了，这样便于数据移动。 哈希解决的是映射问题，使用key的哈希值来计算所在的槽，便于数据分配。 7.3、多少个hash槽 一个集群只能有16384个槽，编号0-16383（0-2^14-1）。这些槽会分配给集群中的所有主节点，分配策略没有要求。可以指定哪些编号的槽分配给哪个主节点。集群会记录节点和槽的对应关系。解决了节点和槽的关系后，接下来就需要对key求哈希值，然后对16384取余，余数是几key就落入对应的槽里。slot = CRC16(key) % 16384。以槽为单位移动数据，因为槽的数目是固定的，处理起来比较容易，这样数据移动问题就解决了。 7.4、哈希槽计算 Redis 集群中内置了 16384 个哈希槽，redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。当需要在 Redis 集群中放置一个 key-value时，redis 先对 key 使用 crc16 算法算出一个结果，然后把结果对 16384 求余数，这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽，也就是映射到某个节点上。如下代码，key之A 、B在Node2， key之C落在Node3上。
本文档制定使用Redis规范和使用要求，制定规范命名和流程化的使用规则，从而降低后期维护、扩容、管理的成本。 一、名词释义 Redis 可基于内存亦可持久化的日志型、Key-Value 数据库。 TableName 实体类名称,例如 bi_menu 表对应的实体类是 BiMenu。 PrimaryKeyValue 某个表的主键值。 Column 实体类里面的字段名称。例如 bi_menu 表对应的实体类字段名称 name。 ColumnValue 列的值。 index 字符串 index 代表此 key 是用来记录索引的。 sort 字符串 sort 代表此 key 是用来排序标记的。 二、开发规则 2.1、key 命名 1、存放表里面所有字段信息。TableName: PrimaryKeyValue: Column 2、存放表里面某一列的信息 TableName：Column：ColumnValue 3、存放表里面某一行object信息。TableName: PrimaryKeyValue 4、存放表里面的索引。TableName: index: Column 5、存放表里面的字段排序。TableName: sort: Column bi_menu (菜单按钮) CREATE TABLE bi_menu ( id VARCHAR(36) NOT NULL PRIMARY KEY COMMENT '主键', name VARCHAR(200) NULL COMMENT '名称', sequence INT(11) NULL COMMENT '序列', description VARCHAR(200) NULL COMMENT '描述', logo VARCHAR(200) NULL COMMENT '图标', url VARCHAR(200) NULL COMMENT '访问地址' ); 类型1(value就是具体的值) BiMenu:1:id 1 BiMenu:1:name 系统应用 BiMenu:1:sequence 1 BiMenu:1:description 这是系统应用的按钮 BiMenu:1:logo 图片地址 BiMenu:1:url http://localhost:8080/aa.do 类型2(value就是该行的主键值PrimaryKeyValue) BiMenu:name:系统应用 1 BiMenu:url:http://www.baidu.com 1 类型3(value是该行数据的jason格式) BiMenu:1 { "id": "1", "name": "系统应用", " sequence ": "1", " description ": "这是系统应用的按钮" } 类型4(value是该行数据的主键值PrimaryKeyValue) BiMenu:index:id BiMenu:1 BiMenu:index:id BiMenu:2 BiMenu:index:id BiMenu:3 类型5(value是该行数据的主键值PrimaryKeyValue) BiMenu:sort:sequence BiMenu:1 BiMenu:sort:sequence BiMenu:2 BiMenu:sort:sequence BiMenu:3
环境准备 redis-server： 192.168.25.128:6379 主 redis6379.conf 192.168.25.128:6380 从 redis6380.conf 192.168.25.128:6381 从 redis6381.conf 一、redis 一主二从 主节点 redis6379.conf 配置 port 6379 daemonize yes bind 192.168.25.128 requirepass 123456 pidfile /usr/local/redis/etc/redis_pid_6379.pid logfile /usr/local/redis/etc/redis_6379.log dbfilename dump6379.rdb 从节点 redis6380.conf redis6381.conf 配置 port 6380 #6381 daemonize yes bind 192.168.25.128 requirepass 123456 masterauth 123456 pidfile /usr/local/redis/etc/redis_pid_6380.pid logfile /usr/local/redis/etc/redis_6380.log dbfilename dump6380.rdb slaveof 192.168.25.128 6379 分别启动三个 redis 实例 /usr/local/redis/bin/redis-server /usr/local/redis/etc/redis6379.conf /usr/local/redis/bin/redis-server /usr/local/redis/etc/redis6380.conf /usr/local/redis/bin/redis-server /usr/local/redis/etc/redis6381.conf 执行info replication查看当前主从配置 192.168.25.128:6379> info replication # Replication role:master connected_slaves:2 slave0:ip=192.168.25.128,port=6380,state=online,offset=211,lag=1 slave1:ip=192.168.25.128,port=6381,state=online,offset=211,lag=1 master_repl_offset:211 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:2 repl_backlog_histlen:210 192.168.25.128:6380> info replication # Replication role:slave master_host:192.168.25.128 master_port:6379 master_link_status:up master_last_io_seconds_ago:9 master_sync_in_progress:0 slave_repl_offset:29 slave_priority:100 slave_read_only:1 connected_slaves:0 master_repl_offset:0 repl_backlog_active:0 repl_backlog_size:1048576 repl_backlog_first_byte_offset:0 repl_backlog_histlen:0 192.168.25.128:6381> info replication # Replication role:slave master_host:192.168.25.128 master_port:6379 master_link_status:up master_last_io_seconds_ago:8 master_sync_in_progress:0 slave_repl_offset:43 slave_priority:100 slave_read_only:1 connected_slaves:0 master_repl_offset:0 repl_backlog_active:0 repl_backlog_size:1048576 repl_backlog_first_byte_offset:0 repl_backlog_histlen:0 如果如上图所示没有发现从节点，很有可能是防火墙没有开放 8000 端口导致主从节点之间没法通信。 执行以下命令： firewall-cmd --zone=public --add-port=8000/tcp --permanent firewall-cmd --zone=public --add-port=6800/tcp --permanent firewall-cmd --reload 二、redis 一主二从三哨兵 Redis Sentinel 是 Redis 官方提供的集群管理工具，可以部署在其他与 redis 集群可通讯的机器中监控 redis 集群。 特性： 监控：能持续监控Redis的主从实例是否正常工作; 通知：当被监控的Redis实例出问题时，能通过API通知系统管理员或其他程序; 自动故障恢复：如果主实例无法正常工作，Sentinel将启动故障恢复机制把一个从实例提升为主实例，其他的从实例将会被重新配置到新的主实例，且应用程序会得到一个更换新地址的通知。 哨兵的作用： 监控 redis(master和slave) 是否正常运行; 当 master 运行出现状况，能够通知另外一个进程自动将 slave 切换成 master。 应用场景： 当使用 redis 做 master-slave 的高可用方案时，如果 master 宕机了，想自动进行主备切换，可以考虑使用哨兵模式。 配置文件 sentinel_26379.conf： port 26379 daemonize yes dir "/opt/redis-3.0.0/sentinel/tmp/26379" logfile "/opt/redis-3.0.0/sentinel/log/sentinel_26379.log" sentinel monitor mymaster 192.168.25.128 6379 2 sentinel down-after-milliseconds mymaster 60000 sentinel auth-pass mymaster 123456 启动三方 sentinel ： /usr/local/redis/bin/redis-sentinel /opt/redis-3.0.0/sentinel/sentinel_26379.conf & /usr/local/redis/bin/redis-sentinel /opt/redis-3.0.0/sentinel/sentinel_26380.conf & /usr/local/redis/bin/redis-sentinel /opt/redis-3.0.0/sentinel/sentinel_26381.conf & 连接 sentinel 查看信息： redis-cli -h 192.168.25.128 -p 26379 info sentinel # Sentinel sentinel_masters:1 sentinel_tilt:0 sentinel_running_scripts:0 sentinel_scripts_queue_length:0 master0:name=mymaster,status=ok,address=192.168.25.128:6379,slaves=2,sentinels=3 主节点状态： 192.168.25.128:6379> info replication # Replication role:master connected_slaves:2 slave0:ip=192.168.25.128,port=6380,state=online,offset=170809,lag=0 slave1:ip=192.168.25.128,port=6381,state=online,offset=170809,lag=0 master_repl_offset:170952 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:2 repl_backlog_histlen:170951 手动关闭 Master 之后，sentinel 在监听 master 确实是断线了之后，将会开始计算权值，然后重新分配主服务器 3551:X 21 Dec 18:05:38.047 # +sdown master mymaster 192.168.25.128 6379 3551:X 21 Dec 18:05:38.146 # +new-epoch 1 3551:X 21 Dec 18:05:38.149 # +vote-for-leader 57ff9a9503775f11895a3d7e59ec116634c19718 1 3551:X 21 Dec 18:05:39.152 # +odown master mymaster 192.168.25.128 6379 #quorum 3/2 3551:X 21 Dec 18:05:39.152 # Next failover delay: I will not start a failover before Mon Dec 21 18:11:38 2020 3551:X 21 Dec 18:05:39.267 # +config-update-from sentinel 192.168.25.128:26380 192.168.25.128 26380 @ mymaster 192.168.25.128 6379 3551:X 21 Dec 18:05:39.267 # +switch-master mymaster 192.168.25.128 6379 192.168.25.128 6381 3551:X 21 Dec 18:05:39.268 * +slave slave 192.168.25.128:6380 192.168.25.128 6380 @ mymaster 192.168.25.128 6381 3551:X 21 Dec 18:05:39.274 * +slave slave 192.168.25.128:6379 192.168.25.128 6379 @ mymaster 192.168.25.128 6381 3551:X 21 Dec 18:06:39.315 # +sdown slave 192.168.25.128:6379 192.168.25.128 6379 @ mymaster 192.168.25.128 6381 6381 被选举为 Master redis-cli -h 192.168.25.128 -p 26380 info sentinel # Sentinel sentinel_masters:1 sentinel_tilt:0 sentinel_running_scripts:0 sentinel_scripts_queue_length:0 master0:name=mymaster,status=ok,address=192.168.25.128:6381,slaves=2,sentinels=3 重新启动之前的主节点 6379 如果 6379 重连之后，会不会抢回属于他的位置，答案是否定的，因此当 6379 回来之后，也只能当个从服务 redis-cli -h 192.168.25.128 -p 6379 -a 123456 192.168.25.128:6379> info replication # Replication role:slave master_host:192.168.25.128 master_port:6381 master_link_status:down master_last_io_seconds_ago:-1 master_sync_in_progress:0 slave_repl_offset:1 master_link_down_since_seconds:1608603251 slave_priority:100 slave_read_only:1 connected_slaves:0 master_repl_offset:0 repl_backlog_active:0 repl_backlog_size:1048576 repl_backlog_first_byte_offset:0 repl_backlog_histlen:0 Sentinel的工作方式: 每个Sentinel以每秒钟一次的频率向它所知的Master，Slave以及其他 Sentinel 实例发送一个 PING 命令 如果一个实例（instance）距离最后一次有效回复 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 的主观下线状态就会被移除。 三、redis 集群搭建 Redis 集群采用了 P2P 的模式，完全去中心化。Redis 把所有的 Key 分成了 16384 个 slot，每个 Redis 实例负责其中一部分 slot 。集群中的所有信息（节点、端口、slot等），都通过节点之间定期的数据交换而更新。 Redis 客户端可以在任意一个 Redis 实例发出请求，如果所需数据不在该实例中，通过重定向命令引导客户端访问所需的实例。 安装集群所需软件： yum install ruby yum install rubygems gem install redis 创建集群命令： /usr/local/redis/bin/redis-trib.rb create --replicas 1 192.168.25.128:6379 192.168.25.128:6380 192.168.25.128:6381 192.168.25.128:6382 192.168.25.128:6383 192.168.25.128:6384 调用 ruby 命令来进行创建集群，--replicas 1 表示主从复制比例为 1:1，即一个主节点对应一个从节点；然后，默认给我们分配好了每个主节点和对应从节点服务，以及 solt 的大小，因为在 Redis 集群中有且仅有 16383 个 solt ，默认情况会给我们平均分配，当然你可以指定，后续的增减节点也可以重新分配。 验证： redis-cli -c -h 192.168.25.128 -p 9001 cluster info cluster nodes 通过命令，可以详细的看出集群信息和各个节点状态，主从信息以及连接数、槽信息等。 当我们 set key1 value1 时，出现了 Redirected to slot 信息并自动连接到了 9002 节点。这也是集群的一个数据分配特性，这里不详细说了。
一、基本配置 # 当配置中需要配置内存大小时，可以使用 1k, 5GB, 4M 等类似的格式，其转换方式如下(不区分大小写) # # 1k => 1000 bytes # 1kb => 1024 bytes # 1m => 1000000 bytes # 1mb => 1024*1024 bytes # 1g => 1000000000 bytes # 1gb => 1024*1024*1024 bytes # # 内存配置大小写是一样的.比如 1gb 1Gb 1GB 1gB # daemonize no 默认情况下，redis不是在后台运行的，如果需要在后台运行，把该项的值更改为yes daemonize yes # 当redis在后台运行的时候，Redis默认会把pid文件放在/var/run/redis.pid，你可以配置到其他地址。 # 当运行多个redis服务时，需要指定不同的pid文件和端口 pidfile /var/run/redis.pid # 指定redis运行的端口，默认是6379 port 6379 # 指定redis只接收来自于该IP地址的请求，如果不进行设置，那么将处理所有请求， # 在生产环境中最好设置该项 # bind 127.0.0.1 # Specify the path for the unix socket that will be used to listen for # incoming connections. There is no default, so Redis will not listen # on a unix socket when not specified. # # unixsocket /tmp/redis.sock # unixsocketperm 755 # 设置客户端连接时的超时时间，单位为秒。当客户端在这段时间内没有发出任何指令，那么关闭该连接 # 0是关闭此设置 timeout 0 # 指定日志记录级别 # Redis总共支持四个级别：debug、verbose、notice、warning，默认为verbose # debug 记录很多信息，用于开发和测试 # varbose 有用的信息，不像debug会记录那么多 # notice 普通的verbose，常用于生产环境 # warning 只有非常重要或者严重的信息会记录到日志 loglevel debug # 配置log文件地址 # 默认值为stdout，标准输出，若后台模式会输出到/dev/null #logfile stdout logfile /var/log/redis/redis.log # To enable logging to the system logger, just set 'syslog-enabled' to yes, # and optionally update the other syslog parameters to suit your needs. # syslog-enabled no # Specify the syslog identity. # syslog-ident redis # Specify the syslog facility. Must be USER or between LOCAL0-LOCAL7. # syslog-facility local0 # 可用数据库数 # 默认值为16，默认数据库为0，数据库范围在0-（database-1）之间 databases 16 ################################ 快照 ################################# # # 保存数据到磁盘，格式如下: # # save <seconds> <changes> # # 指出在多长时间内，有多少次更新操作，就将数据同步到数据文件rdb。 # 相当于条件触发抓取快照，这个可以多个条件配合 # # 比如默认配置文件中的设置，就设置了三个条件 # # save 900 1 900秒内至少有1个key被改变 # save 300 10 300秒内至少有300个key被改变 # save 60 10000 60秒内至少有10000个key被改变 save 900 1 save 300 10 save 60 10000 # 存储至本地数据库时（持久化到rdb文件）是否压缩数据，默认为yes rdbcompression yes # 本地持久化数据库文件名，默认值为dump.rdb dbfilename dump.rdb # 工作目录 # # 数据库镜像备份的文件放置的路径。 # 这里的路径跟文件名要分开配置是因为redis在进行备份时，先会将当前数据库的状态写入到一个临时文件中，等备份完成时， # 再把该该临时文件替换为上面所指定的文件，而这里的临时文件和上面所配置的备份文件都会放在这个指定的路径当中。 # # AOF文件也会存放在这个目录下面 # # 注意这里必须制定一个目录而不是文件 dir ./ ################################# 复制 ################################# # 主从复制. 设置该数据库为其他数据库的从数据库. # 设置当本机为slav服务时，设置master服务的IP地址及端口，在Redis启动时，它会自动从master进行数据同步 # # slaveof <masterip> <masterport> # 当master服务设置了密码保护时(用requirepass制定的密码) # slav服务连接master的密码 # # masterauth <master-password> # 当从库同主机失去连接或者复制正在进行，从机库有两种运行方式： # # 1) 如果slave-serve-stale-data设置为yes(默认设置)，从库会继续相应客户端的请求 # # 2) 如果slave-serve-stale-data是指为no，出去INFO和SLAVOF命令之外的任何请求都会返回一个 # 错误"SYNC with master in progress" # slave-serve-stale-data yes # 从库会按照一个时间间隔向主库发送PINGs.可以通过repl-ping-slave-period设置这个时间间隔，默认是10秒 # # repl-ping-slave-period 10 # repl-timeout 设置主库批量数据传输时间或者ping回复时间间隔，默认值是60秒 # 一定要确保repl-timeout大于repl-ping-slave-period # repl-timeout 60 ################################## 安全 ################################### # 设置客户端连接后进行任何其他指定前需要使用的密码。 # 警告：因为redis速度相当快，所以在一台比较好的服务器下，一个外部的用户可以在一秒钟进行150K次的密码尝试，这意味着你需要指定非常非常强大的密码来防止暴力破解 # # requirepass foobared # 命令重命名. # # 在一个共享环境下可以重命名相对危险的命令。比如把CONFIG重名为一个不容易猜测的字符。 # # 举例: # # rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52 # # 如果想删除一个命令，直接把它重命名为一个空字符""即可，如下： # # rename-command CONFIG "" ################################### 约束 #################################### # 设置同一时间最大客户端连接数，默认无限制，Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件描述符数， # 如果设置 maxclients 0，表示不作限制。 # 当客户端连接数到达限制时，Redis会关闭新的连接并向客户端返回max number of clients reached错误信息 # # maxclients 128 # 指定Redis最大内存限制，Redis在启动时会把数据加载到内存中，达到最大内存后，Redis会先尝试清除已到期或即将到期的Key # Redis同时也会移除空的list对象 # # 当此方法处理后，仍然到达最大内存设置，将无法再进行写入操作，但仍然可以进行读取操作 # # 注意：Redis新的vm机制，会把Key存放内存，Value会存放在swap区 # # maxmemory的设置比较适合于把redis当作于类似memcached的缓存来使用，而不适合当做一个真实的DB。 # 当把Redis当做一个真实的数据库使用的时候，内存使用将是一个很大的开销 # maxmemory <bytes> # 当内存达到最大值的时候Redis会选择删除哪些数据？有五种方式可供选择 # # volatile-lru -> 利用LRU算法移除设置过过期时间的key (LRU:最近使用 Least Recently Used ) # allkeys-lru -> 利用LRU算法移除任何key # volatile-random -> 移除设置过过期时间的随机key # allkeys->random -> remove a random key, any key # volatile-ttl -> 移除即将过期的key(minor TTL) # noeviction -> 不移除任何可以，只是返回一个写错误 # # 注意：对于上面的策略，如果没有合适的key可以移除，当写的时候Redis会返回一个错误 # # 写命令包括: set setnx setex append # incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd # sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby # zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby # getset mset msetnx exec sort # # 默认是: # # maxmemory-policy volatile-lru # LRU 和 minimal TTL 算法都不是精准的算法，但是相对精确的算法(为了节省内存)，随意你可以选择样本大小进行检测。 # Redis默认的灰选择3个样本进行检测，你可以通过maxmemory-samples进行设置 # # maxmemory-samples 3 ############################## AOF ############################### # 默认情况下，redis会在后台异步的把数据库镜像备份到磁盘，但是该备份是非常耗时的，而且备份也不能很频繁，如果发生诸如拉闸限电、拔插头等状况，那么将造成比较大范围的数据丢失。 # 所以redis提供了另外一种更加高效的数据库备份及灾难恢复方式。 # 开启append only模式之后，redis会把所接收到的每一次写操作请求都追加到appendonly.aof文件中，当redis重新启动时，会从该文件恢复出之前的状态。 # 但是这样会造成appendonly.aof文件过大，所以redis还支持了BGREWRITEAOF指令，对appendonly.aof 进行重新整理。 # 你可以同时开启asynchronous dumps 和 AOF appendonly no # AOF文件名称 (默认: "appendonly.aof") # appendfilename appendonly.aof # Redis支持三种同步AOF文件的策略: # # no: 不进行同步，系统去操作 . Faster. # always: always表示每次有写操作都进行同步. Slow, Safest. # everysec: 表示对写操作进行累积，每秒同步一次. Compromise. # # 默认是"everysec"，按照速度和安全折中这是最好的。 # 如果想让Redis能更高效的运行，你也可以设置为"no"，让操作系统决定什么时候去执行 # 或者相反想让数据更安全你也可以设置为"always" # # 如果不确定就用 "everysec". # appendfsync always appendfsync everysec # appendfsync no # AOF策略设置为always或者everysec时，后台处理进程(后台保存或者AOF日志重写)会执行大量的I/O操作 # 在某些Linux配置中会阻止过长的fsync()请求。注意现在没有任何修复，即使fsync在另外一个线程进行处理 # # 为了减缓这个问题，可以设置下面这个参数no-appendfsync-on-rewrite # # This means that while another child is saving the durability of Redis is # the same as "appendfsync none", that in pratical terms means that it is # possible to lost up to 30 seconds of log in the worst scenario (with the # default Linux settings). # # If you have latency problems turn this to "yes". Otherwise leave it as # "no" that is the safest pick from the point of view of durability. no-appendfsync-on-rewrite no # Automatic rewrite of the append only file. # AOF 自动重写 # 当AOF文件增长到一定大小的时候Redis能够调用 BGREWRITEAOF 对日志文件进行重写 # # 它是这样工作的：Redis会记住上次进行些日志后文件的大小(如果从开机以来还没进行过重写，那日子大小在开机的时候确定) # # 基础大小会同现在的大小进行比较。如果现在的大小比基础大小大制定的百分比，重写功能将启动 # 同时需要指定一个最小大小用于AOF重写，这个用于阻止即使文件很小但是增长幅度很大也去重写AOF文件的情况 # 设置 percentage 为0就关闭这个特性 auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb ################################## SLOW LOG ################################### # Redis Slow Log 记录超过特定执行时间的命令。执行时间不包括I/O计算比如连接客户端，返回结果等，只是命令执行时间 # # 可以通过两个参数设置slow log：一个是告诉Redis执行超过多少时间被记录的参数slowlog-log-slower-than(微妙)， # 另一个是slow log 的长度。当一个新命令被记录的时候最早的命令将被从队列中移除 # 下面的时间以微妙微单位，因此1000000代表一分钟。 # 注意制定一个负数将关闭慢日志，而设置为0将强制每个命令都会记录 slowlog-log-slower-than 10000 # 对日志长度没有限制，只是要注意它会消耗内存 # 可以通过 SLOWLOG RESET 回收被慢日志消耗的内存 slowlog-max-len 1024 ################################ VM ############################### ### WARNING! Virtual Memory is deprecated in Redis 2.4 ### The use of Virtual Memory is strongly discouraged. # Virtual Memory allows Redis to work with datasets bigger than the actual # amount of RAM needed to hold the whole dataset in memory. # In order to do so very used keys are taken in memory while the other keys # are swapped into a swap file, similarly to what operating systems do # with memory pages. # # To enable VM just set 'vm-enabled' to yes, and set the following three # VM parameters accordingly to your needs. vm-enabled no # vm-enabled yes # This is the path of the Redis swap file. As you can guess, swap files # can't be shared by different Redis instances, so make sure to use a swap # file for every redis process you are running. Redis will complain if the # swap file is already in use. # # The best kind of storage for the Redis swap file (that's accessed at random) # is a Solid State Disk (SSD). # # *** WARNING *** if you are using a shared hosting the default of putting # the swap file under /tmp is not secure. Create a dir with access granted # only to Redis user and configure Redis to create the swap file there. vm-swap-file /tmp/redis.swap # vm-max-memory configures the VM to use at max the specified amount of # RAM. Everything that deos not fit will be swapped on disk *if* possible, that # is, if there is still enough contiguous space in the swap file. # # With vm-max-memory 0 the system will swap everything it can. Not a good # default, just specify the max amount of RAM you can in bytes, but it's # better to leave some margin. For instance specify an amount of RAM # that's more or less between 60 and 80% of your free RAM. vm-max-memory 0 # Redis swap files is split into pages. An object can be saved using multiple # contiguous pages, but pages can't be shared between different objects. # So if your page is too big, small objects swapped out on disk will waste # a lot of space. If you page is too small, there is less space in the swap # file (assuming you configured the same number of total swap file pages). # # If you use a lot of small objects, use a page size of 64 or 32 bytes. # If you use a lot of big objects, use a bigger page size. # If unsure, use the default :) vm-page-size 32 # Number of total memory pages in the swap file. # Given that the page table (a bitmap of free/used pages) is taken in memory, # every 8 pages on disk will consume 1 byte of RAM. # # The total swap size is vm-page-size * vm-pages # # With the default of 32-bytes memory pages and 134217728 pages Redis will # use a 4 GB swap file, that will use 16 MB of RAM for the page table. # # It's better to use the smallest acceptable value for your application, # but the default is large in order to work in most conditions. vm-pages 134217728 # Max number of VM I/O threads running at the same time. # This threads are used to read/write data from/to swap file, since they # also encode and decode objects from disk to memory or the reverse, a bigger # number of threads can help with big objects even if they can't help with # I/O itself as the physical device may not be able to couple with many # reads/writes operations at the same time. # # The special value of 0 turn off threaded I/O and enables the blocking # Virtual Memory implementation. vm-max-threads 4 ############################### ADVANCED CONFIG ############################### # 当hash中包含超过指定元素个数并且最大的元素没有超过临界时， # hash将以一种特殊的编码方式（大大减少内存使用）来存储，这里可以设置这两个临界值 # Redis Hash对应Value内部实际就是一个HashMap，实际这里会有2种不同实现， # 这个Hash的成员比较少时Redis为了节省内存会采用类似一维数组的方式来紧凑存储，而不会采用真正的HashMap结构，对应的value redisObject的encoding为zipmap, # 当成员数量增大时会自动转成真正的HashMap,此时encoding为ht。 hash-max-zipmap-entries 512 hash-max-zipmap-value 64 # list数据类型多少节点以下会采用去指针的紧凑存储格式。 # list数据类型节点值大小小于多少字节会采用紧凑存储格式。 list-max-ziplist-entries 512 list-max-ziplist-value 64 # set数据类型内部数据如果全部是数值型，且包含多少节点以下会采用紧凑格式存储。 set-max-intset-entries 512 # zsort数据类型多少节点以下会采用去指针的紧凑存储格式。 # zsort数据类型节点值大小小于多少字节会采用紧凑存储格式。 zset-max-ziplist-entries 128 zset-max-ziplist-value 64 # Redis将在每100毫秒时使用1毫秒的CPU时间来对redis的hash表进行重新hash，可以降低内存的使用 # # 当你的使用场景中，有非常严格的实时性需要，不能够接受Redis时不时的对请求有2毫秒的延迟的话，把这项配置为no。 # # 如果没有这么严格的实时性要求，可以设置为yes，以便能够尽可能快的释放内存 activerehashing yes ################################## INCLUDES ################################### # 指定包含其它的配置文件，可以在同一主机上多个Redis实例之间使用同一份配置文件，而同时各个实例又拥有自己的特定配置文件 # include /path/to/local.conf # include /path/to/other.conf 二、配置详解&优化 1、配置文件中单元大小的解释，不区分大小写 # Note on units: when memory size is needed, it is possible to specify # it in the usual form of 1k 5GB 4M and so forth: # # 1k => 1000 bytes # 1kb => 1024 bytes # 1m => 1000000 bytes # 1mb => 1024*1024 bytes # 1g => 1000000000 bytes # 1gb => 1024*1024*1024 bytes # # units are case insensitive so 1GB 1Gb 1gB are all the same. 2、配置模板，针对个性化配置 # 假如说你有一个可用于所有的 redis server 的标准配置模板， # 但针对某些 server 又需要一些个性化的设置， # 你可以使用 include 来包含一些其他的配置文件，这对你来说是非常有用的。 # include /path/to/local.conf # include /path/to/other.conf 3、加载模块 模块有两种加载方式， 一是在配置文件redis.conf中使用loadmodule /path/to/mymodule.so在Redis启动时加载。 另一种方式在运行时使用命令MODULE LOAD /path/to/mymodule.so加载。加载的模块可以使用命令MODULE LIST查看，使用MODULE UNLOAD mymodule卸载。 在载入的模块的时候可以传入参数，如：loadmodule mymodule.so foo bar 123456，参数会被传入模块的OnLoad方法中。 # loadmodule /path/to/my_module.so # loadmodule /path/to/other_module.so 4、安全相关bind/protected-mode 默认设置yes， 禁止公网访问redis cache，加强redis安全 它启用的条件，有两个： 1） 没有bind IP 2） 没有设置访问密码 配置redis的sentinel集群时，哨兵之间不能通信，不能进行主结节客观下线的判断，以及failover，解决呢办法sentinel.conf中加入了protected-mode no 详情说明可以见：acceptCommonHandler源码说明 关于bind设置说明 bind配置了什么ip，别人就得访问bind里面配置的ip才访问到redis服务。 bind配置的ip必须是本机的ip，一台机器可以对应多个ip地址，配置非本机的ip地址会报错，如果配置为 bind 127.0.0.1 表明只能本机访问， bind 0.0.0.0等价于 不配置 bind 即注释掉bind 想限制只有指定的主机可以连接到redis中，我们只能通过防火墙来控制，而不能通过redis中的bind参数来限制 很容易让人误解的一个配置 5、访问端口 port 6379 默认值 6、TCP 监听的最大容纳数量 tcp-backlog 511 //在高并发的环境下，你需要把这个值调高以避免客户端连接缓慢的问题。 //值的大小是受somaxconn影响，调大需要修改内核的somaxconn值，实际应该是tcp过程中accept queue队列的最大值 7、unix socket方式来接收请求 # unixsocket /tmp/redis.sock # unixsocketperm 700 //通过unixsocket配置项来指定unix socket文件的路径，并通过unixsocketperm来指定文件的权限 8、redis-client连接断开时间 timeout 0 redis-client一直没有请求发向server端，那么server端有权主动关闭这个连接，可以通过timeout来设置“空闲超时时限”，0表示永不关闭，推荐配置为300 9、tcp-keepalive 300 //tcp保持连接的时长 10、守护进程 daemonize no 默认为no //进程pid号写入至redis.conf选项pidfile设置的文件中 11、supervised no 通过其他的守护进程upstart和systemd管理Redis守护进程，这个参数是和具体的操作系统相关的。 12、pidfile /usr/local/redis/etc/redis_pid_6379.pid 配置pid文件路径。当redis以守护模式启动时，如果没有配置pidfile，pidfile默认值是/usr/local/redis/etc/redis_pid_6379.pid 13、日志等级/路径 debug（记录大量日志信息，适用于开发、测试阶段）； verbose（较多日志信息）； notice（适量日志信息，使用于生产环境）；warning（仅有部分重要、关键信息才会被记录）。 日志文件的位置，当指定为空字符串时，为标准输出，如果redis已守护进程模式运行，那么日志将会输出到 /dev/null #syslog-enabled设置为yes会把日志输出到系统日志，默认是no #syslog-enabled no #指定syslog的标示符，如果syslog-enabled是no，则这个选项无效。 # syslog-ident redis syslog-facility local0 若启用日志记录，则需要设置日志facility，可取值范围为local0~local7，表示不同的日志级别 14、databases 16 //默认数据库的数量 15、always-show-logo yes //设置是否在控制台显示redis logo图标 16、快照备份相关设置 save 900 1 save 300 10 save 60 10000 save <seconds> <changes> //指定在多长时间内，有多少次更新操作，就将数据同步到数据文件，可以多个条件配合 stop-writes-on-bgsave-error yes //后台存储存储发生错误时禁止写入，默认为yes rdbcompression yes //启动rdb文件压缩，耗费CPU资源，默认为yes，建议开启，压缩率高 rdbchecksum yes //对rdb数据进行校验，耗费CPU资源，默认为yes dbfilename dump.rdb //rdb文件名称 dir ./ //路径 17、主从复制相关配置 # replicaof <masterip> <masterport> 主节点ip和端口 # masterauth <master-password> 访问密码 replica-serve-stale-data yes replica-serve-stale-data yes，即使主从断了，从依然响应客户端的请求。 replica-serve-stale-data no，主从断开了，则从会提示客户端"SYNC with master in progress"，但有些指令还可以使用 INFO, replicaOF, AUTH, PING, SHUTDOWN, REPLCONF, ROLE, CONFIG,SUBSCRIBE, UNSUBSCRIBE, PSUBSCRIBE, PUNSUBSCRIBE, PUBLISH, PUBSUB, COMMAND, POST, HOST: and LATENCY replica-read-only yes //配置从节点是否只读 repl-diskless-sync no //以往主从复制是生成rdb文件,然后传输给从节点,配置成yes后可以不进行写磁盘直接进行复制,适用于磁盘慢网络带宽大的场景 repl-diskless-sync-delay 5//让主节点等待更多从节点来同时复制,设置过小,复制时来的从节点必须等待下一次rdb transfer 单位秒,如果小于0则启动失败 # repl-ping-replica-period 10 //从发给主的心跳周期,如果小于0则启动失败 # repl-timeout 60 多少秒没收到心跳的响应认为超时,最好设置的比 repl-ping-slave-period/repl-ping-replica-period大如果小于0则启动失败 repl-disable-tcp-nodelay no //如果设置yes,会导致主从同步有40ms滞后(linux默认),如果no,则主从同步更及时 # repl-backlog-size 1mb 复制积压大小,解决复制过程中从节点重连后不需要full sync,这个值越大,那么从节点断开到重连的时间就可以更长 # repl-backlog-ttl 3600 //复制积压的生命期,超过多长时间从节点还没重连,则释放内存 replica-priority 100 //给众多的从Redis设置优先级，在主Redis持续工作不正常的情况，优先级高的从Redis将会升级为主Redis。而编号越小，优先级越高。 比如一个主Redis有三个从Redis，优先级编号分别为10、100、25，那么编号为10的从Redis将会被首先选中升级为主Redis。 当优先级被设置为0时，这个从Redis将永远也不会被选中,默认的优先级为100 # min-replicas-to-write 3 # min-replicas-max-lag 10 //假如有大于等于3个从Redis的连接延迟大于10秒，那么主Redis就不再接受外部的写请求。 上述两个配置中有一个被置为0，则这个特性将被关闭。默认情况下min-slaves-to-write为0，而min-slaves-max-lag为10 # replica-announce-ip 5.5.5.5 # replica-announce-port 1234 Redis master 可以通过不同方式列出连接上来的 replicas 节点的地址和端口。 如 Redis Sentinel 等会使用 “INFO replication” 命令来获取 replica 实例信息。 master 的 “ROLE“ 命令也会提供此信息。 这个信息一般来说是通过 replica 节点通过一下方式获取然后报告上来的： IP：通过自动识别连接到 Socket 的信息自动获取 Port：一般来说这个值就是 replicas 节点用来接受客户端的连接的监听端口 但是，若启用了端口转发或者 NAT，可能需要其他地址和端口才能连接到 replicas 节点。 这种情况下，需要设置这两个选项，这样 replicas 就会用这两个选项设置的值覆盖默认行为获取的值，然后报告给 master 节点。 根据实际情况，你可以只设置其中某个选项，而不用两个选项都设置。 18、安全 # requirepass foobared 设置Redis连接密码，如果配置了连接密码，客户端在连接Redis时需要通过AUTH <password>命令提供密码，默认关闭 ps：由于 Redis 非常快，外部用户若进行暴力破解，每秒能尝试超过 150k 个密码。因此你需要使用强度非常高的密码才能保证密码不容易被暴力破解掉。 rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52 在共享环境下，可以通过 rename-command 命令将一些危险的命令进行重命名。 如上所示将 CONFIG 命令重命名为难以猜测的命令。 可以通过将命令重命名为空字符串从而将其完全 ”kill“ 掉，如 rename-command CONFIG "" rename-command 命令会被记录到日志和 AOF 文件中或者传输到 replicas 节点，而这可能会是一个安全问题。 19、客户端数量 # maxclients 10000 设置同一时间最大客户端连接数，默认无限制，Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件描述符数，如果设置 maxclients 0，表示不作限制。当客户端连接数到达限制时，Redis会关闭新的连接并向客户端返回max number of clients reached错误信息，上限值和系统的句柄连接数相关。 20、内存设置相关 # maxmemory <bytes> // 指定Redis最大内存限制，Redis新的vm机制，会把Key存放内存，Value会存放在swap区,意义不大。 redis内存管理策略，默认为noeviction 1.volatile-lru(least recently used):最近最少使用算法，从设置了过期时间的键中选择空转时间最长的键值对清除掉； 2.volatile-lfu(least frequently used):最近最不经常使用算法，从设置了过期时间的键中选择某段时间之内使用频次最小的键值对清除掉； 3.volatile-ttl:从设置了过期时间的键中选择过期时间最早的键值对清除； 4.volatile-random:从设置了过期时间的键中，随机选择键进行清除； 5.allkeys-lru:最近最少使用算法，从所有的键中选择空转时间最长的键值对清除； 6.allkeys-lfu:最近最不经常使用算法，从所有的键中选择某段时间之内使用频次最少的键值对清除； 7.allkeys-random:所有的键中，随机选择键进行删除； 8.noeviction:不做任何的清理工作，在redis的内存超过限制之后，所有的写入操作都会返回错误；但是读操作都能正常的进行; # maxmemory-policy noeviction maxmemory-samples 5个key作为样本池进行抽样清理，默认值5为最优 # replica-ignore-maxmemory yes replica 节点会忽略 maxmemory 设置 21、惰性删除 lazyfree-lazy-eviction no lazyfree-lazy-expire no lazyfree-lazy-server-del no replica-lazy-flush no 默认设置为no，个人感觉应该全部设置yes，代码会根据实际情况进行判断，是否进行惰性删除。 22、aof持久化配置 appendonly no appendfilename "appendonly.aof" # appendfsync always appendfsync everysec # appendfsync no 1、appendfsync no 当设置appendfsync为no的时候，Redis不会主动调用fsync去将AOF日志内容同步到磁盘，所以这一切就完全依赖于操作系统的调试了。对大多数Linux操作系统，是每30秒进行一次fsync，将缓冲区中的数据写到磁盘上。 2、appendfsync everysec 当设置appendfsync为everysec的时候，Redis会默认每隔一秒进行一次fsync调用，将缓冲区中的数据写到磁盘。但是当这一 次的fsync调用时长超过1秒时。Redis会采取延迟fsync的策略，再等一秒钟。也就是在两秒后再进行fsync，这一次的fsync就不管会执行多长时间都会进行。这时候由于在fsync时文件描述符会被阻塞，所以当前的写操作就会阻塞。 所以，结论就是：在绝大多数情况下，Redis会每隔一秒进行一次fsync。在最坏的情况下，两秒钟会进行一次fsync操作，掉数据也就1-2秒 这一操作在大多数数据库系统中被称为group commit，就是组合多次写操作的数据，一次性将日志写到磁盘。 3、appednfsync always 当设置appendfsync为always时，每一次写操作都会调用一次fsync，这时数据是最安全的，当然，由于每次都会执行fsync，所以其性能也会受到影响。 /////////////////////////////// no-appendfsync-on-rewrite no bgrewriteaof机制，在一个子进程中进行aof的重写，从而不阻塞主进程对其余命令的处理，同时解决了aof文件过大问题。 现在问题出现了，同时在执行bgrewriteaof操作和主进程写aof文件的操作，两者都会操作磁盘，而bgrewriteaof往往会涉及大量磁盘操作，这样就会造成主进程在写aof文件的时候出现阻塞的情形，现在no-appendfsync-on-rewrite参数出场了。如果该参数设置为no，是最安全的方式，不会丢失数据，但是要忍受阻塞的问题。如果设置为yes呢？这就相当于将appendfsync设置为no，这说明并没有执行磁盘操作，只是写入了缓冲区，因此这样并不会造成阻塞（因为没有竞争磁盘），但是如果这个时候redis挂掉，就会丢失数据。丢失多少数据呢？在linux的操作系统的默认设置下，最多会丢失30s的数据。 因此，如果应用系统无法忍受延迟，而可以容忍少量的数据丢失，则设置为yes。如果应用系统无法忍受数据丢失，则设置为no。 /////////////// rewrite执行临界值 auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb 自动重写 append only file 选项。 当 AOF 文件增长到一定比例后，Redis 可以自动通过隐式调用 BGREWRITEAOF 命令来重写 AOF 文件。 Redis 会记录上一次 rewrite 的 AOF 文件大小（若从未进行 rewrite，Redis 会使用启动时的 AOF 文件大小）作为基准大小。 Redis 会比较当前大小和基准大小，若当前大小大于一定比例则触发 rewrite。 为了防止增长比例到了但是总数据量还是非常小的情况就触发 rewrite，你还需要指定一个 AOF rewritten 的最小大小。 通过将 auto-aof-rewrite-percentage 设置为 0 可以禁用此功能。 /////////aof文件不完整 aof-load-truncated yes 当 Redis 启动时可能会发现 AOF 文件被截断了（不完整），这可能是由于系统崩溃了， 特别是 ext4 没有以 data=ordered 选项挂载的情况（在 Redis 崩溃而系统正常的情况下不会发生截断）。 当这种情况发生时，Redis 可以选择终止进程，或者加载 AOF 文件上尽可能多的数据（目前的默认行为）。 当 aof-load-truncated 设置为 yes， Redis 服务端在启动的时候发现加载的 AOF 文件是被截断的会发送一条日志来通知客户。 若 aof-load-truncated 设置为 no，服务端会以错误形式终止进程并拒绝启动。 这是需要用户在重启服务前使用 "redis-check-aof" 工具来修复 AOF 文件。 aof-use-rdb-preamble yes //aof,rdb混合持久化 23、lua脚本 lua-time-limit 5000 此选项用于控制 Lua 脚本的最长执行时间，单位为毫秒。 当 Lua 脚本的执行时间超出限制后，Redis 会在写入相关日志，并且向客户端返回出错。 24、redis cluster配置 # cluster-enabled yes 如果配置yes则开启集群功能，此redis实例作为集群的一个节点，否则，它是一个普通的单一的redis实例。 # cluster-config-file nodes-6379.conf 集群配置文件，但是此配置文件不能人工编辑，它是集群节点自动维护的文件，主要用于记录集群中有哪些节点、他们的状态以及一些持久化参数等，方便在重启时恢复这些状态。通常是在收到请求之后这个文件就会被更新。 # cluster-node-timeout 15000 这是集群中的节点能够失联的最大时间，超过这个时间，该节点就会被认为故障。如果主节点超过这个时间还是不可达，则用它的从节点将启动故障迁移，升级成主节点。注意，任何一个节点在这个时间之内如果还是没有连上大部分的主节点，则此节点将停止接收任何请求。一般设置为15秒即可。 # cluster-replica-validity-factor 10 如果数据太旧，集群中的不可用master的slave节点会避免成为备用master。如果slave和master失联时间超过:(node-timeout * slave-validity-factor) + repl-ping-slave-period则不会被提升为master。 如node-timeout为30秒，slave-validity-factor为10, 默认default repl-ping-slave-period为10秒,失联时间超过310秒slave就不会成为master。 较大的slave-validity-factor值可能允许包含过旧数据的slave成为master，同时较小的值可能会阻止集群选举出新master。 为了达到最大限度的高可用性，可以设置为0，即slave不管和master失联多久都可以提升为master #cluster-migration-barrier 只有在之前master有其它指定数量的工作状态下的slave节点时，slave节点才能提升为master。默认为1（即该集群至少有3个节点，1 master＋2 slaves，master宕机，仍有另外1个slave的情况下其中1个slave可以提升） 测试环境可设置为0，生成环境中至少设置为1 #cluster-require-full-coverage yes 默认情况下如果redis集群如果检测到至少有1个hash slot不可用，集群将停止查询数据。 如果所有slot恢复则集群自动恢复。 如果需要集群部分可用情况下仍可提供查询服务，设置为no。 #cluster-migration-barrier 1 只有在之前master有其它指定数量的工作状态下的slave节点时，slave节点才能提升为master。默认为1（即该集群至少有3个节点，1 master＋2 slaves，master宕机，仍有另外1个slave的情况下其中1个slave可以提升） 测试环境可设置为0，生成环境中至少设置为1 #cluster-require-full-coverage yes 默认情况下如果redis集群如果检测到至少有1个hash slot不可用，集群将停止查询数据。 如果所有slot恢复则集群自动恢复。 如果需要集群部分可用情况下仍可提供查询服务，设置为no。 #cluster-replica-no-failover no 选项设置为yes时，会阻止replicas尝试对其master在主故障期间进行故障转移 然而，master仍然可以执行手动故障转移,如果强制这样做的话。
一、编译安装 下载、解压 wget http://download.redis.io/releases/redis-3.2.8.tar.gz tar -zxvf redis-3.2.8.tar.gz cd redis-3.2.8 make 编译 编译之前 00-RELEASENOTES BUGS CONTRIBUTING COPYING deps INSTALL Makefile MANIFESTO README.md redis.conf runtest 编译完成之后，可以看到解压文件redis-3.0.7 中会有对应的src、conf等文件。 二、部署文件结构 首先为了方便管理，将 Redis 文件中的 conf 配置文件和常用命令移动到统一文件中。 创建以下文件目录 mkdir -p /usr/local/redis/bin mkdir -p /usr/local/redis/etc 切换到redis-3.2.8目录，移动redis.conf配置文件： mv /home/payn/redis-3.2.8/redis.conf /usr/local/redis/etc 继续进入到src目录执行其他文件移动： mv mkreleasehdr.sh redis-benchmark redis-check-aof redis-check-rdb redis-cli redis-sentinel redis-server redis-trib.rb /usr/local/redis/bin 三、配置和启动 redis 服务 编辑redis.conf cd /usr/local/redis/etc vi redis.conf 需要修改的参数 --后台运行 daemonize yes --端口号 port 63700 --和哪个网卡绑定，和客户端是什么网段没有关系，这里我绑定的是内网网卡, bind 192.168.25.128 -- AES("https://github.com/Tinywan/Lua-Nginx-Redis/blob/master/Redis/redis-install.md") 加密 -- 结果：b6Pbc42gP8hXPNLzZaDnhREijtn1BSVSIYTkhTXw8SuPGpWZvN5kVpVeEVBdEQDw7M/+EZuDS6FxTOtgD2QrPe6014LPEdv2DY+YSUQZ4cE= requirepass b6Pbc42gP8hXPNLzZaDnhREijtn1BSVSIYTkhTXw8SuPGpWZvN5kVpVeEVBdEQDw7M/+EZuDS6FxTOtgD2QrPe6014LPEdv2DY+YSUQZ4cE= -- db文件名 dbfilename dump63700.rdb -- log 日志文件路径 logfile "/usr/local/redis/etc/redis_63700.log" -- 安全考虑，rename-command 配置以下命令 rename-command FLUSHALL "payngithubFLUSHALL" rename-command CONFIG "payngithubCONFIG" rename-command SHUTDOWN "payngithubSHUTDOWN" rename-command DEBUG "payngithubDEBUG" 启动 redis 服务，并指定启动服务配置文件，检测运行端口，为了安全，请不要使用 root 用户去启动。 $ sudo chown -R www:www /usr/local/redis/ //赋予指定该用户组，而非root账号 $ /usr/local/redis/bin/redis-server /usr/local/redis/etc/redis6379.conf $ ps -aux | grep redis www 70764 0.6 0.1 38160 0:00 /usr/local/redis/bin/redis-server 127.0.0.1:63700 www 70768 0.0 0.0 15984 0:00 grep --color=auto redis redis-cli启动、检测重置命令是否生效（结果：配置文件已经OK）。 $ redis-cli -h 127.0.0.1 -p 63700 -a b6Pbc42gP8hXPNLzZaDnhREijtn1BSVSIYTkhTXw8SuPGpWZvN5kVpVeEVBdEQDw7M/+EZuDS6FxTOtgD2QrPe6014LPEdv2DY+YSUQZ4cE= 127.0.0.1:63700> set username tinywan OK 127.0.0.1:63700> get username "tinywan" 127.0.0.1:63700> SHUTDOWN (error) ERR unknown command 'SHUTDOWN' 127.0.0.1:63700> FLUSHALL (error) ERR unknown command 'FLUSHALL' 127.0.0.1:63700> tinywangithubFLUSHALL OK 127.0.0.1:63700> get username (nil) 127.0.0.1:63700> 远程链接出现的错误： 错误信息 xxxxxxxxxx DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients....... 修改配置文件：protected-mode yes 修改为protected-mode no 。 查看远程Redis服务器的版本 redis-cli -h 192.168.25.128 info | grep 'redis_version'。 四、Redis开机启动的方法 Linux中设置Redis开机启动的方法 环境：Ubuntu 16.04.2 LTS 编辑脚本：vim /etc/init.d/redis #!/bin/sh # # Simple Redis init.d script conceived to work on Linux systems # as it does use of the /proc filesystem. ### BEGIN INIT INFO # Provides: redis6379 # Required-Start: $local_fs $network # Required-Stop: $local_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: redis6379 # Description: penavico redis 6379 ### END INIT INFO REDISPORT=6379 # 【1】修改一 EXEC=/usr/local/bin/redis-server CLIEXEC=/usr/local/bin/redis-cli PIDFILE=/var/run/redis_${REDISPORT}.pid CONF="/usr/local/redis/etc/redis_6379.conf" # 【2】修改二 case "$1" in start) if [ -f $PIDFILE ] then echo "$PIDFILE exists, process is already running or crashed" else echo "Starting Redis server..." $EXEC $CONF fi ;; stop) if [ ! -f $PIDFILE ] then echo "$PIDFILE does not exist, process is not running" else PID=$(cat $PIDFILE) echo "Stopping ..." $CLIEXEC -p $REDISPORT shutdown while [ -x /proc/${PID} ] do echo "Waiting for Redis to shutdown ..." sleep 1 done echo "Redis stopped" fi ;; *) echo "Please use start or stop as first argument" ;; esac 注册事件，开机启动：update-rc.d redis defaults 启动服务：sudo systemctl start redis 停止服务：sudo systemctl stop redis 查看服务是否启动： ps -aux | grep redis root 1722 0.0 0.8 44752 8300 ? Ssl 13:08 0:00 /usr/local/bin/redis-server 127.0.0.1:6379 www 1730 0.0 0.1 14224 1024 pts/0 S+ 13:08 0:00 grep --color=auto redis 五、Redis关闭 命令方式关闭 redis-cli -h 127.0.0.1 -p 6379 127.0.0.1:6379> shutdown 进程号杀掉 redis ps -ef | grep redis kill -9 XXX 六、Redis数据迁移 查找RDB文件： sudo find / -name dump.rdb 进行远程拷贝备份文件： scp ./dump.rdb www@192.168.1.18:/home/www/redis/ 数据迁移步骤如下 关闭目标 Redis 服务； 将相应的 RDB 文件或者AOF文件复制过去； 设置 REDIS 的 DIR 或者开启 AOF 功能； 启动目标 REDIS 服务。