10 min read

Redis入门

Redis 入门
Redis入门

Redis 安装

brew install redis

启动 redis server

redis-server

启动 redis 命令行连接

redis-cli
# 退出
quit/exit

redis-insight

redis-insight 下载链接 macos arm64

redis 基本类型

redis 字符串

redis 中的字符串区分大小写

SET key calue
GET key
DEL key
EXISTS key
keys * # 显示键, 以pattern查找,例如 *表示所有, *me表示me结尾的键
flushall #清空所有键, 成功返回 "OK"

SETNX key value 不存在 key 时设置 key 如果存在 key 不做任何操作

127.0.0.1:6379> SETNX k3 雷神
1
127.0.0.1:6379> SETNX k3 雷神
0 ##已存在,返回0

redis 中的内容以二进制存储,所以默认不支持中文

如果希望支持中文,启动时设置参数 --raw 以原始数据格式存储

redis-cli --raw

127.0.0.1:6379> set k1 大神
OK
127.0.0.1:6379> get k1
大神

设置过期时间

查看过期时间 TTL

TTL key

127.0.0.1:6379> TTL k1
-2 ## -2 表示过期

设置过期时间

EXPIRE key time

127.0.0.1:6379> EXPIRE k1 10 # 单位是second秒
1

设置一个具有过期时间的键值对

SETEX key seconds value
127.0.0.1:6379> SETEX k2 50 小神
OK
127.0.0.1:6379> ttl k2
41

redis 列表

LPUSH RPUSH 添加到头部和尾部

LPUSH listname element

在列表的首部添加元素

> LPUSH list1 a b c d e f g
(integer) 7

> LRANGE list1 0 -1
1) "g"
2) "f"
3) "e"
4) "d"
5) "c"
6) "b"
7) "a"

RPUSH listname element

在列表的尾部添加元素

> RPUSH list2 a b c d e f g
(integer) 7

> LRANGE list2 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"
6) "f"
7) "g"

LPOP RPOP 从列表的首尾删除元素

LPOP listname count

> LPOP list2 3
1) "a"
2) "b"
3) "c"

RPOP listname count

> RPOP list2 3
1) "g"
2) "f"
3) "e"

LTRIM 修剪列表, 只保留参数范围内的元素

LTRIM key start stop start 与 stop 都是闭区间

> LRANGE list1 0 -1
1) "g"
2) "f"
3) "e"
4) "d"
5) "c"
6) "b"
7) "a"

> LTRIM list1 2 5
"OK"

> LRANGE list1 0 -1
1) "e"
2) "d"
3) "c"
4) "b"

redis 集合 SET

无序集合, 元素不能重复

SEt 相关的命令都是 S 开头

添加元素

SADD key member , 如果存在返回 0

查看所有元素

SMEMBERS key

判断是否存在元素

SISMEMBER key member

删除元素

SREM key member,返回 1 表示成功

> SADD set1 redis mysql java c++
(integer) 4

> SMEMBERS set1
1) "redis"
2) "mysql"
3) "java"
4) "c++"

> SADD set1 redis
(integer) 0

> SISMEMBER set1 redis
(integer) 1

> SISMEMBER set1 python
(integer) 0

> SREM set1 redis
(integer) 1

集合操作

TODO:

SINTER SUNION SDIFF

Sorted SET 有序集合 / ZSET

添加元素

ZADD key score member

显示元素

ZRANGE key start stop

显示元素和分数

ZRANGE key start stop WITHSCORES

> ZADD zset1 100 english 120 math 50 chemis 70 history
(integer) 4

> ZRANGE zset1 0 -1
1) "chemis"
2) "history"
3) "english"
4) "math"

> ZRANGE zset1 0 -1 WITHSCORES
1) "chemis"
2) "50"
3) "history"
4) "70"
5) "english"
6) "100"
7) "math"
8) "120"

查找某个元素的分数

ZSCORE key member

> zscore zset1 math
"120"

查看从小到大的排名:

ZRANK key number

> ZRANK zset1 math
(integer) 3

> zrank zset1 math withscore
1) "3"
2) "120"

从大到小排名:

> ZREVRANK zset1 math
(integer) 0

HASH 键值对集合

设置键值对
HSET key field value
获取键值对
HGET key field
获取全部键值对
HGETALL key
删除键值对
HDEL key field
获取所有 key
HKEYS key
获取所有键值对数量
HLEN key

> HSET person name yue
(integer) 1

> HSET person age 24
(integer) 1

> HGET person name
"yue"

> HGET person age
"24"

> HGETALL person
1) "name"
2) "yue"
3) "age"
4) "24"

> HDEL person age
(integer) 1

发布订阅功能

消息无法持久化, 无法记录历史消息

PUBLISH

创建一个发布频道
PUBLISH channel message

127.0.0.1:6379> publish losto redis
1

