Redis
简介
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
相关网站
- 官网 👉 https://redis.io/
- Windows版本下载 👇
- Linux安装
apt install redis-server
或用 Docker 安装- Redis命令大全 👉 http://www.redis.cn/commands.html
常用命令
redis-cli
连接redis
redis-cli -h 127.0.0.1 -p 6379 # -c 连接集群结点时使用,此选项可防止moved和ask异常 # -a 密码
切换数据库
# 默认有16个数据库(0-15) select 1 select 16 # (error) ERR DB index is out of range
查看数据库数据量
dbsize
查看数据库所有的key
keys *
存值、取值
set key1 v1 # OK get key1 # "v1"
清空数据操作
# 清除当前数据库 flushdb # 清除所有数据库(慎用) flushall
判定键是否存在
exists key1
移动某个键到某个数据库
move key1 1
设置键的过期时间,查看键的剩余过期时间
expire key1 10 # 10秒后过期 ttl key1
查看数据类型
type key1 # string
数据类型
string
末尾追加字符串
append key1 xxx # 键不存在时,等于set操作
自增、自减操作
set view_num 0 # 自增 incr view_num # 自减 decr view_num # 以步长为10,自增 incrby view_num 10
截取、替换字符串
set key1 abcdefg # 截取下标为1-3位的字符 [1,3] getrange key1 1 3 # bcd # 截取全部(等于查看全部) getrange key1 0 -1 # 从下标第2个字符开始替换后面的字符为xx setrange key1 2 xx # "abxxefg"
setex、setnx(分布式锁、乐观锁常用)
# 设置过期时间并赋予新值 setex set_with_expire 30 'newData' # 不存在键的时候赋值,存在无法赋值 setnx set_if_not_exist 'data' setnx set_if_not_exist 'newData' get set_if_not_exist # "data"
存取多值
mset k1 v1 k2 v2 k3 v3 mget k1 k2 k3 # msetnx 原子性操作,失败一个都失败 msetnx k1 v1 k4 v4
getset
# 先获取在设置值 getset k6 v6 # (nil) getset k6 v6_new # "v6" get k6 # "v6_new"
list
lpush
lpush list_key firstValue lpush list_key secondValue thirdValue lrange list_key 0 -1 # 1) "thirdValue" # 2) "secondValue" # 3) "firstValue"
rpush
rpush list_key right_side lrange list_key 0 -1 # 1) "thirdValue" # 2) "secondValue" # 3) "firstValue" # 4) "right_side"
lpop、rpop
lpop list_key rpop list_key lrange list_key 0 -1 # 1) "secondValue" # 2) "firstValue"
lindex
lindex list_key 1 # "firstValue"
llen
llen list_key # (integer) 2
lrem
lrem list_key 1 secondValue
ltrim
lpush list_key2 a b c d e f g # 通过下标截取list ltrim list_key2 3 5 lrange list_key2 0 -1 # 1) "d" # 2) "c" # 3) "b"
rpoplpush
lpush list_key3 1 2 3 4 5 # 移动一个list最右边的,加在另一个list的最左边 rpoplpush list_key3 list_key4 lrange list_key3 0 -1 # 1) "5" # 2) "4" # 3) "3" # 4) "2" lrange list_key4 0 -1 # 1) "1"
exists
exists list_key3 list_key4
lset
lset list_key4 0 one lrange list_key4 0 0 # 1) "one"
linsert
linsert list_key4 before "one" "before" linsert list_key4 after "one" "after" lrange list_key4 0 -1 # 1) "before" # 2) "one" # 3) "after"
set
sadd
sadd set_key firstValue secondValue thirdValue sadd set_key secondValue smembers set_key # 1) "secondValue" # 2) "thirdValue" # 3) "firstValue"
sismember、scard
# 是否存在某个元素 sismember set_key thirdValue # (integer) 1 # set集合中的元素个数(set cardinality) scard set_key # (integer) 3
srem
# 移除某个元素 srem set_key secondValue
srandmember
sadd set_key2 a b c d e f g h i j k l m n o p q r s t u v w x y z # 随机取5个元素 srandmember set_key2 5
smove
# 移动一个元素到另外一个set中 smove set_key2 set_key3 a
sdiff、sinter、sunion
sadd set_key4 1 2 3 4 sadd set_key5 3 4 5 6 # 第一个set的差集 sdiff set_key4 set_key5 # 1) "1" # 2) "2" # 交集 sinter set_key4 set_key5 # 1) "3" # 2) "4" # 并集 sunion set_key4 set_key5
hash
hset
hset hash_key field1 v1 field2 v2 hget hash_key field1 field2 # "v1" hmget hash_key field1 field2 # 1) "v1" # 2) "v2" hgetall hash_key # 1) "field1" # 2) "v1" # 3) "field2" # 4) "v2"
hdel
# 删除某个字段 hdel hash_key field1
hlen、hkeys、hvals
hset hash_key field1 v1 field2 v2 field3 v3 field4 v4 field5 v5 # 获取map长度 hlen hash_key # (integer) 5 # 获取所有字段 hkeys hash_key # 1) "field2" # 2) "field1" # 3) "field3" # 4) "field4" # 5) "field5" # 获取所有的值 hvals hash_key # 1) "v2" # 2) "v1" # 3) "v3" # 4) "v4" # 5) "v5"
hexists
# 是否存在某个字段 hexists hash_key field3
hincrby、hdecrby
hset hash_key num 0 # 自增、自减 hincrby hash_key num 5 hincrby hash_key num -3 hget hash_key num # "2"
zset
zadd
# 有序set zadd zset_key 2 secondValue 3 thirdValue zadd zset_key 1 firstValue zrange zset_key 0 -1 withscores
zcard
# 统计个数 zcard zset_key
zrevrange
# 倒序 zrevrange zset_key 0 -1 zrevrange zset_key 2 3 # 1) "firstValue" zrevrange zset_key -2 -1 withscores # 1) "secondValue" # 2) "2" # 3) "firstValue" # 4) "1"
zrem
# 删除指定元素 zrem zset_key secondValue
zcount
# 指定区间计数 zcount zset_key -inf +inf # (integer) 2 zcount zset_key 0 2 # (integer) 1
事务
MULTI 、 EXEC 、 DISCARD 和 WATCH 是 Redis 事务相关的命令。事务可以一次执行多个命令, 并且带有以下两个重要的保证:
- 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
- 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。
EXEC 命令负责触发并执行事务中的所有命令:
- 如果客户端在使用 MULTI 开启了一个事务之后,却因为断线而没有成功执行 EXEC ,那么事务中的所有命令都不会被执行。
- 另一方面,如果客户端成功在开启事务之后执行 EXEC ,那么事务中的所有命令都会被执行。
当使用 AOF 方式做持久化的时候, Redis 会使用单个 write(2) 命令将事务写入到磁盘中。
# 开启事务
127.0.0.1:6379[1]> multi
OK
# 开始输入命令
127.0.0.1:6379[1]> set k1 v1
QUEUED
127.0.0.1:6379[1]> get k1
QUEUED
127.0.0.1:6379[1]> set k2 v2
QUEUED
127.0.0.1:6379[1]> set k3 v3
QUEUED
127.0.0.1:6379[1]> keys *
QUEUED
127.0.0.1:6379[1]> setex k2 5 xxx
QUEUED
127.0.0.1:6379[1]> keys *
QUEUED
# 输入命令结束
# 触发并执行事务中的所有命令
127.0.0.1:6379[1]> exec
# 1) OK
# 2) "v1"
# 3) OK
# 4) OK
# 5) 1) "k2"
# 2) "k1"
# 3) "k3"
# 6) OK
# 7) 1) "k2"
# 2) "k1"
# 3) "k3"
# 再次验证k2是否过期
127.0.0.1:6379[1]> keys *
# 1) "k1"
# 2) "k3"
discard 放弃事务
Redis 不支持回滚(roll back),回滚并不能解决编程错误带来的问题
以下是这种做法的优点:
- Redis 命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上面:这也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中
- 因为不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速
check-and-set 操作实现乐观锁
- WATCH 命令可以为 Redis 事务提供 check-and-set (CAS)行为
管理客户端
自带的 redis-cli
RedisDesktopManager (高版本收费,0.9.3 免费)
下载地址 https://github.com/uglide/RedisDesktopManager/releases/tag/0.9.3
RedisInsight
下载地址 https://docs.redis.com/latest/ri/installing/install-redis-desktop/
单机启动
# windows下 配置好 redis.windows.conf cmd中运行 redis-server redis.windows.conf
# Docker
docker run -itd --name redis-test-pw -p 6379:6379 redis --requirepass "password"
集群启动(三台机器,三主三从,Docker版)
虚拟机3台Liunx设备
# 这里用 Ubuntu 22.04 系统 # 3台设备的ip为 192.168.1.95 、 192.168.1.96 、 192.168.1.97
3台机器分别创建容器
# 192.168.1.95 docker create --name redis-node1 --net host -v /data/redis-data/node1:/data redis --cluster-enabled yes --cluster-config-file nodes-node-1.conf --port 6379 --requirepass "password" --masterauth "password" docker create --name redis-node2 --net host -v /data/redis-data/node2:/data redis --cluster-enabled yes --cluster-config-file nodes-node-2.conf --port 6380 --requirepass "password" --masterauth "password" # 192.168.1.96 docker create --name redis-node3 --net host -v /data/redis-data/node3:/data redis --cluster-enabled yes --cluster-config-file nodes-node-3.conf --port 6379 --requirepass "password" --masterauth "password" docker create --name redis-node4 --net host -v /data/redis-data/node4:/data redis --cluster-enabled yes --cluster-config-file nodes-node-4.conf --port 6380 --requirepass "password" --masterauth "password" # 192.168.1.97 docker create --name redis-node5 --net host -v /data/redis-data/node5:/data redis --cluster-enabled yes --cluster-config-file nodes-node-5.conf --port 6379 --requirepass "password" --masterauth "password" docker create --name redis-node6 --net host -v /data/redis-data/node6:/data redis --cluster-enabled yes --cluster-config-file nodes-node-6.conf --port 6380 --requirepass "password" --masterauth "password"
启动容器,并设置docker重启始终启动策略
# 192.168.1.95 docker start redis-node1 redis-node2 docker update --restart=always redis-node1 redis-node2 # 192.168.1.96 docker start redis-node3 redis-node4 docker update --restart=always redis-node3 redis-node4 # 192.168.1.97 docker start redis-node5 redis-node6 docker update --restart=always redis-node5 redis-node6
随意进入一个容器
docker exec -it redis-node6 bash
设置集群关系
redis-cli --cluster create 192.168.1.95:6379 192.168.1.95:6380 192.168.1.96:6379 192.168.1.96:6380 192.168.1.97:6379 192.168.1.97:6380 --cluster-replicas 1 # 中途输入 yes
测试集群
# 进入集群节点 redis-cli -c -h 192.168.1.95 -p 6379 -a password # 查看集群节点信息 cluster info # 查看配置信息 CONFIG GET *