Redis
基础知识:
Redis
是什么:
Redis
被描述为一个数据结构服务器,它允许将键映射到不同类型的值。它是一个基于内存的数据库,数据通常存储在内存中,因此具有快速的读写性能。
内存中的数据不会持久化到磁盘上,一但将
redis
服务关闭,数据将被丢弃
Redis
的工作原理:
Redis
采用了单线程的事件驱动模型。它使用一个主事件循环来处理客户端请求和其他事件。Redis
的单线程模型避免了多线程之间的竞争和同步开销,从而实现了高性能和低延迟。
Redis
采用单线程的事件驱动模型是指Redis
服务器在运行时只使用一个主线程来处理所有的客户端请求和其他事件,而不是采用多线程或多进程的方式。具体来说,
Redis
的主线程会启动一个事件循环(event loop),它会不断地监听并接收来自客户端的请求,以及其他系统事件,如定时器事件、文件事件等。当有事件发生时,事件循环会根据事件的类型进行相应的处理。事件驱动模型的工作原理如下:
- 接收客户端请求:当有客户端连接到
Redis
服务器时,事件循环会接收到连接事件,并创建相应的套接字来与客户端进行通信。- 处理请求:一旦有请求到达,事件循环会将该请求放入队列中,然后按照顺序逐个处理。由于
Redis
采用单线程,它可以确保每个请求的原子性,避免了多线程之间的竞争条件。- 非阻塞操作:
Redis
的事件循环是非阻塞的,意味着它不会等待某个操作完成才能处理其他事件。当某个请求需要执行耗时的操作(例如读写磁盘),Redis
会将该操作转化为非阻塞的异步操作,然后继续处理其他事件。- 响应请求:一旦处理完一个请求,
Redis
会将结果返回给客户端,并继续监听其他事件。通过采用单线程的事件驱动模型,
Redis
能够避免多线程或多进程之间的上下文切换开销,并能更好地利用计算资源。虽然Redis
是单线程的,但它通过异步非阻塞的方式处理耗时操作,从而保持了高性能和低延迟的特性。
思考:多线程环境下的
redis
(基于单线程)它可以保证数据在多线程环境的安全吗?Redis 的单线程模型确保了在多线程环境下 Redis 的数据安全性,但是在具体的业务场景中,可能需要保证数据的原子性和一致性,此时需要我们使用 Redis 提供的一些命令来实现。例如,Redis 提供的事务(Transaction)机制,可以将多个操作打包成一个事务进行执行,保证了这些操作的原子性。另外,Redis 还提供了一些原子性命令,例如 SETNX、INCRBY、HINCRBY 等,这些命令可以保证在多线程环境下对数据的操作是原子性的,不会出现并发问题。
Redis
的数据结构:
- 字符串(Strings):用于存储字符串、整数、浮点数等数据。
在Redis
中,可以使用Redis
提供的命令来对字符串数据结构进行增加(create)、读取(retrieve)、更新(update)和删除(delete)等操作。以下是一些常用的Redis
命令示例:
以下是使用Redis
命令进行增加、读取、更新和删除字符串值的示例:
-
创建或设置字符串值:
SET mykey "Hello, Redis!"
-
获取字符串值:
GET mykey
-
更新字符串值:
SET mykey "Hello, World!"
-
追加字符串值:
APPEND mykey " Welcome!"
-
获取字符串长度:
STRLEN mykey
-
删除字符串值:
DEL mykey
符串数据结构在具体的业务常做些什么呢?
- 缓存:字符串数据结构常被用作缓存存储。例如,将经常访问的数据存储为字符串,以避免频繁的数据库查询或计算操作,提高系统的性能和响应速度。
- 计数器:字符串数据结构可以用来实现计数器功能。通过将字符串的值设置为数字,并使用递增或递减命令,可以方便地进行计数操作,如统计网页浏览次数、用户点击次数等。
- 分布式锁:使用字符串数据结构可以实现分布式锁。通过将某个键设置为特定的字符串值,表示锁的状态,可以协调多个进程或线程对共享资源的访问,保证数据的一致性和安全性。
- 队列:字符串数据结构可以用来实现队列。通过在列表的一端进行插入操作,另一端进行弹出操作,可以实现先进先出(FIFO)的队列结构,用于消息队列、任务队列等场景。
- 消息发布与订阅:通过字符串数据结构的发布与订阅功能,可以将消息发布到特定的频道,并让订阅者接收和处理这些消息。这在实时通信、实时数据更新等场景中非常有用。
- 缓存失效时间设置:字符串数据结构可以设置过期时间,用于缓存数据的自动失效。通过为字符串设置过期时间,可以控制缓存数据的有效期,避免数据过时或占用过多的内存。
- 哈希表(Hashes):哈希表(Hashes)数据结构在Redis中提供了一种关联键和值的方式.
以下是使用Redis命令进行哈希表的增加、读取、更新和删除操作的示例:
-
创建或设置哈希表字段和值:
HSET user:id1 name "John" age 30
-
获取哈希表字段的值:
HGET user:id1 name
-
获取哈希表中所有字段和值:
HGETALL user:id1
-
更新哈希表字段的值:
HSET user:id1 age 31
-
删除哈希表字段:
HDEL user:id1 age
哈希表(Hashes)数据结构在具体的业务中有各种应用?
- 存储对象属性:哈希表可以用来存储对象或实体的属性。每个字段可以表示对象的一个属性,字段值则是对应属性的值。这在用户信息、商品信息等场景中非常常见。
- 缓存存储:哈希表可以用作缓存存储,将经常访问的数据存储在哈希表中,以提高读取性能。例如,将数据库查询结果存储在哈希表中,避免重复查询,加快数据访问速度。
- 表示关系:哈希表可以用于表示关系型数据。例如,在社交网络应用中,可以使用哈希表存储用户的好友关系、关注关系等。
- 计数器:哈希表可以用来实现计数器功能。每个字段可以表示一个计数器,字段值表示计数器的当前值。这在统计用户行为、计数访问次数等场景中很有用。
- 数据索引:哈希表可以用于数据索引和快速查找。例如,使用哈希表存储关键字和对应的数据项,可以快速定位和检索数据。
- 缓存失效时间设置:和字符串一样,哈希表字段也可以设置过期时间,用于缓存数据的自动失效。这对于需要定期更新和刷新的数据非常有用。
哈希表(Hash Table)是一种常用的数据结构,它是通过一个数组和链表来实现的。Redis 的哈希表被称为字典(Dictionary),每个字典节点保存了一个键值对。
- 列表(Lists):有序、可重复的字符串集合。
以下是使用Redis命令进行列表的增加、读取、更新和删除操作的示例:
-
在列表的左侧插入元素:
LPUSH mylist "element1" "element2" "element3"
-
在列表的右侧插入元素:
RPUSH mylist "element4" "element5" "element6"
-
获取列表指定范围内的元素:
LRANGE mylist 0 -1
-
获取列表指定位置的元素:
LINDEX mylist 2
-
更新列表指定位置的元素:
LSET mylist 1 "new_element"
-
删除列表指定元素的所有匹配项:
LREM mylist 0 "element3"
-
弹出并获取列表左侧的元素:
LPOP mylist
-
弹出并获取列表右侧的元素:
RPOP mylist
Redis中的有序列表(Sorted Sets)每个元素都与一个相关的分数(score)关联。这个分数是作为元素的排序依据,它决定了元素在有序列表中的位置。有序列表的内部实现是通过双向链表和压缩列表(ziplist)两种数据结构来支持
压缩列表将多个节点的数据按照一定的格式连续存储在一块内存中,减少了指针和链表结构的开销,从而节省了存储空间。
如果在插入元素到有序列表时没有显式地设置分数,Redis会默认将元素的初始分数设为0。这意味着如果没有指定分数,所有插入的元素将具有相同的分数,它们在有序列表中的排列顺序将按照它们被插入的顺序来确定。
- 排行榜:有序列表可以用来存储和管理排行榜数据。每个成员都有一个关联的分数,可以根据分数进行排序,并通过有序列表提供的操作,如范围查询、按分数范围获取成员等,方便地实现排行榜功能。
- 实时排名:有序列表可以用于实时统计和排名,例如统计网站的访问量、用户的活跃度等。通过有序列表的分数和成员的更新操作,可以实时更新并获取排名信息。
- 范围查询:有序列表支持根据分数范围进行查询,可以方便地获取在指定分数范围内的成员列表。这对于实现基于分数的范围查询功能非常有用,例如获取某个时间段内的数据。
- 带有权重的任务队列:有序列表的成员可以用作任务的
- 集合(Sets):无序、唯一的字符串集合。
使用Redis语言进行集合的增删改查时,可以使用以下命令和示例:
-
增加元素:
SADD myset value1 value2 value3
这个命令将元素
value1
、value2
和value3
添加到名为myset
的集合中。 -
删除元素:
SREM myset value1
这个命令将从
myset
集合中移除元素value1
。 -
查询元素数量:
SCARD myset
这个命令将返回
myset
集合中元素的数量。 -
判断元素是否存在:
SISMEMBER myset value1
这个命令将返回布尔值,表示
value1
是否存在于myset
集合中。 -
获取集合中的所有元素:
SMEMBERS myset
这个命令将返回
myset
集合中的所有元素。
Redis的集合数据结构底层使用哈希表来存储元素,哈希表使用键值对的方式存储数据,集合的元素存储在哈希表的键中。
- 有序集合(Sorted Sets):是Redis提供的一种有序的数据结构,它与普通集合(Set)类似,但每个元素都有一个与之关联的分数(score),用于进行元素的排序和排名。
有序集合的底层实现使用了跳跃表(Skip List)和哈希表(Hash Table),这使得有序集合具有高效的插入、删除和查找性能,平均时间复杂度为O(log N),其中N是有序集合中的元素数量。
跳表的核心思想是通过添加额外的索引层来加速数据的查找。除了水平方向的链表,跳表还维护了一系列垂直方向的索引链表。
插入新节点时,需要根据节点的值找到插入位置,并更新相应层级的指针。
原始链表是跳表中的第一层,它包含了所有的数据节点,而上方的索引层级用于加速查找操作。
在跳表中,选择性添加上方的索引层级是根据一定的概率来决定的。具体而言,对于每个节点,根据一定的概率(通常是1/2)来确定是否将该节点添加到上一层的索引中。
当一个节点被添加到上一层索引时,它会在上一层创建一个新的节点,同时保持与下方相同位置的节点的关联。这样就形成了一种垂直方向的链表结构,其中每个节点都与下方相同位置的节点或下一个节点相连接。
Level 3: --------------------------------------> NIL Level 2: --------------> 5 ------------------> 8 --> NIL Level 1: ------> 2 ------> 5 ------> 6 ------> 8 --> 9 --> NIL Level 0: 1 --> 2 --> 3 --> 5 --> 6 --> 8 --> 9 --> 12 --> NIL
跳表可以在进行查找操作时,通过上方索引层级快速定位到目标区域,然后在原始链表中进行进一步的查找。同时,跳表的每个节点也包含实际存储的数据。当要查找某个值时,可以从最高层开始,逐层跳跃,最终到达目标节点,从而实现了快速查找。
- Bitmap(位图):用于处理位级别的操作,如记录用户签到、统计布隆过滤器等。
# 设置位图
SETBIT key offset value
# 获取位图
GETBIT key offset
# 统计位图指定区间内的值为 1 的位数
BITCOUNT key [start] [end]
# 获取位图指定区间内的值
GETRANGE key start end
# 统计多个位图并集指定区间内的值为 1 的位数
BITOP AND destkey key [key ...]
# 删除位图
DEL key
Bitmap可以表示一个很大的二进制数,它可以有非常大的位数。在Redis中,Bitmap是通过字符串类型来表示,每个字符都可以看作是8个二进制位(一个字节)的存储单元。
bitmap存储完1、0这些数据之后,会将它变为字符串。bitmap中存放000 1111。000 1111 存放在一个字节中,二进制表示为 00001111,转为十六进制表示为 0x0F。因此,存储 000 1111 的字符串就是 '\x0F'。
- HyperLogLog:用于基数统计(Cardinality Estimation),可以估计一个集合中的不重复元素个数。
可以使用以下命令进行HyperLogLog的增删改查操作:
- 添加元素(Add Element):使用PFADD命令将一个或多个元素添加到HyperLogLog中,语法为
PFADD key element [element ...]
。 - 获取基数估计(Get Cardinality Estimate):使用PFCOUNT命令获取HyperLogLog中的基数估计值,即不重复元素的个数,语法为
PFCOUNT key [key ...]
。 - 合并多个HyperLogLog数据(Merge HyperLogLogs):使用PFMERGE命令将多个HyperLogLog数据进行合并,生成一个新的HyperLogLog,语法为
PFMERGE destkey sourcekey [sourcekey ...]
。
HyperLogLog是一种概率性的数据结构,它通过使用一定的空间来实现近似的基数估计,而不是精确的计数。
HyperLogLog主要用于统计一些大规模数据的基数(cardinality),即不重复元素的数量。它在一些大数据场景中被广泛使用,例如社交网络中的用户统计、搜索引擎中的关键词统计等。同时,由于HyperLogLog在内存占用方面表现优异,它也被广泛应用于分布式系统中,如大规模的分布式计算和分布式存储系统等。
- Geospatial(地理空间索引):用于存储和查询地理位置信息,支持范围查询和附近位置搜索。
将这些数据存储到 Geospatial 数据结构中,然后可以使用 Geospatial 数据结构来执行各种查询,如:
- 查找一个给定经纬度附近的其他地点。
- 查找一个给定地点周围的地点。
- 查找位于某个给定矩形范围内的所有地点。
- 查找位于某个给定圆形范围内的所有地点。
# 将纬度为 37.7749,经度为 -122.4194 的地点添加到名为 "locations" 的 Geospatial 数据结构中
127.0.0.1:6379> GEOADD locations -122.4194 37.7749 "San Francisco"
# 将纬度为 40.7484,经度为 -73.9857 的地点添加到名为 "locations" 的 Geospatial 数据结构中
127.0.0.1:6379> GEOADD locations -73.9857 40.7484 "New York"
# 将纬度为 34.0522,经度为 -118.2437 的地点添加到名为 "locations" 的 Geospatial 数据结构中
127.0.0.1:6379> GEOADD locations -118.2437 34.0522 "Los Angeles"
# 查找距离纬度为 37.7749,经度为 -122.4194 的地点最近的其他地点,按距离排序(从近到远),返回结果包括距离和地点名
127.0.0.1:6379> GEORADIUS locations -122.4194 37.7749 1000 km WITHDIST WITHCOORD ASC
# 查找距离纬度为 40.7484,经度为 -73.9857 的地点周围 10 km 范围内的所有地点,返回结果包括距离和地点名
127.0.0.1:6379> GEORADIUS locations -73.9857 40.7484 10 km WITHDIST
# 查找位于纬度范围为 33.44 到 34.08,经度范围为 -118.41 到 -118.12 的矩形范围内的所有地点,返回结果只包括地点名
127.0.0.1:6379> GEORADIUSBYMEMBER locations "Los Angeles" 100 km
可以通过Geospatial索引快速查询附近的信息。一般来说,查询需要提供一个中心点的经度和纬度,以及一个半径范围。Geospatial会找到在这个半径范围内的所有数据点,并按照距离中心点的距离排序返回。
Geospatial 底层数据结构使用的是 Zset(Sorted Set),也就是有序集合。
在 Zset 中,每个元素都有一个分数(score)和一个成员(member)。在 Geospatial 中,每个元素的成员是地理位置,其对应的分数是一个叫做 geohash 的编码值,用于快速计算距离和查询附近的位置。
- Bloom Filter(布隆过滤器 ):是一种空间效率很高的数据结构,它利用位数组和哈希函数来快速判断一个元素是否存在于集合中。
-
BF.ADD:将元素添加到布隆过滤器中。
BF.ADD key element [element ...]
-
BF.MADD:批量将元素添加到布隆过滤器中。
BF.MADD key element [element ...]
-
BF.EXISTS:判断元素是否在布隆过滤器中。
BF.EXISTS key element
-
BF.MEXISTS:批量判断元素是否在布隆过滤器中。
布隆过滤器可以处理任何数据类型,它并不关心具体的数据内容,而是将数据通过哈希函数转换为一个固定长度的二进制向量,然后将二进制向量的每一位映射到一个位图中。
二进制数据放入布隆过滤器的bitmap时,并不是简单的进行位运算或取或操作。实际上,我们需要将这两个二进制数据分别作为索引值,定位到bitmap的对应位置,并将这些位置的值都设为1。
在布隆过滤器中,索引值的计算通常需要使用哈希函数。哈希函数将输入的数据映射成一个指定范围内的整数,该整数就是在布隆过滤器中的索引值。
简单来说:布隆过滤器会将输入的值(可以是任何类型的数据)先转换为二进制数,然后通过哈希函数进行映射为一个或多个int类型的索引值。这些索引值对应于布隆过滤器中的bitmap中的二进制位。最终,这些位会被标记为1,表示对应的元素可能存在于集合中。
- 安装和配置:学会在本地环境中安装和配置
Redis
,包括选择正确的版本、启动和停止Redis
服务器,以及设置适当的配置选项。
选择合适的 Redis 版本:可以从 Redis 的官方网站 (https://`redis`.io/download) 下载适用于的操作系统的 Redis 安装包。
解压 Redis 安装包:将下载好的 Redis 安装包解压到的目标文件夹。
启动 Redis 服务器:打开命令行工具,进入 Redis 的安装目录,输入 `redis`-server 命令来启动 Redis 服务器。
设置 Redis 配置选项:Redis 的默认配置文件为 `redis`.conf。可以修改此文件来配置 Redis 的行为。例如,可以更改 Redis 监听的端口,设置密码等。要修改默认配置,请将 `redis`.conf 文件复制到另一个位置,并在启动 Redis 服务器时指定配置文件路径,例如:`redis`-server /path/to/`redis`.conf。
连接 Redis 服务器:打开新的命令行工具,输入 `redis`-cli 命令来连接 Redis 服务器。如果 Redis 服务器在本地运行,并且使用默认端口,那么可以直接运行该命令。
测试 Redis 连接:在 Redis 客户端中,输入 ping 命令来测试与 Redis 服务器的连接。如果返回 PONG,则表示连接已成功。
关闭 Redis 服务器:在 Redis 客户端中,输入 shutdown 命令来关闭 Redis 服务器。如果想要以安全的方式关闭服务器,请使用 shutdown save 命令。这将导致 Redis 将所有挂起的写操作保存到磁盘上的持久性存储中,并在关闭服务器之前关闭所有客户端连接。
Redis 持久化:
- 快照持久化(snapshotting)
快照持久化是将Redis数据集以快照的形式写入磁盘的持久化方式。快照持久化可以通过配置Redis服务器的save
选项来设置快照的触发条件。例如,可以设置当在60秒内有10000个键被修改时,自动执行快照持久化操作。
快照持久化的优点是它非常简单、快速,并且可以最大程度地减少内存占用。缺点是在数据量大时会导致Redis服务器阻塞,因为Redis需要将整个数据集写入磁盘。此外,如果Redis在执行快照持久化时崩溃,则可能会丢失最后一次快照后的所有更改。
通过配置文件启动快照模式
在Redis的配置文件`redis
.conf中,可以设置
save`参数来控制快照的触发时间和条件,例如:
save 900 1 # 在900秒内,如果发生至少1次修改就执行快照
save 300 10 # 在300秒内,如果发生至少10次修改就执行快照
save 60 10000 # 在60秒内,如果发生至少10000次修改就执行快照
默认情况下,Redis的快照模式是关闭的。可以通过修改`redis
.conf中的
save`参数来启用快照模式。
通过命令行参数启动快照模式
可以在启动Redis服务时,通过命令行参数--save
`redis`-server --save "900 1" --dir /data/`redis`/data --dbfilename dump.rdb
Redis快照采用RDB(Redis DataBase)持久化方式,即将Redis在内存中的数据保存到磁盘上,形成快照文件。快照文件是一个二进制文件,它包含了某个时间点上Redis数据库的所有键值对数据。
Redis会先将内存中的数据写入一个临时文件中,待快照文件写入完毕后再替换原有的快照文件。
快照的触发条件设置为在XXX秒内,如果发生至少1次修改就执行快照
- AOF持久化
AOF持久化是将Redis的每个写命令追加到一个文件中的持久化方式。AOF文件是一个只追加文件(append-only file),因此在写入时不会有阻塞操作。AOF持久化可以通过配置Redis服务器的appendonly
选项来启用。
AOF持久化的优点是它可以提供更好的数据安全性,因为它将所有写命令都记录在文件中。此外,AOF文件的格式是文本格式,可以很容易地进行备份和恢复。缺点是AOF文件通常比快照文件更大,因此需要更多的磁盘空间。此外,在AOF文件变得非常大时,重写AOF文件可能需要较长的时间。
通过配置文件启动
- 修改
redis
.conf 文件,找到以下行:
# appendonly no
- 将
appendonly
的值从no
改为yes
:
appendonly yes
通过命令行参数启动
在命令行启动 Redis 时,可以通过 --appendonly yes
参数来启用 AOF 持久化模式。例如:
`redis`-server --appendonly yes
这样就可以启用 AOF 持久化模式,并将 AOF 文件保存在默认路径中。如果需要指定 AOF 文件的保存路径,可以使用 --appendfilename
参数。例如:
`redis`-server --appendonly yes --appendfilename "/path/to/appendonly.aof"
这样就可以将 AOF 文件保存在指定的路径中。
如果此时设置一个有效60min的key。在有效期还有30分钟的时候,
redis
服务关闭。采用aof保持数据。此时重启,这个key的有效期时60还是30?如果使用 AOF 模式保持数据,那么 Redis 在重启后会重新加载 AOF 文件,这个 key 的有效期应该是 30 分钟,因为在服务关闭时,这个 key 已经存在了 30 分钟,还剩下 30 分钟才会过期。所以即使 Redis 服务关闭了,AOF 文件也会记录下所有的写命令,包括键的过期时间,重启后会根据 AOF 文件的记录重新恢复数据和过期时间。
发布与订阅:
Redis的发布与订阅(Pub/Sub)功能可以用于消息的广播和订阅模式。它通过实现消息的生产者和消费者之间的解耦,使得生产者和消费者不需要知道彼此的存在,从而提高了系统的可扩展性和灵活性。
使用Redis的Pub/Sub功能需要以下步骤:
- 创建一个Redis连接,可以使用Jedis或Lettuce等Java Redis客户端库。
- 在生产者端,使用PUBLISH命令将消息发布到指定的频道(Channel)中。
- 在消费者端,使用SUBSCRIBE命令订阅一个或多个频道,等待接收消息。
- 当生产者发布消息时,所有订阅了该频道的消费者都会收到消息。
- 如果需要停止订阅某个频道,可以使用UNSUBSCRIBE命令。
import `redis`.clients.jedis.Jedis;
import `redis`.clients.jedis.JedisPubSub;
public class RedisPubSubExample {
public static void main(String[] args) {
// 创建Redis连接
Jedis jedis = new Jedis("localhost", 6379);
// 创建一个订阅者
JedisPubSub subscriber = new JedisPubSub() {
@Override
public void onMessage(String channel, String message) {
System.out.println("Received message: " + message + " from channel: " + channel);
}
};
// 订阅一个频道
jedis.subscribe(subscriber, "test-channel");
// 发布一个消息
jedis.publish("test-channel", "Hello, Redis Pub/Sub!");
// 取消订阅
subscriber.unsubscribe("test-channel");
// 关闭连接
jedis.close();
}
}
使用Redis Pub/Sub功能需要注意以下几点:
- Redis使用单线程处理所有请求,因此如果一个订阅者需要花费很长时间来处理消息,它将阻塞所有其他请求,包括发布者的请求。因此,消费者应该尽可能快地处理消息。
- 如果订阅者断开连接或关闭,它将无法接收到后续的消息。因此,消费者需要在程序中处理这种情况,例如通过重连等方式重新订阅频道。
- 如果需要同时订阅多个频道,可以使用PSUBSCRIBE命令,并使用通配符(例如“news.*”)来匹配多个频道。同时,还可以使用PUNSUBSCRIBE命令来取消订阅多个频道。
Redis的发布订阅功能则是在单个Redis实例内实现的,不支持跨节点和持久化存储。在发布订阅模式下,Redis通过频道(Channel)来组织消息,发布者发布消息到指定的频道,订阅者通过订阅频道来接收相应的消息。Redis的订阅模式支持多个订阅者同时订阅同一个频道,并支持按照模式匹配的方式订阅多个频道。
一个 Redis 节点实例发布的消息只能被同一个节点实例内的订阅者接收到。如果想要实现跨节点的消息发布与订阅,可以考虑使用 Redis 的集群功能
redis
事务:
Redis事务机制是指将多个命令封装为一个事务单元,并保证这些命令会按顺序执行,且在执行期间不会被其他客户端发送的命令所打断。Redis中的事务由MULTI、EXEC、WATCH和UNWATCH四个命令组成。
MULTI命令表示事务开始,之后的命令都将被放入一个队列中,直到执行EXEC命令时才会一次性执行队列中的所有命令。
MULTI
SET key1 value1
SET key2 value2
EXEC
MULTI命令表示开启一个事务,之后的两个SET命令将被放入一个队列中。最后执行EXEC命令,Redis会一次性执行队列中的两个命令。如果在EXEC命令执行之前,有其他客户端修改了key1或key2,则该事务将被回滚,key1和key2的值不会被修改。
使用WATCH命令可以在事务执行之前设置监视指定的键,如果在事务执行期间这些键被其他客户端修改,则会导致当前事务失败。
WATCH key
multi
set key 10
exec
WATCH命令的作用是在MULTI命令之前,为指定的键设置监视器,如果在事务执行期间这些键被其他客户端修改,则事务将被回滚。所以,WATCH命令通常用于乐观锁的场景中,以确保在事务期间,所依赖的键没有被其他客户端修改。
WATCH命令必须在MULTI命令之前使用,用于对指定的键进行监视。
Redis事务的隔离级别为读提交(read-committed),也就是说,事务中的每个命令在执行时都可以看到前面已经执行过的命令所作的修改,但是不能看到后面还未执行的命令所作的修改。
如果一个事务中有多个命令对同一个键进行操作,那么在执行EXEC命令时,这些操作会被一次性执行,并且执行结果只会反映出最后一条命令对该键所做的修改。
此外,由于Redis的单线程特性,在一个事务中执行的命令如果需要耗费很长时间才能完成,那么整个Redis实例在这段时间内都无法处理其他客户端的请求,因此需要谨慎使用事务。
Redis中的库是一种逻辑概念,用于区分不同的数据集。默认情况下,Redis提供了16个数据库,编号从0到15。每个数据库之间是相互独立的,你可以在每个数据库中使用相同的键,而不会发生冲突。
Redis这样分配库的原因是为了方便管理和使用。通过使用不同的库,你可以在一个Redis实例中存储多个数据集,而不必启动多个Redis实例。这可以降低系统的复杂度和成本。
redis
集群:
Redis集群是用于在多个Redis节点之间分片和复制数据的解决方案。它通过在多个节点之间分布数据来提高性能和可靠性。以下是Redis集群相关的一些知识:
-
Redis集群采用分布式哈希槽的方式对数据进行分片。每个节点负责处理一部分哈希槽中的数据。
Redis集群中每个节点只存储部分数据
-
Redis集群至少需要3个主节点才能工作。每个主节点都有至少一个从节点用于复制数据。如果一个主节点失效,其从节点会自动接管它的工作。
Redis集群的每个节点需要至少有一个从节点,但从节点不是必需的。一个Redis集群可以由三个节点或更多节点组成,每个节点处理一部分数据,并可以有自己的从节点进行数据备份和容错。但从节点并不是必需的,如果对数据的可用性要求不高,可以只使用主节点。
-
Redis集群使用Gossip协议来检测节点的状态。节点之间会周期性地交换消息来检测其他节点的状态。
Gossip协议是一种去中心化的通信协议,它通过在节点之间传播消息来更新和维护整个系统的状态。
在Redis集群中,Gossip协议的作用是用于节点之间的状态检测和故障恢复。每个节点会周期性地向其他节点发送消息来更新自己的状态信息,这些状态信息包括节点的IP地址、端口号、负责的哈希槽数量以及节点的健康状态等。如果节点发现某个节点状态异常(比如它没有回复消息),则会将这个节点标记为下线,并向其他节点广播这个消息。如果大多数节点都认为这个节点下线了,那么整个集群就会将这个节点从哈希槽中删除,并将槽迁移到其他节点上。
-
Redis集群支持读写分离,客户端可以将读操作发送到只读从节点,而写操作则发送到主节点。这可以提高读取性能,并减轻主节点的负载。
在Redis集群中使用读写分离需要在客户端上进行配置。
//将读写操作发送到只读从节点,可以使用Jedis对象的readOnly()方法。 Jedis jedis = jedisCluster.getResource(); jedis.readOnly(); String value = jedis.get("mykey"); jedis.close(); //要将写操作发送到主节点,只需要使用普通的Jedis对象即可 Jedis jedis = jedisCluster.getResource(); jedis.set("mykey", "myvalue"); jedis.close();
需要注意的是,只有在Redis集群的配置中将某些节点配置为只读从节点,才能正确地使用读写分离功能。可以通过在节点配置文件中设置
replicaof
属性来配置从节点。例如,以下配置将创建一个从节点,将其连接到主节点127.0.0.1:6379
上:replicaof 127.0.0.1 6379