SUBSCRIBE

订阅一个频道
SUBSCRIBE channel

SUBSCRIBE losto
subscribe
losto
1
message
losto
redis

STREAMS 消息队列

轻量级的消息队列

创建消息

添加消息
XADD key id field value 消息的 id 格式默认为Timestamp-num,可以手动指定num-num,但必须要保证自增

查看长度
XLEN key

查看所有元素

XRANGED key - +
删除元素
XDEL key id
使用 trim 删除所有消息
XTRIM key MAXLEN 0

> XADD losto * course redis
"1725503802356-0"

> XLEN losto
(integer) 4

> XRANGE losto - +
1) 1) "1725503802356-0"
   2) 1) "course"
      2) "redis"
2) 1) "1725503807889-0"
   2) 1) "course"
      2) "git"
3) 1) "1725503810585-0"
   2) 1) "course"
      2) "c"
4)  1) "1725503947329-0"
   2) 1) "math"
      2) "100"

> XDEL losto 1725503802356-0
(integer) 1

> XTRIM losto MAXLEN 0
(integer) 4

消费消息

XREAD [COUNT count] [BLOCK milliseconds] STREAMS key index

count 读取数量

block 规定如果没有消息那么阻塞的时间

index 从 0 开始

> XREAD COUNT 3 BLOCK 1000 STREAMS losto 0
1) 1) "losto"
   2) 1) 1) "1725504525977-0"
         2) 1) "math"
            2) "100"
      2) 1) "1725504536271-0"
         2) 1) "eng"
            2) "99"
      3) 1) "1725504541915-0"
         2) 1) "che"
            2) "99"

使用$来获取最新的消息

  • 消费者

    > XREAD COUNT 3 BLOCK 100000 STREAMS losto $
    1) 1) "losto"
    2) 1) 1) "1725505331545-0"
            2) 1) "name"
                2) "liu"
    
  • 生产者

    XADD losto * name liu
    

创建消费者组
XGROUP CREATE key group id

> XGROUP CREATE losto group1 0
"OK"

查看消费者组的信息

> XINFO GROUPS losto
1) 1) "name"
   2) "group1"
   3) "consumers"
   4) "0"
   5) "pending"
   6) "0"
   7) "last-delivered-id"
   8) "0-0"
   9) "entries-read"
   10) "null"
   11) "lag"
   12) "9"

创建消费者
XGROUP CREATECONSUMER key group consumer

> XGROUP CREATECONSUMER losto group1 consumer3
(integer) 1

使用消费者组读取消息, 参数>表示未被组内消费的起始消息

> XREADGROUP GROUP group1 consumer1 COUNT 2 BLOCK 3000 STREAMS losto >
1) 1) "losto"
   2) 1) 1) "1725504525977-0"
         2) 1) "math"
            2) "100"
      2) 1) "1725504536271-0"
         2) 1) "eng"
            2) "99"

Geospatial

v3.2
添加地理位置
GEOADD key longitude latitude member

> GEOADD city 116 39 beijing
(integer) 1

添加后获取地理位置
GEOPOS key member

 GEOPOS city beijing
1) 1) "116.00000113248825073"
   2) "38.99999918434559731"

计算地理位置距离
GEODIST key member member

> GEODIST city beijing shanghai KM
"999.2077"

地理位置搜索
GEOSEARCH key FROMMEMBER member BYRADIUS 1000 KM
BYRADIUS 使用圆形范围
BYBOX 使用矩形范围

> GEOSEARCH city FROMMEMBER shanghai BYRADIUS 1000 KM
1) "shanghai"
2) "beijing"

HyperLogLog

集合中的基数: 统计集合中唯一值的数量(做 distinct 处理后的数量)
一般用来处理网站的 UV(Unique Visitors) 浏览者

创建一个 HLL
PFADD key element ...
获得基数
PFCOUNT key
合并
PFMERGE destkey [sourcekey sourcekey]

> PFADD course git c java spring ngnix
(integer) 1

> PFCOUNT course
(integer) 5

> PFADD course2 go c++ java
(integer) 1

> PFMERGE result course course2
"OK"

> PFCOUNT result
(integer) 7

Bitmap 位图

字符串类型扩展
应用场景: 签到情况, 在线状态

设置
SETBIT key offset value
获取
GETBIT key offset

> SETBIT dianzan 0 1
(integer) 0

> SETBIT dianzan 1 0
(integer) 0

> GETBIT dianzan 0
(integer) 1

> GETBIT dianzan 1
(integer) 0

使用字符串命令设置
SET key value

 > SET dianzan "\xF0" # 16进制的 11110000
"OK"

获取位图中 1 的个数
BITCOUNT key

> BITCOUNT dianzan
(integer) 4

获取第一次出现 0/1 的位置
BITPOS key bit [start [end]]

Bitfield

