在实际的商用系统中,Redis常用的机制包括备份、回收策略、主从复制、哨兵模式、集群模式等,在保证性能的同时还要保证其高可用
首先要熟悉一下Redis的配置文件,如果实在linux系统中,配置文件是redis.conf
,而在windows中是redis.window.conf
,通常redis是部署在Linux系统的服务器中的,以Linux系统为例,如图所示
在Windows中如下图所示
Redis备份机制
Redis备份是Redis做持久化主要手段,有两种备份方式,一种是快照(snapshotting),它可以备份当前时间节点Redis在内存中的数据记录,另一种是只追加文件(Append-Only File, AOF),其作用是当Redis执行写命令后,在一定的条件下将执行过的写命令依次保存在Redis的备份文件中,将来可以依次执行被保存的命令从而恢复Redis数据
两种方式各有优缺点,快照的方式如果当前Redis数据量较大则快照备份可能会造成Redis卡顿影响当前使用,但其优点是恢复和重启速度较快,而对于AOF备份,只是追加命令,备份代价比较小,但恢复起来需要逐一执行备份的命令,恢复时间较长,并且备份的文件可能比较大
快照备份
打来配置文件,找到如下配置节点,配置项说明用中文写到了注释里
################################ SNAPSHOTTING ################################
# Save the DB to disk.
#
# save <seconds> <changes> [<seconds> <changes> ...]
#
# Redis will save the DB if the given number of seconds elapsed and it
# surpassed the given number of write operations against the DB.
#
# Snapshotting can be completely disabled with a single empty string argument
# as in following example:
#
# save ""
# 除非另有指定,否则默认情况下,Redis将会保存数据库
# Unless specified otherwise, by default Redis will save the DB:
# 下边这三个是默认规则,
# * After 3600 seconds (an hour) if at least 1 change was performed
# * After 300 seconds (5 minutes) if at least 100 changes were performed
# * After 60 seconds if at least 10000 changes were performed
#
# You can set these explicitly by uncommenting the following line.
#
# save 3600 1 300 100 60 10000
# By default Redis will stop accepting writes if RDB snapshots are enabled
# (at least one save point) and the latest background save failed.
# This will make the user aware (in a hard way) that data is not persisting
# on disk properly, otherwise chances are that no one will notice and some
# disaster will happen.
#
# If the background saving process will start working again Redis will
# automatically allow writes again.
#
# However if you have setup your proper monitoring of the Redis server
# and persistence, you may want to disable this feature so that Redis will
# continue to work as usual even if there are problems with disk,
# permissions, and so forth.
# 后台备份运行出错时停止Redis的写入命令
stop-writes-on-bgsave-error yes
# Compress string objects using LZF when dump .rdb databases?
# By default compression is enabled as it's almost always a win.
# If you want to save some CPU in the saving child set it to 'no' but
# the dataset will likely be bigger if you have compressible values or keys.
# 是否压缩备份的RDB文件
rdbcompression yes
# Since version 5 of RDB a CRC64 checksum is placed at the end of the file.
# This makes the format more resistant to corruption but there is a performance
# hit to pay (around 10%) when saving and loading RDB files, so you can disable it
# for maximum performances.
#
# RDB files created with checksum disabled have a checksum of zero that will
# tell the loading code to skip the check.
# 是否检验备份的RDB文件
rdbchecksum yes
# Enables or disables full sanitization checks for ziplist and listpack etc when
# loading an RDB or RESTORE payload. This reduces the chances of a assertion or
# crash later on while processing commands.
# Options:
# no - Never perform full sanitization
# yes - Always perform full sanitization
# clients - Perform full sanitization only for user connections.
# Excludes: RDB files, RESTORE commands received from the master
# connection, and client connections which have the
# skip-sanitize-payload ACL flag.
# The default should be 'clients' but since it currently affects cluster
# resharding via MIGRATE, it is temporarily set to 'no' by default.
#
# sanitize-dump-payload no
# The filename where to dump the DB
# 备份文件名
dbfilename dump.rdb
# Remove RDB files used by replication in instances without persistence
# enabled. By default this option is disabled, however there are environments
# where for regulations or other security concerns, RDB files persisted on
# disk by masters in order to feed replicas, or stored on disk by replicas
# in order to load them for the initial synchronization, should be deleted
# ASAP. Note that this option ONLY WORKS in instances that have both AOF
# and RDB persistence disabled, otherwise is completely ignored.
#
# An alternative (and sometimes better) way to obtain the same effect is
# to use diskless replication on both master and replicas instances. However
# in the case of replicas, diskless is not always an option.
# 如果存在主从结构,是否删除没有开启持久化的从节点的备份文件
rdb-del-sync-files no
# The working directory.
#
# The DB will be written inside this directory, with the filename specified
# above using the 'dbfilename' configuration directive.
#
# The Append Only File will also be created inside this directory.
#
# Note that you must specify a directory here, not a file name.
# 备份文件存储路径
dir ./
AOF备份
在配置文件中找到如下配置节点,配置项说明用中文写到了注释里
############################## APPEND ONLY MODE ###############################
# By default Redis asynchronously dumps the dataset on disk. This mode is
# good enough in many applications, but an issue with the Redis process or
# a power outage may result into a few minutes of writes lost (depending on
# the configured save points).
#
# The Append Only File is an alternative persistence mode that provides
# much better durability. For instance using the default data fsync policy
# (see later in the config file) Redis can lose just one second of writes in a
# dramatic event like a server power outage, or a single write if something
# wrong with the Redis process itself happens, but the operating system is
# still running correctly.
#
# AOF and RDB persistence can be enabled at the same time without problems.
# If the AOF is enabled on startup Redis will load the AOF, that is the file
# with the better durability guarantees.
#
# Please check https://redis.io/topics/persistence for more information.
# 是否使用AOF备份方式,默认为no
appendonly no
# The base name of the append only file.
#
# Redis 7 and newer use a set of append-only files to persist the dataset
# and changes applied to it. There are two basic types of files in use:
#
# - Base files, which are a snapshot representing the complete state of the
# dataset at the time the file was created. Base files can be either in
# the form of RDB (binary serialized) or AOF (textual commands).
# - Incremental files, which contain additional commands that were applied
# to the dataset following the previous file.
#
# In addition, manifest files are used to track the files and the order in
# which they were created and should be applied.
#
# Append-only file names are created by Redis following a specific pattern.
# The file name's prefix is based on the 'appendfilename' configuration
# parameter, followed by additional information about the sequence and type.
#
# For example, if appendfilename is set to appendonly.aof, the following file
# names could be derived:
#
# - appendonly.aof.1.base.rdb as a base file.
# - appendonly.aof.1.incr.aof, appendonly.aof.2.incr.aof as incremental files.
# - appendonly.aof.manifest as a manifest file.
# AOF备份方式的备份文件名
appendfilename "appendonly.aof"
# For convenience, Redis stores all persistent append-only files in a dedicated
# directory. The name of the directory is determined by the appenddirname
# configuration parameter.
# AOF备份方式的备份文件路径
appenddirname "appendonlydir"
# The fsync() call tells the Operating System to actually write data on disk
# instead of waiting for more data in the output buffer. Some OS will really flush
# data on disk, some other OS will just try to do it ASAP.
#
# Redis supports three different modes:
#
# no: don't fsync, just let the OS flush the data when it wants. Faster.
# always: fsync after every write to the append only log. Slow, Safest.
# everysec: fsync only one time every second. Compromise.
#
# The default is "everysec", as that's usually the right compromise between
# speed and data safety. It's up to you to understand if you can relax this to
# "no" that will let the operating system flush the output buffer when
# it wants, for better performances (but if you can live with the idea of
# some data loss consider the default persistence mode that's snapshotting),
# or on the contrary, use "always" that's very slow but a bit safer than
# everysec.
#
# More details please check the following article:
# http://antirez.com/post/redis-persistence-demystified.html
#
# If unsure, use "everysec".
# 下边这3个是AOF备份的频率设置:
# always表示每次写命令执行后立即追加到备份文件,消耗资源大但最安全丢失数据率极低
# everysec 每秒执行一次AOF备份,默认配置,消耗资源多,相对安全,丢失数据率较低
# no 表示将写入工作交给操作系统,由操作系统判断缓冲区大小,统一写入到AOF备份文件,消耗资源少,但不安全,容易丢数据
# appendfsync always
appendfsync everysec
# appendfsync no
# When the AOF fsync policy is set to always or everysec, and a background
# saving process (a background save or AOF log background rewriting) is
# performing a lot of I/O against the disk, in some Linux configurations
# Redis may block too long on the fsync() call. Note that there is no fix for
# this currently, as even performing fsync in a different thread will block
# our synchronous write(2) call.
#
# In order to mitigate this problem it's possible to use the following option
# that will prevent fsync() from being called in the main process while a
# BGSAVE or BGREWRITEAOF is in progress.
#
# This means that while another child is saving, the durability of Redis is
# the same as "appendfsync no". In practical terms, this means that it is
# possible to lose 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的意思是在AOF文件重写的过程中,主线程仍然可以执行fsync()操作来确保数据被立即写入磁盘
no-appendfsync-on-rewrite no
# Automatic rewrite of the append only file.
# Redis is able to automatically rewrite the log file implicitly calling
# BGREWRITEAOF when the AOF log size grows by the specified percentage.
#
# This is how it works: Redis remembers the size of the AOF file after the
# latest rewrite (if no rewrite has happened since the restart, the size of
# the AOF at startup is used).
#
# This base size is compared to the current size. If the current size is
# bigger than the specified percentage, the rewrite is triggered. Also
# you need to specify a minimal size for the AOF file to be rewritten, this
# is useful to avoid rewriting the AOF file even if the percentage increase
# is reached but it is still pretty small.
#
# Specify a percentage of zero in order to disable the automatic AOF
# rewrite feature.
# 当AOF文件扩展时文件大小按百分比扩展
auto-aof-rewrite-percentage 100
# 默认AOF文件最小64mb
auto-aof-rewrite-min-size 64mb
# An AOF file may be found to be truncated at the end during the Redis
# startup process, when the AOF data gets loaded back into memory.
# This may happen when the system where Redis is running
# crashes, especially when an ext4 filesystem is mounted without the
# data=ordered option (however this can't happen when Redis itself
# crashes or aborts but the operating system still works correctly).
#
# Redis can either exit with an error when this happens, or load as much
# data as possible (the default now) and start if the AOF file is found
# to be truncated at the end. The following option controls this behavior.
#
# If aof-load-truncated is set to yes, a truncated AOF file is loaded and
# the Redis server starts emitting a log to inform the user of the event.
# Otherwise if the option is set to no, the server aborts with an error
# and refuses to start. When the option is set to no, the user requires
# to fix the AOF file using the "redis-check-aof" utility before to restart
# the server.
#
# Note that if the AOF file will be found to be corrupted in the middle
# the server will still exit with an error. This option only applies when
# Redis will try to read more data from the AOF file but not enough bytes
# will be found.
# 当使用AOF恢复数据时,如果遇到备份的命令出错,是否忽略,如果不忽略则遇到错误命令就会停止恢复
aof-load-truncated yes
# Redis can create append-only base files in either RDB or AOF formats. Using
# the RDB format is always faster and more efficient, and disabling it is only
# supported for backward compatibility purposes.
# 是否使用和RDB文件混合的方式备份,Redis4.0以上支持
aof-use-rdb-preamble yes
# Redis supports recording timestamp annotations in the AOF to support restoring
# the data from a specific point-in-time. However, using this capability changes
# the AOF format in a way that may not be compatible with existing AOF parsers.
# Redis7.0以上支持,该项表示AOF文件中是否带有时间戳信息
aof-timestamp-enabled no
Redis内存回收策略
Redis会因为内存不足而产生错误,也可能因为回收时间太长了而导致Redis本身卡顿,应用层遇到问题,合理的回收机制非常有必要,之前的文章讲过Redis会通过定时回收和惰性回收来处理,打开Redis配置文件,找到如下配置项,配置项说明用中文写到了注释里
############################## MEMORY MANAGEMENT ################################
# Set a memory usage limit to the specified amount of bytes.
# When the memory limit is reached Redis will try to remove keys
# according to the eviction policy selected (see maxmemory-policy).
#
# If Redis can't remove keys according to the policy, or if the policy is
# set to 'noeviction', Redis will start to reply with errors to commands
# that would use more memory, like SET, LPUSH, and so on, and will continue
# to reply to read-only commands like GET.
#
# This option is usually useful when using Redis as an LRU or LFU cache, or to
# set a hard memory limit for an instance (using the 'noeviction' policy).
#
# WARNING: If you have replicas attached to an instance with maxmemory on,
# the size of the output buffers needed to feed the replicas are subtracted
# from the used memory count, so that network problems / resyncs will
# not trigger a loop where keys are evicted, and in turn the output
# buffer of replicas is full with DELs of keys evicted triggering the deletion
# of more keys, and so forth until the database is completely emptied.
#
# In short... if you have replicas attached it is suggested that you set a lower
# limit for maxmemory so that there is some free RAM on the system for replica
# output buffers (but this is not needed if the policy is 'noeviction').
# 这个配置项用于设置 Redis 实例的最大可用内存限制,无默认值,必须手动设置,不支持动态修改,即不能在运行时通过 CONFIG SET 命令来改变这个配置项的值,需要重启 Redis 才能生效。
# maxmemory <bytes>
# MAXMEMORY POLICY: how Redis will select what to remove when maxmemory
# is reached. You can select one from the following behaviors:
# 8种淘汰键值的策略
# volatile-lru -> Evict using approximated LRU, only keys with an expire set.
# allkeys-lru -> Evict any key using approximated LRU.
# volatile-lfu -> Evict using approximated LFU, only keys with an expire set.
# allkeys-lfu -> Evict any key using approximated LFU.
# volatile-random -> Remove a random key having 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 evict anything, just return an error on write operations.
# LRU means Least Recently Used
# LFU means Least Frequently Used
# volatile-lru
# 含义: 使用近似 LRU (Least Recently Used) 算法来淘汰具有过期时间设置的键。
# 特点: 只考虑设置了过期时间的键,并按照最近最少使用的顺序淘汰。
# allkeys-lru
# 含义: 使用近似 LRU 算法来淘汰任何键。
# 特点: 不考虑键是否有过期时间设置,而是按照所有键中最少使用的顺序淘汰。
# volatile-lfu
# 含义: 使用近似 LFU (Least Frequently Used) 算法来淘汰具有过期时间设置的键。
# 特点: 只考虑设置了过期时间的键,并按照最不频繁使用的顺序淘汰。
# allkeys-lfu
# 含义: 使用近似 LFU 算法来淘汰任何键。
# 特点: 不考虑键是否有过期时间设置,而是按照所有键中最不频繁使用的顺序淘汰。
# volatile-random
# 含义: 随机选择具有过期时间设置的键进行淘汰。
# 特点: 只考虑设置了过期时间的键,并随机选择一个键进行淘汰。
# allkeys-random
# 含义: 随机选择任何键进行淘汰。
# 特点: 不考虑键是否有过期时间设置,而是随机选择一个键进行淘汰。
# volatile-ttl
# 含义: 根据键的过期时间来淘汰,选择过期时间最近的键。
# 特点: 只考虑设置了过期时间的键,并按照过期时间最近的顺序淘汰。
# noeviction
# 含义: 不执行任何淘汰操作,当达到最大内存限制时,返回错误给写操作。
# 特点: 不主动淘汰任何键,而是直接拒绝新的写入操作,返回错误信息。
# 上述提到的算法都是相似度算法,不会进行精确匹配再删除
# Both LRU, LFU and volatile-ttl are implemented using approximated
# randomized algorithms.
# Note: with any of the above policies, when there are no suitable keys for
# eviction, Redis will return an error on write operations that require
# more memory. These are usually commands that create new keys, add data or
# modify existing keys. A few examples are: SET, INCR, HSET, LPUSH, SUNIONSTORE,
# SORT (due to the STORE argument), and EXEC (if the transaction includes any
# command that requires memory).
# Redis默认淘汰策略是noeviction即如果内存满了则Redis无法写入只能读取
# The default is:maxmemory-policy noeviction
# LRU, LFU and minimal TTL algorithms are not precise algorithms but approximated
# algorithms (in order to save memory), so you can tune it for speed or
# accuracy. By default Redis will check five keys and pick the one that was
# used least recently, you can change the sample size using the following
# configuration directive.
#
# The default of 5 produces good enough results. 10 Approximates very closely
# true LRU but costs more CPU. 3 is faster but not very accurate.
# 这个配置项用于控制在执行内存淘汰策略时,从候选键集中抽取样本的数量,数值越大越精确但消耗也越大
# 数值越小执行速度越快但精确度下降消耗也下降,可以在运行时通过 CONFIG SET 命令来改变这个配置项的值
# maxmemory-samples 5
# Eviction processing is designed to function well with the default setting.
# If there is an unusually large amount of write traffic, this value may need to
# be increased. Decreasing this value may reduce latency at the risk of
# eviction processing effectiveness
# 0 = minimum latency, 10 = default, 100 = process without regard to latency
# 这个配置项用于控制在执行内存淘汰策略时,连续尝试淘汰键的最大次数,可以在运行时通过 CONFIG SET 命令来改变这个配置项的值
# maxmemory-eviction-tenacity 10
# Starting from Redis 5, by default a replica will ignore its maxmemory setting
# (unless it is promoted to master after a failover or manually). It means
# that the eviction of keys will be just handled by the master, sending the
# DEL commands to the replica as keys evict in the master side.
#
# This behavior ensures that masters and replicas stay consistent, and is usually
# what you want, however if your replica is writable, or you want the replica
# to have a different memory setting, and you are sure all the writes performed
# to the replica are idempotent, then you may change this default (but be sure
# to understand what you are doing).
#
# Note that since the replica by default does not evict, it may end using more
# memory than the one set via maxmemory (there are certain buffers that may
# be larger on the replica, or data structures may sometimes take more memory
# and so forth). So make sure you monitor your replicas and make sure they
# have enough memory to never hit a real out-of-memory condition before the
# master hits the configured maxmemory setting.
# 这个配置项用于控制从节点(replica)是否忽略主节点(master)的 maxmemory 配置
# 假设主节点的maxmemory设置为100mb,而从节点的maxmemory设置为200mb并且replica-ignore-maxmemory设置为yes
# 那么从节点将忽略主节点的maxmemory 设置,并使用自己的200mb内存限制
# 支持动态修改,即可以在运行时通过 CONFIG SET 命令来改变这个配置项的值
# replica-ignore-maxmemory yes
# Redis reclaims expired keys in two ways: upon access when those keys are
# found to be expired, and also in background, in what is called the
# "active expire key". The key space is slowly and interactively scanned
# looking for expired keys to reclaim, so that it is possible to free memory
# of keys that are expired and will never be accessed again in a short time.
#
# The default effort of the expire cycle will try to avoid having more than
# ten percent of expired keys still in memory, and will try to avoid consuming
# more than 25% of total memory and to add latency to the system. However
# it is possible to increase the expire "effort" that is normally set to
# "1", to a greater value, up to the value "10". At its maximum value the
# system will use more CPU, longer cycles (and technically may introduce
# more latency), and will tolerate less already expired keys still present
# in the system. It's a tradeoff between memory, CPU and latency.
# 这个配置项用于控制 Redis 在主动检查和清理过期键时的努力程度
# 如果你希望在主动检查和清理过期键时更加积极,可以将 active-expire-effort 设置为一个较高的值;反之,如果希望减少对性能的影响,可以将其设置为一个较低的值
# 支持动态修改,即可以在运行时通过 CONFIG SET 命令来改变这个配置项的值
# active-expire-effort 1
回收超时的策略的缺点是必须指明超时的键值对,这会给开发带来更多的代码量
Redis复制
读写分离和主从同步是数据库领域中常用的技术手段,主要用于提高系统的性能和可靠性
-
读写分离是一种数据库架构设计模式,通过将数据库的读取操作和写入操作分开,减轻单一数据库的压力,提高系统的整体性能。通常的做法是设置一个主数据库用于写入操作(如插入、更新、删除),以及一个或多个从数据库用于读取操作(如查询)
-
读写分离的主要目的:提高性能:通过分散负载,减少单一数据库的压力;提高可用性:即使主数据库不可用,从数据库仍然可以提供读取服务;数据备份:从数据库可以作为主数据库的热备份,以防主数据库发生故障。
-
读写分离常见场景包括高并发读取:当应用的读取操作远多于写入操作时,可以通过读写分离来提高读取性能;数据安全性:通过主从同步,可以在不影响主数据库性能的情况下,实现数据的实时备份
-
主从同步是指主数据库(Master)将数据更改同步到一个或多个从数据库(Slave)的过程。主数据库负责接收客户端的写入操作,然后将这些更改发送给从数据库,使从数据库的数据与主数据库保持一致。
-
主从同步工作原理:首先主数据库记录所有更改操作到二进制日志(Binary Log)中,然后从数据库通过网络连接到主数据库,获取二进制日志中的更改信息,最后从数据库解析并应用这些更改,使数据保持一致
-
主从同步特点:异步复制:从数据库通常异步地复制数据,这意味着数据同步可能存在延迟;数据一致性:由于异步复制的存在,从数据库的数据可能不是实时的,这可能会影响某些需要强一致性的- - 主从同步场景
-
主从同步场景:负载均衡:通过将读取操作分配到多个从数据库,可以分散读取负载;容灾备份:从数据库可以用作主数据库的备份,以防主数据库发生故障;扩展性:随着业务的增长,可以通过添加更多的从数据库来扩展读取能力。
应用示例
- MySQL 主从同步:在 MySQL 中,主从同步可以通过配置文件来实现。主数据库需要开启二进制日志,并在从数据库上配置指向主数据库的复制源;监控:可以使用 MySQL 提供的工具来监控主从同步的状态,确保数据同步正常进行。
Redis 主从同步:在 Redis 中,主从同步是通过配置文件或命令行来设置的。主数据库通过slaveof命令来配置从数据库;异步复制:Redis 的主从同步也是异步的,从数据库通过向主数据库发送命令请求来获取数据更新。
注意事项:由于主从同步是异步的,从数据库的数据可能不是最新的,这可能会影响到需要强一致性的场景;在主数据库发生故障时,需要手动或自动地将从数据库提升为主数据库,这通常称为故障转移;在某些场景下,可能需要采取措施来确保数据的一致性,例如通过延迟读取或二次查询等方式。
Redis主从同步配置
找到如下配置项,配置项说明用中文写到了注释里
################################# REPLICATION #################################
# Master-Replica replication. Use replicaof to make a Redis instance a copy of
# another Redis server. A few things to understand ASAP about Redis replication.
#
# +------------------+ +---------------+
# | Master | ---> | Replica |
# | (receive writes) | | (exact copy) |
# +------------------+ +---------------+
#
# 1) Redis replication is asynchronous, but you can configure a master to
# stop accepting writes if it appears to be not connected with at least
# a given number of replicas.
# 2) Redis replicas are able to perform a partial resynchronization with the
# master if the replication link is lost for a relatively small amount of
# time. You may want to configure the replication backlog size (see the next
# sections of this file) with a sensible value depending on your needs.
# 3) Replication is automatic and does not need user intervention. After a
# network partition replicas automatically try to reconnect to masters
# and resynchronize with them.
# Redis 中用于配置从节点(replica)与主节点(master)之间复制关系的命令。通过这个命令,可以从节点指定它要复制的主节点的 IP 地址和端口号
# 当从节点执行 replicaof <masterip> <masterport> 命令时,它将开始与指定的主节点建立复制关系。从节点将连接到主节点,并开始接收主节点发送的数据更新,从而保持数据的一致性
# replicaof <masterip> <masterport>
# If the master is password protected (using the "requirepass" configuration
# directive below) it is possible to tell the replica to authenticate before
# starting the replication synchronization process, otherwise the master will
# refuse the replica request.
# 从节点(replica)连接到主节点(master)时所需的密码认证的命令。通过这个命令,可以从节点指定连接到主节点时需要使用的密码
# 当从节点执行 masterauth <master-password> 命令时,它将使用指定的密码来连接主节点。如果主节点启用了密码认证,从节点必须正确设置 masterauth 命令以使用正确的密码才能成功建立复制关系
# masterauth <master-password>
#
# However this is not enough if you are using Redis ACLs (for Redis version
# 6 or greater), and the default user is not capable of running the PSYNC
# command and/or other commands needed for replication. In this case it's
# better to configure a special user to use with replication, and specify the
# masteruser configuration as such:
# 当主节点启用了 ACLs,并且默认用户不具备执行复制所需的权限时,需要创建一个具有相应权限的用户,并通过 masteruser 配置项指定该用户
# Access Control Lists (ACLs) 功能,允许管理员更精细地控制用户可以执行的操作。当使用 ACLs 时,如果默认用户不具备执行 PSYNC 命令或其他复制所需命令的能力,就需要创建一个专门的用户来处理复制任务
# 通过使用 masteruser 配置项,可以确保从节点在连接到主节点时使用正确的用户,这对于实现安全的复制关系非常重要,尤其是在启用了 ACLs 的情况下
# masteruser <username>
#
# When masteruser is specified, the replica will authenticate against its
# master using the new AUTH form: AUTH <username> <password>.
# When a replica loses its connection with the master, or when the replication
# is still in progress, the replica can act in two different ways:
#
# 1) if replica-serve-stale-data is set to 'yes' (the default) the replica will
# still reply to client requests, possibly with out of date data, or the
# data set may just be empty if this is the first synchronization.
#
# 2) If replica-serve-stale-data is set to 'no' the replica will reply with error
# "MASTERDOWN Link with MASTER is down and replica-serve-stale-data is set to 'no'"
# to all data access commands, excluding commands such as:
# INFO, REPLICAOF, AUTH, SHUTDOWN, REPLCONF, ROLE, CONFIG, SUBSCRIBE,
# UNSUBSCRIBE, PSUBSCRIBE, PUNSUBSCRIBE, PUBLISH, PUBSUB, COMMAND, POST,
# HOST and LATENCY.
# 这个配置项用于控制从节点(replica)在与主节点(master)失去连接后是否继续提供服务,支持动态修改,即可以在运行时通过 CONFIG SET 命令来改变这个配置项的值
# 当 replica-serve-stale-data 设置为 yes 时,意味着即使从节点与主节点失去连接,它仍然会继续提供服务。这意味着从节点将继续响应客户端的读取请求,尽管它的数据可能不是最新的
replica-serve-stale-data yes
# You can configure a replica instance to accept writes or not. Writing against
# a replica instance may be useful to store some ephemeral data (because data
# written on a replica will be easily deleted after resync with the master) but
# may also cause problems if clients are writing to it because of a
# misconfiguration.
#
# Since Redis 2.6 by default replicas are read-only.
#
# Note: read only replicas are not designed to be exposed to untrusted clients
# on the internet. It's just a protection layer against misuse of the instance.
# Still a read only replica exports by default all the administrative commands
# such as CONFIG, DEBUG, and so forth. To a limited extent you can improve
# security of read only replicas using 'rename-command' to shadow all the
# administrative / dangerous commands.
# 这个配置项用于控制从节点(replica)是否只接受读取请求,支持动态修改,即可以在运行时通过 CONFIG SET 命令来改变这个配置项的值
# 当 replica-read-only 设置为 yes 时,意味着从节点将只接受读取请求,并拒绝任何写入请求。这有助于确保数据的一致性,并避免从节点上的数据与主节点的数据产生冲突
replica-read-only yes
# Replication SYNC strategy: disk or socket.
#
# New replicas and reconnecting replicas that are not able to continue the
# replication process just receiving differences, need to do what is called a
# "full synchronization". An RDB file is transmitted from the master to the
# replicas.
#
# The transmission can happen in two different ways:
#
# 1) Disk-backed: The Redis master creates a new process that writes the RDB
# file on disk. Later the file is transferred by the parent
# process to the replicas incrementally.
# 2) Diskless: The Redis master creates a new process that directly writes the
# RDB file to replica sockets, without touching the disk at all.
#
# With disk-backed replication, while the RDB file is generated, more replicas
# can be queued and served with the RDB file as soon as the current child
# producing the RDB file finishes its work. With diskless replication instead
# once the transfer starts, new replicas arriving will be queued and a new
# transfer will start when the current one terminates.
#
# When diskless replication is used, the master waits a configurable amount of
# time (in seconds) before starting the transfer in the hope that multiple
# replicas will arrive and the transfer can be parallelized.
#
# With slow disks and fast (large bandwidth) networks, diskless replication
# works better.
# 这个配置项用于控制从节点(replica)与主节点(master)进行全量同步时是否使用磁盘缓存,不支持动态修改,即不能在运行时通过 CONFIG SET 命令来改变这个配置项的值
# 当repl-diskless-sync设置为yes时,意味着从节点与主节点进行全量同步时将直接通过网络传输数据,而不使用磁盘缓存。这种模式可以减少磁盘I/O操作,提高同步效率,但也可能导致更高的网络带宽使用
# 如果你希望提高从节点与主节点之间的同步效率,尤其是在磁盘 I/O 成为瓶颈的情况下,可以考虑将 repl-diskless-sync 设置为 yes。这有助于提高系统的性能,特别是在网络带宽充足的环境下
repl-diskless-sync yes
# When diskless replication is enabled, it is possible to configure the delay
# the server waits in order to spawn the child that transfers the RDB via socket
# to the replicas.
#
# This is important since once the transfer starts, it is not possible to serve
# new replicas arriving, that will be queued for the next RDB transfer, so the
# server waits a delay in order to let more replicas arrive.
#
# The delay is specified in seconds, and by default is 5 seconds. To disable
# it entirely just set it to 0 seconds and the transfer will start ASAP.
# 这个配置项用于控制从节点(replica)与主节点(master)进行无磁盘缓存的全量同步时的延迟时间,不支持动态修改,即不能在运行时通过 CONFIG SET 命令来改变这个配置项的值
# 当 repl-diskless-sync-delay 设置为 5 时,意味着从节点与主节点进行无磁盘缓存的全量同步时,将等待 5 秒后再开始同步过程。这段时间内,从节点将继续接收主节点的增量更新,从而减少全量同步的数据量
repl-diskless-sync-delay 5
# When diskless replication is enabled with a delay, it is possible to let
# the replication start before the maximum delay is reached if the maximum
# number of replicas expected have connected. Default of 0 means that the
# maximum is not defined and Redis will wait the full delay.
# 这个配置项用于限制主节点(master)在进行无磁盘缓存的全量同步时可以同时处理的最大从节点(replica)数量,不支持动态修改,即不能在运行时通过 CONFIG SET 命令来改变这个配置项的值
# 当 repl-diskless-sync-max-replicas 设置为 0 时,意味着不限制主节点进行无磁盘缓存的全量同步时可以同时处理的最大从节点数量。默认情况下,主节点可以同时处理任意数量的从节点进行无磁盘缓存的全量同步
# 如果你希望限制主节点进行无磁盘缓存的全量同步时可以同时处理的最大从节点数量,可以将 repl-diskless-sync-max-replicas 设置为一个适当的值。这有助于在资源有限的情况下更好地控制同步过程
repl-diskless-sync-max-replicas 0
# -----------------------------------------------------------------------------
# WARNING: RDB diskless load is experimental. Since in this setup the replica
# does not immediately store an RDB on disk, it may cause data loss during
# failovers. RDB diskless load + Redis modules not handling I/O reads may also
# cause Redis to abort in case of I/O errors during the initial synchronization
# stage with the master. Use only if you know what you are doing.
# -----------------------------------------------------------------------------
#
# Replica can load the RDB it reads from the replication link directly from the
# socket, or store the RDB to a file and read that file after it was completely
# received from the master.
#
# In many cases the disk is slower than the network, and storing and loading
# the RDB file may increase replication time (and even increase the master's
# Copy on Write memory and replica buffers).
# However, parsing the RDB file directly from the socket may mean that we have
# to flush the contents of the current database before the full rdb was
# received. For this reason we have the following options:
#
# "disabled" - Don't use diskless load (store the rdb file to the disk first)
# "on-empty-db" - Use diskless load only when it is completely safe.
# "swapdb" - Keep current db contents in RAM while parsing the data directly
# from the socket. Replicas in this mode can keep serving current
# data set while replication is in progress, except for cases where
# they can't recognize master as having a data set from same
# replication history.
# Note that this requires sufficient memory, if you don't have it,
# you risk an OOM kill.
# 这个配置项用于控制从节点(replica)加载主节点(master)的 RDB 快照文件时是否使用无磁盘缓存的方式
# 不支持动态修改,即不能在运行时通过CONFIG SET命令来改变这个配置项的值
# 当 repl-diskless-load 设置为 disabled 时,意味着从节点加载主节点的 RDB 快照文件时将使用传统的磁盘缓存方式。这种方式会将接收到的数据先写入磁盘,然后再加载到内存中
# 如果你希望减少磁盘I/O操作,提高加载效率,特别是在网络带宽充足的环境下,可以考虑将repl-diskless-load设置为enabled。这有助于提高系统的性能,特别是在网络带宽充足的环境中
repl-diskless-load disabled
# Master send PINGs to its replicas in a predefined interval. It's possible to
# change this interval with the repl_ping_replica_period option. The default
# value is 10 seconds.
# 这个配置项用于控制主节点(master)向从节点(replica)发送心跳(ping)消息的时间间隔,支持动态修改,即可以在运行时通过 CONFIG SET 命令来改变这个配置项的值
# 当repl-ping-replica-period设置为10时,意味着主节点每隔10秒会向从节点发送一次心跳消息。这些心跳消息用于监控从节点的状态,并检测从节点是否仍然活跃
# 如果你希望调整主节点向从节点发送心跳消息的时间间隔,可以根据实际需求设置repl-ping-replica-period。这有助于更好地监控从节点的状态,特别是在需要更频繁地检查从节点活动性的情况下
# repl-ping-replica-period 10
# The following option sets the replication timeout for:
#
# 1) Bulk transfer I/O during SYNC, from the point of view of replica.
# 2) Master timeout from the point of view of replicas (data, pings).
# 3) Replica timeout from the point of view of masters (REPLCONF ACK pings).
#
# It is important to make sure that this value is greater than the value
# specified for repl-ping-replica-period otherwise a timeout will be detected
# every time there is low traffic between the master and the replica. The default
# value is 60 seconds.
# 这个配置项用于控制主节点(master)与从节点(replica)之间的通信超时时间,支持动态修改,即可以在运行时通过 CONFIG SET 命令来改变这个配置项的值
# 当 repl-timeout 设置为 60 时,意味着主节点与从节点之间的通信将在 60 秒后超时。如果在这段时间内没有收到从节点的响应,主节点将认为从节点已断开连接,并采取相应的措施
# 如果你希望调整主节点与从节点之间的通信超时时间,可以根据实际需求设置 repl-timeout。这有助于更好地控制复制过程中的超时行为,特别是在需要更长或更短的超时时间的情况下
# repl-timeout 60
# Disable TCP_NODELAY on the replica socket after SYNC?
#
# If you select "yes" Redis will use a smaller number of TCP packets and
# less bandwidth to send data to replicas. But this can add a delay for
# the data to appear on the replica side, up to 40 milliseconds with
# Linux kernels using a default configuration.
#
# If you select "no" the delay for data to appear on the replica side will
# be reduced but more bandwidth will be used for replication.
#
# By default we optimize for low latency, but in very high traffic conditions
# or when the master and replicas are many hops away, turning this to "yes" may
# be a good idea.
# 这个配置项用于控制主节点(master)与从节点(replica)之间的TCP连接是否禁用TCP_NODELAY选项,不支持动态修改,即不能在运行时通过 CONFIG SET 命令来改变这个配置项的值
# 当repl-disable-tcp-nodelay设置为no时,意味着主节点与从节点之间的TCP连接不会禁用TCP_NODELAY选项。这通常意味着数据包将被尽可能快地发送出去,而不是等待足够多的数据来填充整个数据包
# 如果你希望优化主节点与从节点之间的数据传输性能,特别是在需要快速传输数据的情况下,可以将repl-disable-tcp-nodelay设置为no。这有助于提高系统的性能,特别是在需要低延迟传输的环境中
repl-disable-tcp-nodelay no
# Set the replication backlog size. The backlog is a buffer that accumulates
# replica data when replicas are disconnected for some time, so that when a
# replica wants to reconnect again, often a full resync is not needed, but a
# partial resync is enough, just passing the portion of data the replica
# missed while disconnected.
# The bigger the replication backlog, the longer the replica can endure the
# disconnect and later be able to perform a partial resynchronization.
# The backlog is only allocated if there is at least one replica connected.
# 这个配置项用于控制主节点(master)用于存储待同步给从节点(replica)的命令缓冲区大小,不支持动态修改,即不能在运行时通过 CONFIG SET 命令来改变这个配置项的值
# 当repl-backlog-size设置为1mb时,意味着主节点将分配 1MB 的内存空间用于存储待同步给从节点的命令。这些命令会在从节点与主节点断开连接后重新连接时进行重放,以确保数据的一致性
# 如果你希望调整主节点用于存储待同步给从节点的命令缓冲区大小,可以根据实际需求设置repl-backlog-size。这有助于更好地控制复制过程中的缓冲区大小,特别是在需要更大或更小的缓冲区时
# repl-backlog-size 1mb
# After a master has no connected replicas for some time, the backlog will be
# freed. The following option configures the amount of seconds that need to
# elapse, starting from the time the last replica disconnected, for the backlog
# buffer to be freed.
#
# Note that replicas never free the backlog for timeout, since they may be
# promoted to masters later, and should be able to correctly "partially
# resynchronize" with other replicas: hence they should always accumulate backlog.
#
# A value of 0 means to never release the backlog.
# 这个配置项用于控制主节点(master)保存待同步给从节点(replica)的命令缓冲区的有效时间,不支持动态修改,即不能在运行时通过 CONFIG SET 命令来改变这个配置项的值
# 当repl-backlog-ttl设置为3600时,意味着主节点将保留待同步给从节点的命令缓冲区最多3600秒(1 小时)。如果在这段时间内从节点没有重新连接并请求同步,这些命令将被丢弃
# 如果你希望调整主节点保存待同步给从节点的命令缓冲区的有效时间,可以根据实际需求设置 repl-backlog-ttl。这有助于更好地控制复制过程中缓冲区的有效时间,特别是在需要更长或更短的有效时间的情况下
# repl-backlog-ttl 3600
# The replica priority is an integer number published by Redis in the INFO
# output. It is used by Redis Sentinel in order to select a replica to promote
# into a master if the master is no longer working correctly.
#
# A replica with a low priority number is considered better for promotion, so
# for instance if there are three replicas with priority 10, 100, 25 Sentinel
# will pick the one with priority 10, that is the lowest.
#
# However a special priority of 0 marks the replica as not able to perform the
# role of master, so a replica with priority of 0 will never be selected by
# Redis Sentinel for promotion.
#
# By default the priority is 100.
# 这个配置项用于控制从节点(replica)在故障转移(failover)过程中的优先级,支持动态修改,即可以在运行时通过CONFIG SET命令来改变这个配置项的值
# 当replica-priority设置为 100 时,意味着该从节点具有中等的优先级。在故障转移过程中,具有较低数值的优先级的从节点更有可能被选为主节点(master)
# 如果你希望调整从节点在故障转移过程中的优先级,可以根据实际需求设置replica-priority。这有助于更好地控制故障转移过程中从节点的选择顺序,特别是在需要优先选择某些从节点作为新的主节点的情况下
replica-priority 100
# The propagation error behavior controls how Redis will behave when it is
# unable to handle a command being processed in the replication stream from a master
# or processed while reading from an AOF file. Errors that occur during propagation
# are unexpected, and can cause data inconsistency. However, there are edge cases
# in earlier versions of Redis where it was possible for the server to replicate or persist
# commands that would fail on future versions. For this reason the default behavior
# is to ignore such errors and continue processing commands.
#
# If an application wants to ensure there is no data divergence, this configuration
# should be set to 'panic' instead. The value can also be set to 'panic-on-replicas'
# to only panic when a replica encounters an error on the replication stream. One of
# these two panic values will become the default value in the future once there are
# sufficient safety mechanisms in place to prevent false positive crashes.
#
# propagation-error-behavior ignore
# Replica ignore disk write errors controls the behavior of a replica when it is
# unable to persist a write command received from its master to disk. By default,
# this configuration is set to 'no' and will crash the replica in this condition.
# It is not recommended to change this default, however in order to be compatible
# with older versions of Redis this config can be toggled to 'yes' which will just
# log a warning and execute the write command it got from the master.
# 这个配置项用于控制从节点(replica)在遇到磁盘写入错误时的行为,不支持动态修改,即不能在运行时通过 CONFIG SET 命令来改变这个配置项的值
# 当replica-ignore-disk-write-errors设置为no时,意味着从节点在遇到磁盘写入错误时将停止复制过程,并记录错误。这种行为有助于确保数据的一致性和完整性
# 如果你希望确保数据的一致性和完整性,在遇到磁盘写入错误时,可以将 replica-ignore-disk-write-errors 设置为 no。这有助于提高系统的数据一致性和性能,特别是在数据完整性和一致性至关重要的情况下
# replica-ignore-disk-write-errors no
# -----------------------------------------------------------------------------
# By default, Redis Sentinel includes all replicas in its reports. A replica
# can be excluded from Redis Sentinel's announcements. An unannounced replica
# will be ignored by the 'sentinel replicas <master>' command and won't be
# exposed to Redis Sentinel's clients.
#
# This option does not change the behavior of replica-priority. Even with
# replica-announced set to 'no', the replica can be promoted to master. To
# prevent this behavior, set replica-priority to 0.
#
# replica-announced yes
# It is possible for a master to stop accepting writes if there are less than
# N replicas connected, having a lag less or equal than M seconds.
#
# The N replicas need to be in "online" state.
#
# The lag in seconds, that must be <= the specified value, is calculated from
# the last ping received from the replica, that is usually sent every second.
#
# This option does not GUARANTEE that N replicas will accept the write, but
# will limit the window of exposure for lost writes in case not enough replicas
# are available, to the specified number of seconds.
#
# For example to require at least 3 replicas with a lag <= 10 seconds use:
# 这个配置项用于控制主节点(master)在写入操作前至少需要有多少个从节点(replica)可用,支持动态修改,即可以在运行时通过 CONFIG SET 命令来改变这个配置项的值
# 当 min-replicas-to-write 设置为 3 时,意味着主节点在执行写入操作之前,至少需要有 3 个从节点可用。如果当前可用的从节点数量少于 3 个,则写入操作将被延迟,直到有足够的从节点可用为止
# 如果你希望提高系统的高可用性和数据一致性,在执行写入操作前至少需要有特定数量的从节点可用,可以根据实际需求设置 min-replicas-to-write。这有助于更好地控制写入操作的执行条件,特别是在需要确保数据一致性和可靠性的情况下
# min-replicas-to-write 3
# 这个配置项用于控制主节点(master)在写入操作前考虑的从节点(replica)的最大滞后时间,支持动态修改,即可以在运行时通过 CONFIG SET 命令来改变这个配置项的值
# 当 min-replicas-max-lag 设置为 10 时,意味着主节点在执行写入操作之前,至少需要有满足min-replicas-to-write数量的从节点,并且这些从节点的滞后时间不超过10秒。如果从节点的滞后时间超过 10 秒,则这些从节点将不被视为有效的从节点
# 如果你希望提高系统的高可用性和数据一致性,在执行写入操作前考虑从节点的最大滞后时间,可以根据实际需求设置 min-replicas-max-lag。这有助于更好地控制写入操作的执行条件,特别是在需要确保数据一致性和可靠性的情况下
# min-replicas-max-lag 10
#
# Setting one or the other to 0 disables the feature.
#
# By default min-replicas-to-write is set to 0 (feature disabled) and
# min-replicas-max-lag is set to 10.
# A Redis master is able to list the address and port of the attached
# replicas in different ways. For example the "INFO replication" section
# offers this information, which is used, among other tools, by
# Redis Sentinel in order to discover replica instances.
# Another place where this info is available is in the output of the
# "ROLE" command of a master.
#
# The listed IP address and port normally reported by a replica is
# obtained in the following way:
#
# IP: The address is auto detected by checking the peer address
# of the socket used by the replica to connect with the master.
#
# Port: The port is communicated by the replica during the replication
# handshake, and is normally the port that the replica is using to
# listen for connections.
#
# However when port forwarding or Network Address Translation (NAT) is
# used, the replica may actually be reachable via different IP and port
# pairs. The following two options can be used by a replica in order to
# report to its master a specific set of IP and port, so that both INFO
# and ROLE will report those values.
#
# There is no need to use both the options if you need to override just
# the port or the IP address.
# 这个配置项用于控制从节点(replica)向主节点(master)报告其 IP 地址,支持动态修改,即可以在运行时通过 CONFIG SET 命令来改变这个配置项的值
# 当replica-announce-ip设置为5.5.5.5时,意味着从节点将向主节点报告其IP地址为5.5.5.5。这有助于主节点了解从节点的位置,特别是在从节点位于不同的网络环境中时
# 如果你希望从节点向主节点报告其 IP 地址,可以根据实际需求设置 replica-announce-ip。这有助于提高复制过程的可靠性和效率,特别是在从节点位于不同的网络环境时
# replica-announce-ip 5.5.5.5
# 这个配置项用于控制从节点(replica)向主节点(master)报告其监听的端口号,支持动态修改,即可以在运行时通过 CONFIG SET 命令来改变这个配置项的值
# 当 replica-announce-port 设置为 1234 时,意味着从节点将向主节点报告其监听的端口号为 1234。这有助于主节点了解从节点的端口信息,特别是在从节点位于不同的网络环境中时
# 如果你希望从节点向主节点报告其监听的端口号,可以根据实际需求设置 replica-announce-port。这有助于提高复制过程的可靠性和效率,特别是在从节点位于不同的网络环境时
# replica-announce-port 1234
在配置文件中还有个配置bind 0.0.0.0
默认为127.0.0.1
,只允许本机访问,需要修改为0.0.0.0
Redis主从同步过程
- 首先要保证Master服务器开启,开启主从同步后,Slave通过命令或者重启配置项与Master建立联系
- 当从服务器启动时,读取同步配置,根据配置决定是否使用当前数据响应客户端,然后发送SYNC命令,主服务器接收到同步命令时,就会执行bgsave命令备份数据,但不会拒绝客户端的读写,而是将来自客户端的写命令写入缓冲区,从服务器未收到主服务器备份的快照文件时,会根据其配置决定使用现有数据响应或者拒绝客户端请求
- 当bgsave命令被主服务器执行完后,开始向从服务器发送备份文件,这个时候从服务器就会丢弃所有现有数据,开始载入主服务器发送的快照文件
- 当主服务器发送完备份文件后,从服务器就开始执行写入命令,此时就会把bgsave执行之后的缓存区内的写命令也发送给从服务器,从服务器完成备份文件解析,就开始像往常一样接收命令
- 缓冲区的命令发送完成后,主服务器执行完一条写命令,就向从服务器发送同步写入命令,从服务器就和主服务器保持一致了,而从服务器是完成主服务器发送的缓冲区命令后,就开始等待主服务器的命令
而当从机比较多的情况下,都从主机同步,则会影响主机的性能,出现频繁等待和多次执行bgsave命令,这个时候可以考虑主从链同步的机制,如下图所示
Redis哨兵模式
从名字上就能理解,在Redis服务器很多,并且有主从关系,因此哨兵以一个独立的进程存在,通过发送命令来监控每个Redis服务是否正常
其工作逻辑大致是:通过发送命令,让Redis服务器返回其运行状态,包括主服务器和从服务器,而当哨兵监测到主机出现故障后,会自动将其中一台从服务器切换成主服务器,然后通过发布订阅模式通知其他从服务器,修改配置文件,让它们切换新的主服务器,而在实际使用过程中,可能哨兵进程本身出现问题,因此就可能还需要多哨兵模式,在监控Redis服务的同时,各哨兵之间也互相监控,如下图所示
然而这其中又会存在问题,假设Redis主服务器出现问题,有个哨兵监测到主服务器出了故障,当时并不会直接操作故障切换,仅仅是一个哨兵主观的认为主服务器已经不可用了,这个现象被称为主观下线,当其他的哨兵也监测到Redis主服务器出现故障,并且有一定数量的哨兵认为主服务器不可用后,哨兵之间就会形成一次投票,通过哨兵之间的投票机制,选出新的主服务器后,通过发布订阅的方式让各个哨兵对自己监控的服务器进行切换主服务器操作,这个过程称为客观下线
配置哨兵模式
如下表所示3个Redis服务,1主2从3个哨兵进程
首先Redis服务的配置,在redis.conf
中,有几个关于远程连接的配置,如下所示
# 在 Redis 中,protected-mode 配置项的设置决定了是否需要密码来进行管理操作,不支持动态修改,即不能在运行时通过 CONFIG SET 命令来改变这个配置项的值
# protected-mode yes: 当 protected-mode 设置为 yes 时,Redis 处于受保护模式。在这种模式下,Redis 要求客户端在执行某些管理命令(如 CONFIG、SHUTDOWN 等)之前必须提供正确的密码。这是默认设置,旨在提高安全性。
# protected-mode no: 当 protected-mode 设置为 no 时,Redis 将禁用受保护模式。在这种模式下,Redis 允许任何客户端无需密码即可执行所有命令,包括管理命令。这降低了安全性,但提高了便利性
# 如果你希望提高 Redis 的安全性,应该将 protected-mode 设置为 yes。这样,客户端在执行管理命令之前需要提供正确的密码。在生产环境中,通常推荐使用 protected-mode yes 来增强安全性
# protected-mode no
# 在 Redis 的配置文件 redis.conf 中,bind 配置项用于指定 Redis 服务绑定的 IP 地址或主机名。bind 项的作用是设定 Redis 服务监听的网络接口,不支持动态修改,即不能在运行时通过 CONFIG SET 命令来改变这个配置项的值
# bind 0.0.0.0: 当 bind 设置为 0.0.0.0 时,意味着 Redis 服务将监听所有可用的网络接口。这使得 Redis 服务可以从任何 IP 地址访问,包括远程客户端。
# bind 127.0.0.1: 当 bind 设置为 127.0.0.1 时,默认情况下 Redis 服务仅监听本地回环接口,这意味着只有本地客户端可以访问 Redis 服务
# 如果你希望 Redis 服务可以从任何 IP 地址访问,你应该将 bind 设置为 0.0.0.0。这将使 Redis 服务对远程客户端开放,但请注意这样做可能会带来安全风险,因此建议结合使用密码认证和其他安全措施
# bind 0.0.0.0
# Redis 7.0 之前: 使用 requirepass 配置项来设置单一的全局密码。
# Redis 7.0 及以后: 使用用户管理命令(如 acl setuser)来创建用户并设置密码和权限。
# 如果你正在使用 Redis 7.0 或更高版本,你应该使用新的用户管理机制来设置密码和权限。这提供了更灵活和更安全的方式来管理 Redis 的访问控制。
# requirepass Ms123!@#
在redis的目录下可以找到哨兵的配置文件,文件名为sentinel.conf
,在文件中找到如下配置,配置项说明用中文写到了注释里
# Example sentinel.conf
# By default protected mode is disabled in sentinel mode. Sentinel is reachable
# from interfaces different than localhost. Make sure the sentinel instance is
# protected from the outside world via firewalling or other means.
# 在 Redis Sentinel 中,protected-mode 的配置与普通的 Redis 实例有所不同。Sentinel 本身并不直接使用 protected-mode 配置项,因为 Sentinel 的主要功能是监控 Redis 主从实例的状态,并在主节点失效时自动进行故障转移,不支持动态修改,即不能在运行时通过 CONFIG SET 命令来改变这个配置项的值
# protected-mode yes: Sentinel 默认处于受保护模式。这意味着 Sentinel 只能连接到本地的 Redis 实例(例如,只有 127.0.0.1 或者本机的其他 IP 地址)。这对于防止 Sentinel 误操作其他服务器上的 Redis 实例是有帮助的。
# protected-mode no: 如果需要 Sentinel 连接到远程的 Redis 实例,需要将 Sentinel 的 protected-mode 设置为 no。这将允许 Sentinel 连接到任何 IP 地址的 Redis 实例
# 如果你希望 Sentinel 能够连接到远程的 Redis 实例,你需要将 Sentinel 的 protected-mode 设置为 no。这将允许 Sentinel 更加灵活地监控和管理远程 Redis 实例
protected-mode no
# port <sentinel-port>
# The port that this sentinel instance will run on
port 26379
# By default Redis Sentinel does not run as a daemon. Use 'yes' if you need it.
# Note that Redis will write a pid file in /var/run/redis-sentinel.pid when
# daemonized.
daemonize no
# When running daemonized, Redis Sentinel writes a pid file in
# /var/run/redis-sentinel.pid by default. You can specify a custom pid file
# location here.
pidfile /var/run/redis-sentinel.pid
# Specify the log file name. Also the empty string can be used to force
# Sentinel to log on the standard output. Note that if you use standard
# output for logging but daemonize, logs will be sent to /dev/null
logfile ""
# sentinel announce-ip <ip>
# sentinel announce-port <port>
#
# The above two configuration directives are useful in environments where,
# because of NAT, Sentinel is reachable from outside via a non-local address.
#
# When announce-ip is provided, the Sentinel will claim the specified IP address
# in HELLO messages used to gossip its presence, instead of auto-detecting the
# local address as it usually does.
#
# Similarly when announce-port is provided and is valid and non-zero, Sentinel
# will announce the specified TCP port.
#
# The two options don't need to be used together, if only announce-ip is
# provided, the Sentinel will announce the specified IP and the server port
# as specified by the "port" option. If only announce-port is provided, the
# Sentinel will announce the auto-detected local IP and the specified port.
#
# Example:
#
# sentinel announce-ip 1.2.3.4
# dir <working-directory>
# Every long running process should have a well-defined working directory.
# For Redis Sentinel to chdir to /tmp at startup is the simplest thing
# for the process to don't interfere with administrative tasks such as
# unmounting filesystems.
dir /tmp
# sentinel monitor <master-name> <ip> <redis-port> <quorum>
#
# Tells Sentinel to monitor this master, and to consider it in O_DOWN
# (Objectively Down) state only if at least <quorum> sentinels agree.
#
# Note that whatever is the ODOWN quorum, a Sentinel will require to
# be elected by the majority of the known Sentinels in order to
# start a failover, so no failover can be performed in minority.
#
# Replicas are auto-discovered, so you don't need to specify replicas in
# any way. Sentinel itself will rewrite this configuration file adding
# the replicas using additional configuration options.
# Also note that the configuration file is rewritten when a
# replica is promoted to master.
#
# Note: master name should not include special characters or spaces.
# The valid charset is A-z 0-9 and the three characters ".-_".
# sentinel monitor 命令用于在 Redis Sentinel 中配置一个主节点(master)的监控信息。这条命令告诉 Sentinel 应该监控哪个主节点,并指定了监控该主节点的 Sentinel 实例数量
# 监控: Sentinel 实例将开始监控名为 mymaster 的主节点,该主节点的 IP 地址为 127.0.0.1,端口号为 6379
# 故障转移: 如果至少有 2 个 Sentinel 实例认为该主节点已失效,则 Sentinel 会尝试自动进行故障转移,将其中一个从节点提升为主节点
# 如果你希望 Sentinel 实例监控一个主节点,并在主节点失效时自动进行故障转移,可以使用 sentinel monitor 命令来配置监控信息。这有助于提高 Redis 集群的高可用性
sentinel monitor mymaster 127.0.0.1 6379 2
# sentinel auth-pass <master-name> <password>
#
# Set the password to use to authenticate with the master and replicas.
# Useful if there is a password set in the Redis instances to monitor.
#
# Note that the master password is also used for replicas, so it is not
# possible to set a different password in masters and replicas instances
# if you want to be able to monitor these instances with Sentinel.
#
# However you can have Redis instances without the authentication enabled
# mixed with Redis instances requiring the authentication (as long as the
# password set is the same for all the instances requiring the password) as
# the AUTH command will have no effect in Redis instances with authentication
# switched off.
#
# Example:
#
# sentinel auth-pass mymaster MySUPER--secret-0123passw0rd
# sentinel auth-user 命令用于在 Redis Sentinel 中为特定的主节点(master)配置认证用户。这条命令告诉 Sentinel 应该为哪个主节点配置认证用户
# 认证用户: Sentinel 实例将为名为 mymaster 的主节点配置认证用户 myuser。
# 认证: 当 Sentinel 实例与该主节点通信时,将使用 myuser 进行认证。
# 如果你希望 Sentinel 实例在与特定主节点通信时使用认证用户,可以使用 sentinel auth-user 命令来配置认证用户信息。这有助于提高 Redis 集群的安全性。需要注意的是,实际配置认证密码还需要使用 ACL 命令来完成
# sentinel auth-user <master-name> <username>
#
# This is useful in order to authenticate to instances having ACL capabilities,
# that is, running Redis 6.0 or greater. When just auth-pass is provided the
# Sentinel instance will authenticate to Redis using the old "AUTH <pass>"
# method. When also an username is provided, it will use "AUTH <user> <pass>".
# In the Redis servers side, the ACL to provide just minimal access to
# Sentinel instances, should be configured along the following lines:
#
# user sentinel-user >somepassword +client +subscribe +publish \
# +ping +info +multi +slaveof +config +client +exec on
# sentinel down-after-milliseconds <master-name> <milliseconds>
#
# Number of milliseconds the master (or any attached replica or sentinel) should
# be unreachable (as in, not acceptable reply to PING, continuously, for the
# specified period) in order to consider it in S_DOWN state (Subjectively
# Down).
#
# Default is 30 seconds.
sentinel down-after-milliseconds mymaster 30000
# IMPORTANT NOTE: starting with Redis 6.2 ACL capability is supported for
# Sentinel mode, please refer to the Redis website https://redis.io/topics/acl
# for more details.
# Sentinel's ACL users are defined in the following format:
#
# user <username> ... acl rules ...
#
# For example:
#
# user worker +@admin +@connection ~* on >ffa9203c493aa99
#
# For more information about ACL configuration please refer to the Redis
# website at https://redis.io/topics/acl and redis server configuration
# template redis.conf.
# ACL LOG
#
# The ACL Log tracks failed commands and authentication events associated
# with ACLs. The ACL Log is useful to troubleshoot failed commands blocked
# by ACLs. The ACL Log is stored in memory. You can reclaim memory with
# ACL LOG RESET. Define the maximum entry length of the ACL Log below.
acllog-max-len 128
# Using an external ACL file
#
# Instead of configuring users here in this file, it is possible to use
# a stand-alone file just listing users. The two methods cannot be mixed:
# if you configure users here and at the same time you activate the external
# ACL file, the server will refuse to start.
#
# The format of the external ACL user file is exactly the same as the
# format that is used inside redis.conf to describe users.
#
# aclfile /etc/redis/sentinel-users.acl
# requirepass <password>
#
# You can configure Sentinel itself to require a password, however when doing
# so Sentinel will try to authenticate with the same password to all the
# other Sentinels. So you need to configure all your Sentinels in a given
# group with the same "requirepass" password. Check the following documentation
# for more info: https://redis.io/topics/sentinel
#
# IMPORTANT NOTE: starting with Redis 6.2 "requirepass" is a compatibility
# layer on top of the ACL system. The option effect will be just setting
# the password for the default user. Clients will still authenticate using
# AUTH <password> as usually, or more explicitly with AUTH default <password>
# if they follow the new protocol: both will work.
#
# New config files are advised to use separate authentication control for
# incoming connections (via ACL), and for outgoing connections (via
# sentinel-user and sentinel-pass)
#
# The requirepass is not compatible with aclfile option and the ACL LOAD
# command, these will cause requirepass to be ignored.
# sentinel sentinel-user <username>
#
# You can configure Sentinel to authenticate with other Sentinels with specific
# user name.
# sentinel sentinel-pass <password>
#
# The password for Sentinel to authenticate with other Sentinels. If sentinel-user
# is not configured, Sentinel will use 'default' user with sentinel-pass to authenticate.
# sentinel parallel-syncs <master-name> <numreplicas>
#
# How many replicas we can reconfigure to point to the new replica simultaneously
# during the failover. Use a low number if you use the replicas to serve query
# to avoid that all the replicas will be unreachable at about the same
# time while performing the synchronization with the master.
sentinel parallel-syncs mymaster 1
# sentinel failover-timeout <master-name> <milliseconds>
#
# Specifies the failover timeout in milliseconds. It is used in many ways:
#
# - The time needed to re-start a failover after a previous failover was
# already tried against the same master by a given Sentinel, is two
# times the failover timeout.
#
# - The time needed for a replica replicating to a wrong master according
# to a Sentinel current configuration, to be forced to replicate
# with the right master, is exactly the failover timeout (counting since
# the moment a Sentinel detected the misconfiguration).
#
# - The time needed to cancel a failover that is already in progress but
# did not produced any configuration change (SLAVEOF NO ONE yet not
# acknowledged by the promoted replica).
#
# - The maximum time a failover in progress waits for all the replicas to be
# reconfigured as replicas of the new master. However even after this time
# the replicas will be reconfigured by the Sentinels anyway, but not with
# the exact parallel-syncs progression as specified.
#
# Default is 3 minutes.
sentinel failover-timeout mymaster 180000
# SCRIPTS EXECUTION
#
# sentinel notification-script and sentinel reconfig-script are used in order
# to configure scripts that are called to notify the system administrator
# or to reconfigure clients after a failover. The scripts are executed
# with the following rules for error handling:
#
# If script exits with "1" the execution is retried later (up to a maximum
# number of times currently set to 10).
#
# If script exits with "2" (or an higher value) the script execution is
# not retried.
#
# If script terminates because it receives a signal the behavior is the same
# as exit code 1.
#
# A script has a maximum running time of 60 seconds. After this limit is
# reached the script is terminated with a SIGKILL and the execution retried.
# NOTIFICATION SCRIPT
#
# sentinel notification-script <master-name> <script-path>
#
# Call the specified notification script for any sentinel event that is
# generated in the WARNING level (for instance -sdown, -odown, and so forth).
# This script should notify the system administrator via email, SMS, or any
# other messaging system, that there is something wrong with the monitored
# Redis systems.
#
# The script is called with just two arguments: the first is the event type
# and the second the event description.
#
# The script must exist and be executable in order for sentinel to start if
# this option is provided.
#
# Example:
#
# sentinel notification-script mymaster /var/redis/notify.sh
# CLIENTS RECONFIGURATION SCRIPT
#
# sentinel client-reconfig-script <master-name> <script-path>
#
# When the master changed because of a failover a script can be called in
# order to perform application-specific tasks to notify the clients that the
# configuration has changed and the master is at a different address.
#
# The following arguments are passed to the script:
#
# <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
#
# <state> is currently always "start"
# <role> is either "leader" or "observer"
#
# The arguments from-ip, from-port, to-ip, to-port are used to communicate
# the old address of the master and the new address of the elected replica
# (now a master).
#
# This script should be resistant to multiple invocations.
#
# Example:
#
# sentinel client-reconfig-script mymaster /var/redis/reconfig.sh
# SECURITY
#
# By default SENTINEL SET will not be able to change the notification-script
# and client-reconfig-script at runtime. This avoids a trivial security issue
# where clients can set the script to anything and trigger a failover in order
# to get the program executed.
sentinel deny-scripts-reconfig yes
# REDIS COMMANDS RENAMING (DEPRECATED)
#
# WARNING: avoid using this option if possible, instead use ACLs.
#
# Sometimes the Redis server has certain commands, that are needed for Sentinel
# to work correctly, renamed to unguessable strings. This is often the case
# of CONFIG and SLAVEOF in the context of providers that provide Redis as
# a service, and don't want the customers to reconfigure the instances outside
# of the administration console.
#
# In such case it is possible to tell Sentinel to use different command names
# instead of the normal ones. For example if the master "mymaster", and the
# associated replicas, have "CONFIG" all renamed to "GUESSME", I could use:
#
# SENTINEL rename-command mymaster CONFIG GUESSME
#
# After such configuration is set, every time Sentinel would use CONFIG it will
# use GUESSME instead. Note that there is no actual need to respect the command
# case, so writing "config guessme" is the same in the example above.
#
# SENTINEL SET can also be used in order to perform this configuration at runtime.
#
# In order to set a command back to its original name (undo the renaming), it
# is possible to just rename a command to itself:
#
# SENTINEL rename-command mymaster CONFIG CONFIG
# HOSTNAMES SUPPORT
#
# Normally Sentinel uses only IP addresses and requires SENTINEL MONITOR
# to specify an IP address. Also, it requires the Redis replica-announce-ip
# keyword to specify only IP addresses.
#
# You may enable hostnames support by enabling resolve-hostnames. Note
# that you must make sure your DNS is configured properly and that DNS
# resolution does not introduce very long delays.
#
SENTINEL resolve-hostnames no
# When resolve-hostnames is enabled, Sentinel still uses IP addresses
# when exposing instances to users, configuration files, etc. If you want
# to retain the hostnames when announced, enable announce-hostnames below.
#
SENTINEL announce-hostnames no
# When master_reboot_down_after_period is set to 0, Sentinel does not fail over
# when receiving a -LOADING response from a master. This was the only supported
# behavior before version 7.0.
#
# Otherwise, Sentinel will use this value as the time (in ms) it is willing to
# accept a -LOADING response after a master has been rebooted, before failing
# over.
SENTINEL master-reboot-down-after-period mymaster 0
配置好之后首先启动Redis主服务器进程,然后启动Redis从服务器进程./src/redis-server ./redis.conf
,之后再启动哨兵进程./src/redis-sentinel ./sentinel.conf
Java代码中使用哨兵
public static void testJedisSentinel() {
// 连接池配置
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(10);
jedisPoolConfig.setMaxIdle(5);
jedisPoolConfig.setMinIdle(5);
// 哨兵信息
Set<String> sentinels = new HashSet<>(
Arrays.asList(
"192.168.44.119:26379",
"192.168.44.130:26379",
"192.168.44.131:26379"
));
// 创建连接池
// mymaster是我们配置给哨兵的服务名称
// sentinels是哨兵信息
// jedisPoolConfig是连接池配置
// abcdefg是连接Redis服务器的密码
JedisSentinelPool pool = new JedisSentinelPool("mymaster", sentinels, jedisPoolConfig, "Ms123!@#");
// 获取客户端
Jedis jedis = pool.getResource();
// 执行两个命令
jedis.set("sentinel-key", "sentinel-value");
String value = jedis.get("sentinel-key");
// 打印信息
System.out.println(value);
}
在Spring中使用哨兵模式
package com.sr.config;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration.JedisClientConfigurationBuilder;
import org.springframework.data.redis.core.StringRedisTemplate;
import redis.clients.jedis.JedisPoolConfig;
@Configuration
public class RedisSentinelConfig {
/**
* Redis连接池配置
* @return 连接池
*/
@Bean("redisPoolConfig")
public JedisPoolConfig poolConfig() {JedisPoolConfig poolCfg = new JedisPoolConfig();
// 最大空闲数
poolCfg.setMaxIdle(50);
// 最大连接数
poolCfg.setMaxTotal(100);
// 最大等待毫秒数
poolCfg.setMaxWaitMillis(20000);
return poolCfg;
}
@Bean("sentinelConfig")
public RedisSentinelConfiguration sentinelConfig() {
// 主机名
String master = "mymaster";
// 哨兵IP和端口集合
Set<String> sentinels = new HashSet<>(Arrays.asList(
"192.168.44.129:26379",
"192.168.44.130:26379",
"192.168.44.131:26379"
));
// 创建RedisSentinelConfiguration对象
RedisSentinelConfiguration config = new RedisSentinelConfiguration(master, sentinels);
// 设置密码
config.setPassword("Ms123!@#");
return config;
}
/**
* 创建Jedis连接工厂
*
* @param jedisPoolConfig
* @return 连接工厂
*/
@Bean("redisConnectionFactory")
public RedisConnectionFactory redisConnectionFactory(@Autowired RedisSentinelConfiguration sentinelConfig, @Autowired JedisPoolConfig jedisPoolConfig) {
// 获得默认的连接池构造器
JedisClientConfigurationBuilder jpcb = JedisClientConfiguration.builder();
// 设置Redis连接池
jpcb.usePooling().poolConfig(jedisPoolConfig);
// 获取构建器
JedisClientConfiguration jcc = jpcb.build();
// 使用RedisSentinelConfiguration创建连接工厂
return new JedisConnectionFactory(sentinelConfig, jcc);
}
/**
* 创建StringRedisTemplate
*
* @param connectionFactory 连接工厂
* @return StringRedisTemplate对象
*/
@Bean("stringRedisTemplate")
public StringRedisTemplate stringRedisTemplate(@Autowired RedisConnectionFactory connectionFactory) {
// 创建StringRedisTemplate对象
StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
// 设置连接工厂
stringRedisTemplate.setConnectionFactory(connectionFactory);
return stringRedisTemplate;
}
}
测试代码如下
public static void testSentinel() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(RedisSentinelConfig.class);
StringRedisTemplate redisTemplate = applicationContext.getBean(StringRedisTemplate.class);
redisTemplate.opsForValue().set("sentinel-key", "sentinel-value");
String value = redisTemplate.opsForValue().get("sentinel-key");
System.out.println(value);
}
Redis集群
首先要了解哈希槽的概念,如下图所示,很容易看懂,哈希槽有6个数字,这个数字决定了Redis路由到哪个主服务器
在Redis 集群中的哈希槽(Hash Slot)数量固定为16,384个(编号从0到16,383)。这些槽用于分布式的键值存储,使得数据能够在集群中的多个节点之间均匀分布,选择16,384作为哈希槽的数量有几个原因:
- 位图表示:每个槽的状态可以通过一个位来表示,这样整个集群的槽状态可以用一个位图来存储。16,384 个槽可以用 2 KB 的位图来表示(因为 16,384 位等于 2 KB 或 2048 字节),这在内存占用和网络传输方面都是合理的。
- 心跳数据包大小:心跳数据包用于维护集群节点之间的连接状态,包括槽的分配情况。较小的心跳数据包有助于减少网络带宽的消耗。
- 节点数量:假设集群中每个节点管理的槽位数量大致相同,那么即使集群扩展到数百个节点,每个节点仍然能够管理足够数量的槽位,以确保数据的均匀分布。
- 可扩展性与效率:16,384 是一个足够大的数字,可以支持大量的节点和数据分布,同时又不至于过大而导致不必要的资源浪费。例如,如果槽的数量增加到 65,536,则心跳数据包的大小会相应增加到 8 KB,这对于大多数集群来说可能是不必要的。
- 设计决策:根据 Redis 的设计者 Antirez 的说法,16,384 的槽位数量是在考虑了上述因素之后的一个合理选择。它足够大以支持高可用性和扩展性,同时又足够小以保持高效。
16,384 个哈希槽是基于内存使用、网络传输效率、集群规模等因素综合考量的结果
在 Redis 集群中,哈希值的范围是指通过哈希算法计算得到的值的范围,这个值用于确定键值对应该存放在哪个哈希槽中。
具体来说,Redis使用CRC16算法对键进行哈希运算,并且将得到的哈希值对16,384(即哈希槽的数量)取模,从而得到一个介于 0 和 16,383 之间的整数。这个整数就决定了键值对应该被分配到哪一个哈希槽中
假设有3个Redis主服务器时,哈希槽会被均匀地分配给这些主服务器,以实现数据的均衡分布。在Redis集群中,16,384个哈希槽会被尽可能均匀地分配到各个主节点上。哈希槽划分的基本步骤如下:
-
计算每个主服务器分配的哈希槽数量:理想情况下,每个主服务器应该分配到相同数量的哈希槽。对于3个主服务器,每个主服务器理论上会分配到大约 (16,384 / 3) 个哈希槽。由于16,384不能被3整除,实际分配时会有轻微的差异。
- 分配哈希槽:假设我们有3个主服务器,分别为 A、B 和 C。理想情况下,每个主服务器分配到的哈希槽数量应该是:
- 主服务器 A: 大约 (16,384 / 3) 个哈希槽
- 主服务器 B: 大约 (16,384 / 3) 个哈希槽
- 主服务器 C: 大约 (16,384 / 3) 个哈希槽
- 具体计算为:
- 主服务器 A: (16,384 / 3 = 5461.33),取整后为 5461 个哈希槽
- 主服务器 B: (16,384 / 3 = 5461.33),取整后为 5461 个哈希槽
- 主服务器 C: (16,384 - (5461 + 5461) = 5462) 个哈希槽
-
实际上,由于不能完全均分,可能会出现一个主服务器比另外两个多一个哈希槽的情况。哈希槽分配示例:主服务器 A 可能负责哈希槽 0 至 5460。主服务器 B 可能负责哈希槽 5461 至 10921。主服务器 C 可能负责哈希槽 10922 至 16383。
-
键的哈希计算:当一个键被插入时,Redis 使用 CRC16 算法计算键的哈希值,并将结果对 16,384 取模。根据计算出的哈希槽编号,键会被路由到相应的主服务器。
-
动态调整:Redis 集群支持动态调整哈希槽的分配。如果集群中的节点发生变化(如添加或删除节点),哈希槽会重新分配以适应新的节点布局
请注意,实际的哈希槽分配可能因集群的具体配置而略有不同,但上述方法提供了一个大致的指导原则。在实际操作中,您可以通过 Redis 集群命令 CLUSTER SLOTS 来查看具体的哈希槽分配情况
- 哈希槽的分配通常是自动完成的,不需要人为手动配置。当您设置好集群节点并启动集群时,Redis 会自动将哈希槽分配给各个主节点。以下是一些关键点:
- 自动分配:当 Redis 集群首次启动时,它会自动将 16,384 个哈希槽分配给集群中的主节点。这种分配是基于集群中节点的数量和当前的拓扑结构。
- 动态调整:如果集群的拓扑结构发生变化(例如,添加或移除节点),Redis 会自动重新分配哈希槽以适应新的节点布局。这种重新分配是为了确保数据在集群中的分布尽可能均匀。
- 手动干预:虽然通常不需要人为干预,但在某些情况下,管理员可能需要手动调整哈希槽的分配。例如,如果集群中的数据分布不均,或者希望优化特定工作负载的数据访问模式,可以通过 Redis 的 CLUSTER 命令来进行手动迁移哈希槽。
- 监控与调整:管理员可以通过 Redis 的 CLUSTER SLOTS 命令来检查哈希槽的当前分配情况。如果发现分配不均或其他问题,可以使用 CLUSTER SETSLOT 命令来手动迁移哈希槽。
- 自动故障转移:当主节点发生故障时,Redis 集群会自动从对应的从节点中选择一个新的主节点,并将相关的哈希槽转移到新的主节点上。
总之,Redis 集群在大多数情况下会自动处理哈希槽的分配和调整。但是,管理员仍然需要监控集群的健康状况,并在必要时进行手动调整以确保集群的最佳性能。
当主服务器 A 不可用并且从集群中被移除时,原本分配给它的哈希槽将不再可用。Redis 集群会采取以下措施来处理这种情况:
- 故障检测:Redis 集群会定期检测节点的健康状态。一旦检测到主节点 A 不可用,集群会标记该节点为故障状态
- 故障转移:如果主节点 A 有一个或多个从节点,Redis 集群会自动从这些从节点中选择一个作为新的主节点。这个过程称为故障转移(Failover)。新选为主节点的从节点会接管原来主节点的所有哈希槽
- 哈希槽重新分配:一旦故障转移完成,原本分配给原主节点 A 的哈希槽会被重新分配给新的主节点。如果集群中有足够的其他主节点,这些哈希槽也会被重新分配给其他主节点,以保持数据分布的均衡
- 数据复制:在故障转移过程中,新的主节点会从原来的主节点 A 的快照(如果有)或从节点中复制数据。这样可以确保数据的一致性
- 集群状态更新:故障转移完成后,集群的状态会被更新,以反映新的哈希槽分配情况。集群中的所有节点都会同步最新的哈希槽分配信息。
- 客户端重定向:客户端发送请求时,会根据最新的哈希槽分配信息将请求路由到正确的节点。这意味着客户端可能会被重定向到新的主节点或其他主节点,以访问原本由主节点 A 管理的数据。
- 手动干预:在某些情况下,管理员可能需要手动介入来加速故障转移过程或进行额外的哈希槽调整。例如,如果集群中没有足够的从节点,或者管理员希望控制故障转移的过程,可以使用 Redis 的 CLUSTER 命令来进行手动操作。
综上所述,当主服务器 A 不可用时,Redis 集群会自动执行故障转移和哈希槽的重新分配,以确保集群的连续运行和服务可用性
Redis客户端可以连接任意一台Redis主服务器,而在集群中的Redis主服务器是通过网络连接的,他们连接的方式是PING-PONG机制,并且内部使用二进制协议优化传输速度和带宽占用
- 当出现故障时,需要判定某个主节点不可用时,各个主节点就会投票,假如半数以上主节点认为该节点不可用,就会把这个不可用节点剔除集群,由其从节点替换,这样集群就达到了容错的效果,而这个投票机制需要半数以上节点通过,因此一般而言要求节点数大于3,且为单数,否则容易出现投票3:3的情况,没办法剔除不可用节点,严重了就会导致整个集群不可用
- 如果Redis主节点不能够构建完整的哈希槽区间0-16383,也会导致集群不可用,例如Redis主服务器1和其从服务器均不可用,而有没有其他的Redis服务器覆盖区间0-5460,那么就不能构建完整的哈希槽区间0-16383,集群机制就会认为此集群不可用
- 如果原有半数以上的主节点发生故障,无论是否存在可替代的从节点,都认为集群不可用
- Redis集群是通过网络连接的,而网络必然存在延迟和故障,会导致数据一致性出现问题,Redis集群不能保证数据一致性,因此可能产生数据丢失的情况,在应用开发上将其作为缓存更为合理
Redis集群搭建
找到配置文件redis.conf
中如下配置,配置项说明用中文写到了注释里
################################ REDIS CLUSTER ###############################
# Normal Redis instances can't be part of a Redis Cluster; only nodes that are
# started as cluster nodes can. In order to start a Redis instance as a
# cluster node enable the cluster support uncommenting the following:
# cluster-enabled yes 是 Redis 配置文件 (redis.conf) 中的一个配置项,用于启用或禁用 Redis 集群模式。当设置为 yes 时,表示启用 Redis 集群功能
# 启用 cluster-enabled yes 表示您希望使用 Redis 集群模式,这将允许您利用集群的高级功能,如数据分片、故障转移和数据复制等。在生产环境中使用集群模式时,请确保正确配置所有必要的集群参数,并使用 redis-trib.rb 工具来创建和管理集群
# cluster-enabled yes
# Every cluster node has a cluster configuration file. This file is not
# intended to be edited by hand. It is created and updated by Redis nodes.
# Every Redis Cluster node requires a different cluster configuration file.
# Make sure that instances running in the same system do not have
# overlapping cluster configuration file names.
# cluster-config-file nodes-6379.conf 是 Redis 配置文件 (redis.conf) 中的一个配置项,用于指定 Redis 集群状态文件的名称。这个文件包含了集群的元数据,比如节点间的连接信息、哈希槽的分配情况等
# cluster-config-file: 指定集群状态文件的名称。
# nodes-6379.conf: 这里指定了文件名为 nodes-6379.conf,其中的数字 6379 通常对应 Redis 实例监听的端口号
# cluster-config-file nodes-6379.conf
# Cluster node timeout is the amount of milliseconds a node must be unreachable
# for it to be considered in failure state.
# Most other internal time limits are a multiple of the node timeout.
# cluster-node-timeout 15000 是 Redis 配置文件 (redis.conf) 中的一个配置项,用于设置集群中节点之间的超时时间。这个超时时间定义了集群内部节点间通信的最大等待时间,单位为毫秒
# 集群中的节点通过定期发送心跳消息来保持彼此之间的连接状态。cluster-node-timeout 设置了节点间通信的超时时间,如果一个节点在设定的时间内没有收到另一个节点的心跳消息,那么它就会认为该节点已经失效
# cluster-node-timeout 15000
# The cluster port is the port that the cluster bus will listen for inbound connections on. When set
# to the default value, 0, it will be bound to the command port + 10000. Setting this value requires
# you to specify the cluster bus port when executing cluster meet.
# cluster-port 0 是 Redis 配置文件 (redis.conf) 中的一个配置项,用于指定 Redis 集群模式下的通信端口。然而,将 cluster-port 设置为 0 并不是一个有效的配置,因为 Redis 需要知道一个具体的端口来建立集群间的通信
# 在 Redis 配置文件中,cluster-port 通常不需要显式配置,因为默认情况下,Redis 使用与 port 配置项相同的端口来处理集群间的通信。例如,如果您的 Redis 实例监听在端口 6379 上,那么集群通信也将使用端口 6379
# 如果您需要将集群通信端口与客户端连接端口分开,可以在 Redis 2.8 版本之前使用 cluster-port 配置项。但从 Redis 2.8 开始,cluster-port 配置项已被废弃,集群通信端口默认与客户端连接端口相同
# cluster-port 0
# A replica of a failing master will avoid to start a failover if its data
# looks too old.
#
# There is no simple way for a replica to actually have an exact measure of
# its "data age", so the following two checks are performed:
#
# 1) If there are multiple replicas able to failover, they exchange messages
# in order to try to give an advantage to the replica with the best
# replication offset (more data from the master processed).
# Replicas will try to get their rank by offset, and apply to the start
# of the failover a delay proportional to their rank.
#
# 2) Every single replica computes the time of the last interaction with
# its master. This can be the last ping or command received (if the master
# is still in the "connected" state), or the time that elapsed since the
# disconnection with the master (if the replication link is currently down).
# If the last interaction is too old, the replica will not try to failover
# at all.
#
# The point "2" can be tuned by user. Specifically a replica will not perform
# the failover if, since the last interaction with the master, the time
# elapsed is greater than:
#
# (node-timeout * cluster-replica-validity-factor) + repl-ping-replica-period
#
# So for example if node-timeout is 30 seconds, and the cluster-replica-validity-factor
# is 10, and assuming a default repl-ping-replica-period of 10 seconds, the
# replica will not try to failover if it was not able to talk with the master
# for longer than 310 seconds.
#
# A large cluster-replica-validity-factor may allow replicas with too old data to failover
# a master, while a too small value may prevent the cluster from being able to
# elect a replica at all.
#
# For maximum availability, it is possible to set the cluster-replica-validity-factor
# to a value of 0, which means, that replicas will always try to failover the
# master regardless of the last time they interacted with the master.
# (However they'll always try to apply a delay proportional to their
# offset rank).
#
# Zero is the only value able to guarantee that when all the partitions heal
# the cluster will always be able to continue.
#
# cluster-replica-validity-factor 10
# Cluster replicas are able to migrate to orphaned masters, that are masters
# that are left without working replicas. This improves the cluster ability
# to resist to failures as otherwise an orphaned master can't be failed over
# in case of failure if it has no working replicas.
#
# Replicas migrate to orphaned masters only if there are still at least a
# given number of other working replicas for their old master. This number
# is the "migration barrier". A migration barrier of 1 means that a replica
# will migrate only if there is at least 1 other working replica for its master
# and so forth. It usually reflects the number of replicas you want for every
# master in your cluster.
#
# Default is 1 (replicas migrate only if their masters remain with at least
# one replica). To disable migration just set it to a very large value or
# set cluster-allow-replica-migration to 'no'.
# A value of 0 can be set but is useful only for debugging and dangerous
# in production.
#
# cluster-migration-barrier 1
# Turning off this option allows to use less automatic cluster configuration.
# It both disables migration to orphaned masters and migration from masters
# that became empty.
#
# Default is 'yes' (allow automatic migrations).
#
# cluster-allow-replica-migration yes
# By default Redis Cluster nodes stop accepting queries if they detect there
# is at least a hash slot uncovered (no available node is serving it).
# This way if the cluster is partially down (for example a range of hash slots
# are no longer covered) all the cluster becomes, eventually, unavailable.
# It automatically returns available as soon as all the slots are covered again.
#
# However sometimes you want the subset of the cluster which is working,
# to continue to accept queries for the part of the key space that is still
# covered. In order to do so, just set the cluster-require-full-coverage
# option to no.
#
# cluster-require-full-coverage yes
# This option, when set to yes, prevents replicas from trying to failover its
# master during master failures. However the replica can still perform a
# manual failover, if forced to do so.
#
# This is useful in different scenarios, especially in the case of multiple
# data center operations, where we want one side to never be promoted if not
# in the case of a total DC failure.
#
# cluster-replica-no-failover no
# This option, when set to yes, allows nodes to serve read traffic while the
# cluster is in a down state, as long as it believes it owns the slots.
#
# This is useful for two cases. The first case is for when an application
# doesn't require consistency of data during node failures or network partitions.
# One example of this is a cache, where as long as the node has the data it
# should be able to serve it.
#
# The second use case is for configurations that don't meet the recommended
# three shards but want to enable cluster mode and scale later. A
# master outage in a 1 or 2 shard configuration causes a read/write outage to the
# entire cluster without this option set, with it set there is only a write outage.
# Without a quorum of masters, slot ownership will not change automatically.
#
# cluster-allow-reads-when-down no
# This option, when set to yes, allows nodes to serve pubsub shard traffic while
# the cluster is in a down state, as long as it believes it owns the slots.
#
# This is useful if the application would like to use the pubsub feature even when
# the cluster global stable state is not OK. If the application wants to make sure only
# one shard is serving a given channel, this feature should be kept as yes.
#
# cluster-allow-pubsubshard-when-down yes
# Cluster link send buffer limit is the limit on the memory usage of an individual
# cluster bus link's send buffer in bytes. Cluster links would be freed if they exceed
# this limit. This is to primarily prevent send buffers from growing unbounded on links
# toward slow peers (E.g. PubSub messages being piled up).
# This limit is disabled by default. Enable this limit when 'mem_cluster_links' INFO field
# and/or 'send-buffer-allocated' entries in the 'CLUSTER LINKS` command output continuously increase.
# Minimum limit of 1gb is recommended so that cluster link buffer can fit in at least a single
# PubSub message by default. (client-query-buffer-limit default value is 1gb)
#
# cluster-link-sendbuf-limit 0
# Clusters can configure their announced hostname using this config. This is a common use case for
# applications that need to use TLS Server Name Indication (SNI) or dealing with DNS based
# routing. By default this value is only shown as additional metadata in the CLUSTER SLOTS
# command, but can be changed using 'cluster-preferred-endpoint-type' config. This value is
# communicated along the clusterbus to all nodes, setting it to an empty string will remove
# the hostname and also propagate the removal.
#
# cluster-announce-hostname ""
# Clusters can advertise how clients should connect to them using either their IP address,
# a user defined hostname, or by declaring they have no endpoint. Which endpoint is
# shown as the preferred endpoint is set by using the cluster-preferred-endpoint-type
# config with values 'ip', 'hostname', or 'unknown-endpoint'. This value controls how
# the endpoint returned for MOVED/ASKING requests as well as the first field of CLUSTER SLOTS.
# If the preferred endpoint type is set to hostname, but no announced hostname is set, a '?'
# will be returned instead.
#
# When a cluster advertises itself as having an unknown endpoint, it's indicating that
# the server doesn't know how clients can reach the cluster. This can happen in certain
# networking situations where there are multiple possible routes to the node, and the
# server doesn't know which one the client took. In this case, the server is expecting
# the client to reach out on the same endpoint it used for making the last request, but use
# the port provided in the response.
#
# cluster-preferred-endpoint-type ip
# In order to setup your cluster make sure to read the documentation
# available at https://redis.io web site.
还有一个配置节点,在配置文件中属于通用类的配置,如下所示
################################# GENERAL #####################################
# By default Redis does not run as a daemon. Use 'yes' if you need it.
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
# When Redis is supervised by upstart or systemd, this parameter has no impact.
daemonize yes
# If you run Redis from upstart or systemd, Redis can interact with your
# supervision tree. Options:
# supervised no - no supervision interaction
# supervised upstart - signal upstart by putting Redis into SIGSTOP mode
# requires "expect stop" in your upstart job config
# supervised systemd - signal systemd by writing READY=1 to $NOTIFY_SOCKET
# on startup, and updating Redis status on a regular
# basis.
# supervised auto - detect upstart or systemd method based on
# UPSTART_JOB or NOTIFY_SOCKET environment variables
# Note: these supervision methods only signal "process is ready."
# They do not enable continuous pings back to your supervisor.
#
# The default is "no". To run under upstart/systemd, you can simply uncomment
# the line below:
#
# supervised auto
# If a pid file is specified, Redis writes it where specified at startup
# and removes it at exit.
#
# When the server runs non daemonized, no pid file is created if none is
# specified in the configuration. When the server is daemonized, the pid file
# is used even if not specified, defaulting to "/var/run/redis.pid".
#
# Creating a pid file is best effort: if Redis is not able to create it
# nothing bad happens, the server will start and run normally.
#
# Note that on modern Linux systems "/run/redis.pid" is more conforming
# and should be used instead.
pidfile /var/run/redis_6379.pid
# Specify the server verbosity level.
# This can be one of:
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably)
# warning (only very important / critical messages are logged)
loglevel notice
# Specify the log file name. Also the empty string can be used to force
# Redis to log on the standard output. Note that if you use standard
# output for logging but daemonize, logs will be sent to /dev/null
logfile ""
# 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
# To disable the built in crash log, which will possibly produce cleaner core
# dumps when they are needed, uncomment the following:
#
# crash-log-enabled no
# To disable the fast memory check that's run as part of the crash log, which
# will possibly let redis terminate sooner, uncomment the following:
#
# crash-memcheck-enabled no
# Set the number of databases. The default database is DB 0, you can select
# a different one on a per-connection basis using SELECT <dbid> where
# dbid is a number between 0 and 'databases'-1
databases 16
# By default Redis shows an ASCII art logo only when started to log to the
# standard output and if the standard output is a TTY and syslog logging is
# disabled. Basically this means that normally a logo is displayed only in
# interactive sessions.
#
# However it is possible to force the pre-4.0 behavior and always show a
# ASCII art logo in startup logs by setting the following option to yes.
always-show-logo no
# By default, Redis modifies the process title (as seen in 'top' and 'ps') to
# provide some runtime information. It is possible to disable this and leave
# the process name as executed by setting the following to no.
set-proc-title yes
# When changing the process title, Redis uses the following template to construct
# the modified title.
#
# Template variables are specified in curly brackets. The following variables are
# supported:
#
# {title} Name of process as executed if parent, or type of child process.
# {listen-addr} Bind address or '*' followed by TCP or TLS port listening on, or
# Unix socket if only that's available.
# {server-mode} Special mode, i.e. "[sentinel]" or "[cluster]".
# {port} TCP port listening on, or 0.
# {tls-port} TLS port listening on, or 0.
# {unixsocket} Unix domain socket listening on, or "".
# {config-file} Name of configuration file used.
#
proc-title-template "{title} {listen-addr} {server-mode}"
配置文件比较清楚,有多少机器就要根据实际的机器属性进行配置,主服务器就按主的配,从服务器就按从的配,集群就配置集群,需要仔细配置,另外通常集群的主从使用AOF备份方式,因此也需要配置AOF
假如有6台机器,包含3个主3个从,那就是6个配置文件,首先创建这些文件并且赋予权限,执行如下命令
# 进入redis安装目录
cd /root/redis
# 创建集群文件夹及子目录
mkdir cluster
cd ./cluster
mkdir 7001 7002 7003 7004 7005 7006
# 复制配置文件
cp ../redis.conf ./7001
cp ../redis.conf ./7002
cp ../redis.conf ./7003
cp ../redis.conf ./7004
cp ../redis.conf ./7005
cp ../redis.conf ./7006
# 给这些文件路径全部权限
chmod -R 777 ./
如此从7001到7006都存在一个Redis启动的配置文件,复制的配置文件里,要进行修改,对应到7001到7006端口上,这样6份启动文件,分别使用7001到7006启动服务,接下来找到/root/redis/utils/create-cluster
路径下的create-cluster.sh
文件,这是一个启动集群的SHELL脚本,对应自己服务器的配置修改即可
#!/bin/bash
SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
# Settings
BIN_PATH="$SCRIPT_DIR/../../src/"
CLUSTER_HOST=127.0.0.1
PORT=30000
TIMEOUT=2000
NODES=6
REPLICAS=1
PROTECTED_MODE=yes
ADDITIONAL_OPTIONS=""
# You may want to put the above config parameters into config.sh in order to
# override the defaults without modifying this script.
if [ -a config.sh ]
then
source "config.sh"
fi
# Computed vars
ENDPORT=$((PORT+NODES))
if [ "$1" == "start" ]
then
while [ $((PORT < ENDPORT)) != "0" ]; do
PORT=$((PORT+1))
echo "Starting $PORT"
$BIN_PATH/redis-server --port $PORT --protected-mode $PROTECTED_MODE --cluster-enabled yes --cluster-config-file nodes-${PORT}.conf --cluster-node-timeout $TIMEOUT --appendonly yes --appendfilename appendonly-${PORT}.aof --appenddirname appendonlydir-${PORT} --dbfilename dump-${PORT}.rdb --logfile ${PORT}.log --daemonize yes ${ADDITIONAL_OPTIONS}
done
exit 0
fi
if [ "$1" == "create" ]
then
HOSTS=""
while [ $((PORT < ENDPORT)) != "0" ]; do
PORT=$((PORT+1))
HOSTS="$HOSTS $CLUSTER_HOST:$PORT"
done
OPT_ARG=""
if [ "$2" == "-f" ]; then
OPT_ARG="--cluster-yes"
fi
$BIN_PATH/redis-cli --cluster create $HOSTS --cluster-replicas $REPLICAS $OPT_ARG
exit 0
fi
if [ "$1" == "stop" ]
then
while [ $((PORT < ENDPORT)) != "0" ]; do
PORT=$((PORT+1))
echo "Stopping $PORT"
$BIN_PATH/redis-cli -p $PORT shutdown nosave
done
exit 0
fi
if [ "$1" == "watch" ]
then
PORT=$((PORT+1))
while [ 1 ]; do
clear
date
$BIN_PATH/redis-cli -p $PORT cluster nodes | head -30
sleep 1
done
exit 0
fi
if [ "$1" == "tail" ]
then
INSTANCE=$2
PORT=$((PORT+INSTANCE))
tail -f ${PORT}.log
exit 0
fi
if [ "$1" == "tailall" ]
then
tail -f *.log
exit 0
fi
if [ "$1" == "call" ]
then
while [ $((PORT < ENDPORT)) != "0" ]; do
PORT=$((PORT+1))
$BIN_PATH/redis-cli -p $PORT $2 $3 $4 $5 $6 $7 $8 $9
done
exit 0
fi
if [ "$1" == "clean" ]
then
echo "Cleaning *.log"
rm -rf *.log
echo "Cleaning appendonlydir-*"
rm -rf appendonlydir-*
echo "Cleaning dump-*.rdb"
rm -rf dump-*.rdb
echo "Cleaning nodes-*.conf"
rm -rf nodes-*.conf
exit 0
fi
if [ "$1" == "clean-logs" ]
then
echo "Cleaning *.log"
rm -rf *.log
exit 0
fi
echo "Usage: $0 [start|create|stop|watch|tail|tailall|clean|clean-logs|call]"
echo "start -- Launch Redis Cluster instances."
echo "create [-f] -- Create a cluster using redis-cli --cluster create."
echo "stop -- Stop Redis Cluster instances."
echo "watch -- Show CLUSTER NODES output (first 30 lines) of first node."
echo "tail <id> -- Run tail -f of instance at base port + ID."
echo "tailall -- Run tail -f for all the log files at once."
echo "clean -- Remove all instances data, logs, configs."
echo "clean-logs -- Remove just instances logs."
echo "call <cmd> -- Call a command (up to 7 arguments) on all nodes."
为了方便创建、停止、和启动集群,在之前创建的cluster路径下创建3个文件,执行如下命令
cd /root/redis/cluster
touch create.sh start.sh shutdown.sh
chmod 777 *.sh
然后在create.sh文件中写入如下命令
# 启动6个Redis服务器
./root/redis/src/redis-server /root/redis/cluster/7001/redis.conf
./root/redis/src/redis-server /root/redis/cluster/7002/redis.conf
./root/redis/src/redis-server /root/redis/cluster/7003/redis.conf
./root/redis/src/redis-server /root/redis/cluster/7004/redis.conf
./root/redis/src/redis-server /root/redis/cluster/7005/redis.conf
./root/redis/src/redis-server /root/redis/cluster/7006/redis.conf
# 创建集群
cd /root/redis/utils/create-cluster
./create-cluster create
然后直接执行这个create.sh文件即可
cd /root/redis/
./cluster/create.sh
启动成功后,就可以在命令行测试集群,如下命令所示
# 登录集群: -c 代表集群形式登录 -p 登录端口 -a 登录密码
redis-cli -c -p 7001 -a Ms123!@#
# 然后执行如下命令
set key1 value1
set key2 value2
set key3 value3
set key4 value4
set key5 value5
set key6 value6
再补充一下start.sh
和shutdown.sh
cd /root/redis/utils/create-cluster
./create-cluster start
cd /root/redis/utils/create-cluster
./create-cluster stop
在Spring中使用Redis集群
集群配置文件如下
package com.sr.config;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration.JedisClientConfigurationBuilder;
import org.springframework.data.redis.core.StringRedisTemplate;
import redis.clients.jedis.JedisPoolConfig;
@Configuration
public class RedisClusterConfig {
/**
* Redis连接池配置
* @return 连接池
*/
@Bean("redisPoolConfig")
public JedisPoolConfig poolConfig() {
JedisPoolConfig poolCfg = new JedisPoolConfig();
// 最大空闲数
poolCfg.setMaxIdle(50);
// 最大连接数
poolCfg.setMaxTotal(100);
// 最大等待毫秒数
poolCfg.setMaxWaitMillis(20000);
return poolCfg;
}
@Bean("clusterConfig")
public RedisClusterConfiguration clusterConfig() {
// 集群节点
Set<String> nodes = new HashSet<>(Arrays.asList(
"192.168.44.129:7001",
"192.168.44.129:7002",
"192.168.44.129:7003",
"192.168.44.129:7004",
"192.168.44.129:7005",
"192.168.44.129:7006"
));
// 创建RedisClusterConfiguration对象
RedisClusterConfiguration config = new RedisClusterConfiguration(nodes);
// 设置密码
config.setPassword("Ms123!@#");
return config;
}
/**
* 创建Jedis连接工厂
* @param jedisPoolConfig
* @return 连接工厂
*/
@Bean("redisConnectionFactory")
public RedisConnectionFactory redisConnectionFactory(@Autowired RedisClusterConfiguration clusterConfig, @Autowired JedisPoolConfig jedisPoolConfig) {
// 获得默认的连接池构造器
JedisClientConfigurationBuilder jpcb = JedisClientConfiguration.builder();
// 设置Redis连接池
jpcb.usePooling().poolConfig(jedisPoolConfig);
// 获取构建器
JedisClientConfiguration jcc = jpcb.build();
// 使用RedisClusterConfiguration创建连接工厂
return new JedisConnectionFactory(clusterConfig, jcc);
}
/**
* 创建StringRedisTemplate
* @param connectionFactory 连接工厂
* @return StringRedisTemplate对象
*/
@Bean("stringRedisTemplate")
public StringRedisTemplate stringRedisTemplate(@Autowired RedisConnectionFactory connectionFactory) {
// 创建StringRedisTemplate对象
StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
// 设置连接工厂
stringRedisTemplate.setConnectionFactory(connectionFactory);
return stringRedisTemplate;
}
}
测试代码如下
public static void testCluster() {
// 创建IoC容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(RedisClusterConfig.class);
StringRedisTemplate redisTemplate = applicationContext.getBean(StringRedisTemplate.class);
// 设置值
redisTemplate.opsForValue().set("key1", "value1");
redisTemplate.opsForValue().set("key2", "value2");
redisTemplate.opsForValue().set("key3", "value3");
redisTemplate.opsForValue().set("key4", "value4");
redisTemplate.opsForValue().set("key5", "value5");
redisTemplate.opsForValue().set("key6", "value6");
// 获取值并打印
String value = redisTemplate.opsForValue().get("key1");
System.out.println(value);
}