将小的整数存储到位图节省内存

设置一个位域
BITFIELD key SET encoding offset value
获取位域的值
BITFIELD key GET encoding offset
增加位域的值
BITFIELD key INCRBY encoding offset incrementvalue

> BITFIELD player:0 SET u8 #0 1
1) "0"

> BITFIELD player:0 GET u8 #0
1) "1"

> BITFIELD player:0 SET u32 #1 100
1) "0"

> BITFIELD player:0 GET u32 #1
1) "100"

> BITFIELD player:0 INCRBY u32 #1 100
1) "200"

> BITFIELD player:0 GET u32 #1
1) "200"

Redis 支持事务

在一次请求中执行多个命令

MULTI
    SET
    LPUSH
    SADD
EXEC/DISCARD

不同于关系型数据库, 没有原子性操作,但保证:

  • 发起 EXEC 命令前,所有命令都会被放到队列缓存起来,不会立即执行;
  • 收到 EXEC 命令后,事务开始执行,任何一个事务执行失败,其他命令依然会执行;
  • 事务执行过程中,其他客户端请求的命令不会被插入到事务执行命令序列中;
> MULTI
"OK"

> SET k1 v1
"QUEUED"

> SET k2 v2
"QUEUED"

> EXEC
1) "OK"
2) "OK"

错误不会影响后续事务

> SET k3 3
"OK"

> set k4 V4
"OK"

> set k5 5
"OK"

> multi
"OK"

> incr k3
"QUEUED"

> incr k4
"QUEUED"

> incr k5
"QUEUED"

> exec
1) "4"
2) "ReplyError: ERR value is not an integer or out of range"
3) "6"

>  get k3
"4"

> get k4
"V4"

> get k5
"6"

Redis 持久化

RDB redis database

某个时间点上数据的完整副本
vim redis.conf
macos 下的 redis 配置文件路径:
/opt/homebrew/etc/redis.conf
获取方法:

brew list redis
cat /opt/homebrew/Cellar/redis/7.2.5/homebrew.mxcl.redis.plist
## 得到/opt/homebrew/etc/redis.conf

打开 redis.conf
修改 save <seconds> <changes>
在指定时间有多少次修改才进行一次快照

 ################################ 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.
#
# 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

使用save命令手动执行快照会得到dump.rdb文件
将 dump.rdb 文件移动到 redis 安装目录, 重启 redis 会自动加载数据快照

127.0.0.1:6379> save
OK

bgsave 创建一个子进程来进行快照,创建子进程时间内没有办法进行秒级快照

AOF append only file

将 redis 中每个写操作以日志的形式记录, 当重启时执行,在内存中重建 redis 数据库

开启方法:
appendonly no -> appendonly yes

主从复制 Replication

将主节点(master)单向复制到从节点(slave)
一般主节点负责写, 从节点负责读
主节点将自己的数据变化异步方式发送到从节点,从节点更新数据

redis 默认启动的是主节点
查看当前角色:role

> role
1) "master"
2) "0"
3) (empty list or set)

配置所属主节点
命令行(不常用)

replicaof host port
/
slaveof host port(legacy)

配置文件设置从节点

# 1. 复制配置文件
 cp /opt/homebrew/etc/redis.conf redis-6380.conf
# 2. 更改配置文件
code redis-6380.conf
# port 6379 -> 6380
# pidfile /opt/homebrew/var/run/redis-6379.pid -> pidfile /opt/homebrew/var/run/redis-6380.pid 防止进程id重复
# dbfilename dump.rdb -> dbfilename dump-6380.rdb  执行save/bgsave时保存的数据库快照名
# # replicaof <masterip> <masterport> -> replicaof 127.0.0.1 6379 端口号指向主节点
# 3.启动
redis-server redis-6380.conf
# 4.连接
redis-cli -p 6380
# 5.查看info
info replication
# 输出如下信息
Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:3
master_sync_in_progress:0
slave_read_repl_offset:98
slave_repl_offset:98
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:9dfc0f4bc24761c9ac7d9fda79ce252b4b7c14ce
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:98
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:15
repl_backlog_histlen:84

此时主从节点的数据已经同步

哨兵模式

监控:监控集群中各个节点的状态, 通过不断发送命令检查节点正常
通知:发现某个节点出现问题,通过发布订阅模式通知其他节点
自动故障转移: 主当节点不能正常工作, 将其中一个从节点升级主节点, 将其他的从节点指向新的主节点

# 编写 sentinel.conf
vim sentinel.conf
# 添加如下内容:
sentinel monitor master 127.0.0.1 6379 1
# 退出并运行
redis-sentinel sentinel.conf

sentinel
生产环境中会用三个哨兵节点, 选出一个领导来监控其他节点, 当领导停止运行, 会有其他哨兵接替领导位置,保证哨兵节点的高可用性