2021-08-31 14:25:35

redis参考

[TOC]

REmote DIctionary Server(Redis) ,它通常被称为数据结构服务器。比memcache强在:

  1. 支持丰富的数据类型: String, List, Set, Sorted Set, Hash等。
  2. 支持2种持久化:快照和追加。
  3. 支持主从复制。 这个比memcache强多了。挂了1个节点不会影响整体的缓存。

由于redis支持持久化,所以不光是缓存,同时也是一个数据库。

本篇介绍一些基本的使用。

Redis的安装和使用

安装

mac 简单。直接brew install redis
gcc有版本要求,得gcc 4.8.2以上。可参考Centos6.8升级高版本gcc

gcc 4.8安装

# curl -Lks http://www.hop5.in/yum/el6/hop5.repo > /etc/yum.repos.d/hop5.repo

# yum install gcc gcc-g++ –y

# gcc  --version

linux下载并安装:

# wget http://download.redis.io/releases/redis-6.0.8.tar.gz
# tar xzf redis-6.0.8.tar.gz
# cd redis-6.0.8
# make

执行完 make 命令后,redis-6.0.8 的 src 目录下会出现编译后的 redis 服务程序 redis-server,还有用于测试的客户端程序 redis-cli, 性能测试工具redis-benchmark。可以用ls ./src -F | grep '*'查看编译完的工具。

下面启动 redis 服务:

# cd src
# ./redis-server
# ./redis-server ../redis.conf

redis不会自动安装。需要自己手动copy

# sudo cp redis.conf /etc/
# sudo cp redis-* /usr/bin/

链接

redis-cli -h 127.0.0.1 -p 6379 -a "mypass"

注意:密码是-a

修改Redis配置文件

参考

配置项参考

以下为redis 的部分配置文件以属性值:

配置名 含义 默认值 可选值 是否支持热生效
常规配置
daemonize 是否是守护进程 no yes,no 不支持
supervised 是upstart还是systemd接管redis进程 no no,upstart,systemd,auto 不支持
pidfile 进程文件 /var/run/redis.pid 可自定义文件路径 不支持
loglevel 日志级别 notice debug,verbose,notice,warning 可以
logfile 日志文件路径 自定义 不支持
syslog-enabled redis系统日志 no yes,no 不支持
syslog-facility 系统日志facility local0 local0-local7 不支持
databases 可用的数据库数, 通过select命令选择数据库。 16 整数 不支持
文件引用
include 包含外部的配置文件 可自定义文件路径 不支持
网络
bind 如果不配置,则可接受来自于所有网络的连接 127.0.0.1 ip,多个ip 不支持
protected-mode 可与bind 组合使用,默认开启,如果redis 没有设置密码,同时bind为空,则在使用客户端连接的时候会进行提示 yes yes,no 不支持
unixsocket unix套接字 空(不通过unix 套接字来监听) 指定套接字文件 不支持
unixsocketperm unix套接字权限 0 Linux三位数权限 不支持
timeout 客户端N秒没有发送数据,自动断开连接 默认禁用 0 整数 不支持
tcp-keepalive 如果值非0,单位是秒。表示将周期性的使用SO_KEEPALIVE检测客户端是否还处于健康状态。避免服务器一直阻塞,官方给出的建议值是300S(3.2.1之后) 0 整数 不支持
RDB快照
save RDB的保存条件 900秒更新了一个key 300秒更新了10个key 60秒更新了10000个key 都会进行rdb保存 save 900 1 save 300 10 save 60 10000 如果没有该配置则使用自动RDB策略 支持
stop-writes-on-bgsave-error bgsave执行错误是否停止Redis接收写请求 yes yes,no 支持
rdbcompression RDB文件是否压缩 yes yes,no 支持
rdbchecksum RDB文件是否使用校验和 yes yes,no 支持
dbfilename RDB文件名称 dump.rdb 自命名 建议使用dump-{port}.rdb 支持
dir RDB文件存放目录 redis安装目录 自定义文件路径 支持
主从复制
slaveof 指定当前从节点复制哪个主节点 ip port 不支持 但可以用slaveof命令设置
requirepass 密码 自定义 支持
masterauth 主节点密码 主节点的密码 支持
slave-serve-stale-data 当从节点与主节点连接中断时,如果此参数设置为yes 则从节点可以继续处理客户端的请求。否则除info和slaveof命令之外,拒绝所有的请求并统一回复: “SYNC with master in progress” yes yes,no 支持
slave-read-only 从节点是否只读 yes yes,no 支持
repl-diskless-sync 是否开启无盘复制 no yes,no 支持
repl-diskless-sync-delay 开启无盘复制后,延迟多少秒后进行RDB的操作,一般用于同时加入多个从节点时,保证多个从节点共享RDB 5 整数 支持
repl-ping-slave-period 主节点定期向从节点发送ping命令,用来判断从节点是否存活(单位:秒) 10 整数 支持
repl-timeout 主节点复制超时时间,秒 60 整数 支持
repl-disable-tcp-nodelay 是否开启主从复制socket的NO_DELAY选项: yes:Redis会合并小的TCP包来节省带宽,但是这要增加同步延迟,造成主从 数据不一致;no:主节点会立即同步数据,没有延迟 no yes,no 支持
repl-backlog-size 复制积压缓冲区大小 1M 整数 支持
repl-backlog-ttl 主节点在没有从节点的情况下多久后释放复制积压缓存区空间 3600 整数 支持
slave-priority 从节点的优先级 100 0-100 支持
min-slaves-to-write 当主节点发现从节点数量小于min-slaves-to-write 且延迟小于等于min-slaves-max-lag时,master停止写操作。 0 整数 支持
min-slaves-max-lag 同上 10 整数 支持
slave-announce-ip Redis Sentinel可以使用该信息来发现slave实例。 ip 支持
slave-announce-port 同上 port 支持
安全
requirepass 密码 自定义 支持
内存策略
maxclients 最大客户端连接数 10000 整数 支持
maxmemory 节点的最大内存 无限制 不能大于物理内存 支持
maxmemory-policy redis 内存淘汰策略 noeviction volatile-lru:在设置过期时间的key中,剔除最少使用的key
allkeys-lru:在所有的key中剔除最少使用的Key
volatile-random:在过期时间key中,随机剔除
allkeys-random:在所有的key中,随机剔除
volatile-ttl:在设置过期的key中,优先剔除即将过期的key
noeviction:不做任何操作,直接返回oom异常
支持
maxmemory-samples 上面LRU和最小TTL策略并非严谨的策略,而是大约估算的方式,因此可以选择取样值以便检查 5 整数 支持
AOF相关配置
appendonly 是否开启AOF持久化模式 no yes,no 支持
appendfilename aof文件名称 appendonly.aof 建议:appendonly-{port}.aof 不支持
appendfsync aof同步磁盘频率 everysec everysec,always,no 支持
no-appendfsync-on-rewrite 设置为yes,表示rewrite期间对新的写操作不fsync,暂时放入缓冲区,等rewrite完成之后再写入 no yes,no 支持
auto-aof-rewrite-percentage 触发rewrite的AOF文件增长比例条件 100 整数 支持
auto-aof-rewrite-min-size 触发rewrite的AOF文件最小阀值(单位:兆) 64 整数+m 支持
aof-load-truncated 加载AOF文件时,是否忽略AOF文件不完整的情况 yes yes,no 支持
Lua脚本
lua-time-limit Lua脚本超时时间单位:毫秒 5000 整数,但是此超时不会真正停止脚本运行 支持
Redis集群
cluster-enabled 是否开启redis 集群 yes yes,no 不支持
cluster-config-file 集群配置文件 nodes-6379.conf nodes-{port}.conf 不支持
cluster-node-timeout 集群节点超时时间,单位毫秒 15000 整数 支持
cluster-slave-validity-factor 从节点有效性判断因子,当从节点与主节点最后通信时间超过(cluster-node-timeout * slave-validity-factor + repl-ping-slave-period)时,对应从 节点不具备故障转移资格,防止断线时间过长的从节点进行故障转称。设置为0表示从节点永不过期。 10 整数 支持
cluster-migration-barrier 主从节点切换需要的从节点数最小个数。 1 整数 支持
cluster-require-full-coverage 集群是否需要所有的slot都分配给在线节点。才能正常访问。 yes yes,no 不支持
慢查询
slowlog-log-slower-than 慢查询被记录的阀值。单位:微秒 10000 整数 支持
slowlog-max-len 慢查询记录的条数。 128 整数 支持
latency-monitor-threshold Redis服务内存延迟监控,0代表关闭 0 整数 支持
高级选项
hash-max-ziplist-entries hash数据结构优化参数 512 整数 支持
hash-max-ziplist-value hash数据结构优化参数 64 整数 支持
list-max-ziplist-size list数据结构优化参数 -2 -5,-4,-3,-2,-1 支持
list-compress-depth list数据结构优化参数,0代表不可用 0 0,1,2,3 支持
set-max-intset-entries set数据结构优化参数 512 整数 支持
zset-max-ziplist-entries zset数据结构优化参数 128 整数 支持
zset-max-ziplist-value zset数据结构优化参数 64 整数 支持
hll-sparse-max-bytes hyperLogLog数据结构优化参数 3000 整数 支持
client-output-buffer-limit 客户端输出缓冲区限制 normal 0 0
slave 256mb 64mb 60
pubsub 32mb 8mb 60
整数 支持

编辑配置

  1. 直接修改配置文件redis.conf, 然后重启。
  2. 命令配置
    1. CONFIG SET name value
    2. 可通过 CONFIG GET name获取最新值。 config get *查看所有配置项。

主从同步

主服务器配置

bind 127.0.0.1 192.168.x.x # 指定只允许内网连接
# requirepass xxxx # 已经是内网可以不要密码

从服务器配置

slaveof 192.168.x.x 6379 #指定ip和端口
# masterauth xxx  我这里不设置,是因为只允许内网连接
slave-read-only yes

测试

主redis操作
从redis操作

命令

key

key不能包含空格和换行符。因为空格是分隔参数用的。换行是分隔命令用的。

命令列表如下(10个)

命令 描述
exits key key是否存在。1-存在。0-不存在
del key1 key2 ... keyN 删除给定的key, 返回删除key的数目。
type key 返回给定key的类型,none表示不存在key, String, List, Set
keys pattern 返回匹配指定模式的所有key, keys *返回所有key
expire key seconds 设置给定key的过期时间
randomkey 返回随机key, 没有则返回空串
rename oldkey newkey 重命名key,newkey已存在会被覆盖。1-成功,0-失败。失败可能是oldkey不存在或者和newkey相同
renamenx oldkey newkey 同上,但是newkey已存在时返回失败
ttl key 返回key剩余的过期时间。-1 表示key不存在或者没设置过
move key db-index 把key剪切到另一个数据库。1-成功。0-key不存在或者已经在db-index中

String

String是二进制安全的。可以存图片和文件。

struct sdshdr {
    long len; //buf累计空间。
    long free; //buf剩余可用空间。 len-free就是数据实际使用的空间。
    char buf[]; //保存字符串的内容。
}

String支持12个命令。

命令 描述
set key value 设置key对应的String类型的值。1-成功。0-失败
setex key expire value 设置值和过期时间。适合用这个替代memcache
setnx key value 同上,但是key已存在时返回失败。
get key 返回给定key的String值,nil表示不存在key
getset key value 先获取key的值,再设置key的值。nil表示不存在key。 相比memcache 要操作2次,redis一步到位。
mget key1 key2 ... keyN 批量获取key的对应值。如果对应的key不存在,则对应返回nil。 这也说明了一个缓存场景。不应该缓存sql查询的列表值,而是应该按主键id, 存若干条。这样可以节省存储空间。
mset key1 value1 key2 value2 ... keyN valueN 批量设置k/v。1-都设置。0-都没设置。
msetnx key1 value1 key2 value2 ... keyN valueN 同上,但是不会覆盖已经存在的key
incr key 原子自增1,适合做秒杀类活动。也能统计访问次数,但是不能统计给管理员看。
decr key 原子自减1
incrby key n 原子自增n
decrby key n 原子自减n

注意:如果一个字符串设定了过期时间,然后调用set方法修改了它,他的过期时间会小时。

List

是个双向链表。可以存访客列表。经常用来做消息队列,处理异步任务。

可以当队列用(2端操作),也可以当栈用(1端操作),用栈的场景很少。

内部实现不是传统的双链表。而是由ziplist组成的quicklist, 可以理解成 把ziplist理解成数组。

List类型支持12个命令

命令 描述
lpush key value1 value2 ... valueN 往key列表的头部插入value。1-成功。0-失败
rpush key value1 value2 ... valueN 往key列表的尾部插入value。1-成功。0-失败
llen key 返回key列表的长度。0-key对应的List不存在。key对应的类型不是List则返回错误
lindex key index 返回index位置的元素。实际很少使用。
lrange key start end 返回指定区间的元素(start-end)。下标从0开始。-1表示最后一个元素。 lrange key 0 -1就是遍历。
ltrim key start end 只保留指定区间的元素(start-end),区间外的删除。1-成功。key不存在返回错误。适合做定长的链表。
lset key index value 设置key对应List的index位置元素为value。1-成功。key不存在或者index不存在返回错误
lrem key count value 按顺序删除count个value的。返回设计删除的个数。count>0从头删。count<0从尾删。count=0全删
lpop key 弹出头部元素。list不存在或者为空,返回nil, 如果不是list则返回错误
rpop key 同上,弹出尾部元素。
blpop key1 key2 ...keyN timeout 从多个队列中尝试弹出头部元素。如果找不到,就阻塞timeout秒, 如果超时返回nil。timeout=0表示一直阻塞
brpop key1 key2 ...keyN timeout 同上,弹出尾部元素

Set

集合。内部是通过HashTable实现的。适合快速查找。譬如用户名排重, 当日投票只能一票等场景。
可以支持并查集。

有14个命令

命令 描述
sadd key member 添加元素到集合中。1-成功。0-member已经存在。错误-set不存在
srem key member 从key对应set中移除给定元素,成功返回1,如果member在集合中不存在 或者 key不存在返回0,如果key对应的不是set类型的值返回错误
spop key 删除并返回key对应set中随机的一个元素, 如果set是空或者key对应的set不存在返回nil
srandmember key 通spop, 随机取,但是不删除
smove srckey dstkey member 从srckey对应的set中移除member并添加到dstkey对应的set中,整个操作是原子的。成功返回1,如果member在srckey中不存在返回0,如果key对应的值不是set类型,返回错误。
scard key 返回set的元素个数,如果set是空或者key不存在返回0
sismember key member 判断member是否在set中,存在返回1,不存在或者key对应的set集合不存在返回0
sinter key1 key2 ...keyN 返回所有给定key的交集
sinterstore dstkey key1 key2 ...KeyN 通sinter, 同时把交集存到dstkey 对应的set集合中
sunion key1 key2... keyN 返回所给定key的并集
sunionstore dstkey key1 key2... keyN 通sunion, 同时把并集存到dstkey 对应的set集合中
sdiff key1 key2... keyN 返回所给定key的差集
sdiffstore dstkey key1 key2... keyN 通sdiff, 同时把差集存到dstkey 对应的set集合中
smembers key 返回key对应set的所有元素,结果是无序的

Sorted Set

有序集合,通过一个double类型的整数score进行排序。Sorted Set通过SkipList(跳跃表)和Hash Table组合完成。SkipList负责排序功能,而HashTable负责保存数据。

有13个命令

命令 描述
zadd key score member 添加元素member到集合,元素在集合中存在则更新对应score
zrem key member 删除指定元素,1表示成功,如果元素不存在返回0
zincrby key incr member 增加对应member的score值,并且重新排序,返回更新后的score值
zrank key member 返回指定元素在集合中的排名(下标),集合中元素按score从小到大排序
zrange key start end 从集合中指定区间的元素,返回结果按score顺序排序
zrecrange key start end 同上,返回结果按score逆序排序
zrangebyscore key min max 返回集合中score在给定区间的元素
zcount key min max 返回集合中score在给定区间的数量
zcard key 返回集合中元素个数
zscore key element 返回给定元素对应的score
zremrangebyrank key min max 删除集合中排名在给定区间的元素
zremrangebyscore key min max 删除集合中score在给定区间的元素

Hash

hash 特别适合用于存储对象。

有14个命令

命令 描述
HDEL key field1 [field2] 删除一个或多个哈希表字段
HEXISTS key field 查看哈希表 key 中,指定的字段是否存在。
HGET key field 获取存储在哈希表中指定字段的值。
HGETALL key 获取在哈希表中指定 key 的所有字段和值
HINCRBY key field increment 为哈希表 key 中的指定字段的整数值加上增量 increment 。
HINCRBYFLOAT key field increment 为哈希表 key 中的指定字段的浮点数值加上增量 increment 。
HKEYS key 获取所有哈希表中的字段
HLEN key 获取哈希表中字段的数量
[HMGET key field1 field2] 获取所有给定字段的值
[HMSET key field1 value1 field2 value2 ] 同时将多个 field-value (域-值)对设置到哈希表 key 中。
HSET key field value 将哈希表 key 中的字段 field 的值设为 value
HSETNX key field value 只有在字段 field 不存在时,设置哈希表字段的值。
HVALS key 获取哈希表中所有值。
[HSCAN key cursor MATCH pattern] [COUNT count] 迭代哈希表中的键值对。

排序命令详解

redis支持对List、Set、Sorted Set类型进行排序,sort命令完整格式如下:

SORT key[BY pattern][LIMIT start count][GET pattern][ASC | DESC][ALPHA][STORE dstKey]

  1. sort key 最简单,返回升序结果

  2. [ASC | DESC][ALPHA]

    1. 默认是升序。可以通过 DESC指定降序。
    2. 通过ALPHA指定是字典顺序。
  3. by pattern 按给定模式将元素内容组合成新key, 并按新key排序,返回结果。得看示例才能理解。

    127.0.0.1:6379> lpush mylist 2
    (integer) 1
    127.0.0.1:6379> lpush mylist 1
    (integer) 2
    127.0.0.1:6379> lpush mylist 3
    (integer) 3
    127.0.0.1:6379> set name1 102
    OK
    127.0.0.1:6379> set name2 103
    OK
    127.0.0.1:6379> set name3 101
    OK
    127.0.0.1:6379> sort mylist by name*
    1) "3"
    2) "1"
    3) "2"
    

    模式name*代表使用mylist集合中的元素的值填充"*", 按照name1、name2、name3这3个key对应的值排序,返回的是排序后mylist集合中的元素。

  4. limit start count 限制返回条数的

  5. store dstkey把结果存下来。

HyperLogLog(基数基数)

就是计算集合中不重复元素的个数。

下表列出了 redis HyperLogLog 的基本命令:

序号 命令及描述
1 [PFADD key element element …] 添加指定元素到 HyperLogLog 中。
2 [PFCOUNT key key …] 返回给定 HyperLogLog 的基数估算值。
3 [PFMERGE destkey sourcekey sourcekey …] 将多个 HyperLogLog 合并为一个 HyperLogLog

发布订阅

img

下表列出了 redis 发布订阅常用命令:

序号 命令及描述
1 [PSUBSCRIBE pattern pattern …] 订阅一个或多个符合给定模式的频道。
2 [PUBSUB subcommand argument [argument …]] 查看订阅与发布系统状态。
3 PUBLISH channel message 将信息发送到指定的频道。
4 [PUNSUBSCRIBE pattern [pattern …]] 退订所有给定模式的频道。
5 [SUBSCRIBE channel channel …] 订阅给定的一个或多个频道的信息。
6 [UNSUBSCRIBE channel [channel …]] 指退订给定的频道。

事务处理

Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证:

  • 批量操作在发送 EXEC 命令前被放入队列缓存。
  • 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
  • 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。

一个事务从开始到执行会经历以下三个阶段:

  • 开始事务。
  • 命令入队。
  • 执行事务。

单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。

事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。

Redis 事务命令

下表列出了 redis 事务的相关命令:

序号 命令及描述
1 DISCARD 取消事务,放弃执行事务块内的所有命令。
2 EXEC 执行所有事务块内的命令。
3 MULTI 标记一个事务块的开始。
4 UNWATCH 取消 WATCH 命令对所有 key 的监视。
5 [WATCH key key …] 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

redis脚本

下表列出了 redis 脚本常用命令:

序号 命令及描述
1 [EVAL script numkeys key key …] arg [arg …] 执行 Lua 脚本。
2 [EVALSHA sha1 numkeys key key …] arg [arg …] 执行 Lua 脚本。
3 [SCRIPT EXISTS script script …] 查看指定的脚本是否已经被保存在缓存当中。
4 SCRIPT FLUSH 从脚本缓存中移除所有脚本。
5 SCRIPT KILL 杀死当前正在运行的 Lua 脚本。
6 SCRIPT LOAD script 将脚本 script 添加到脚本缓存中,但并不立即执行这个脚本。

连接命令

下表列出了 redis 连接的基本命令:

序号 命令及描述
1 AUTH password 验证密码是否正确
2 ECHO message 打印字符串
3 PING 查看服务是否运行
4 QUIT 关闭当前连接
5 SELECT index 切换到指定的数据库

服务器命令

下表列出了 redis 服务器的相关命令:

序号 命令及描述
1 BGREWRITEAOF 异步执行一个 AOF(AppendOnly File) 文件重写操作
2 BGSAVE 在后台异步保存当前数据库的数据到磁盘
3 [CLIENT KILL ip:port] [ID client-id] 关闭客户端连接
4 CLIENT LIST 获取连接到服务器的客户端连接列表
5 CLIENT GETNAME 获取连接的名称
6 CLIENT PAUSE timeout 在指定时间内终止运行来自客户端的命令
7 CLIENT SETNAME connection-name 设置当前连接的名称
8 CLUSTER SLOTS 获取集群节点的映射数组
9 COMMAND 获取 Redis 命令详情数组
10 COMMAND COUNT 获取 Redis 命令总数
11 COMMAND GETKEYS 获取给定命令的所有键
12 TIME 返回当前服务器时间
13 [COMMAND INFO command-name command-name …] 获取指定 Redis 命令描述的数组
14 CONFIG GET parameter 获取指定配置参数的值
15 CONFIG REWRITE 对启动 Redis 服务器时所指定的 redis.conf 配置文件进行改写
16 CONFIG SET parameter value 修改 redis 配置参数,无需重启
17 CONFIG RESETSTAT 重置 INFO 命令中的某些统计数据
18 DBSIZE 返回当前数据库的 key 的数量
19 DEBUG OBJECT key 获取 key 的调试信息
20 DEBUG SEGFAULT 让 Redis 服务崩溃
21 FLUSHALL 删除所有数据库的所有key
22 FLUSHDB 删除当前数据库的所有key
23 [INFO section] 获取 Redis 服务器的各种信息和统计数值
24 LASTSAVE 返回最近一次 Redis 成功将数据保存到磁盘上的时间,以 UNIX 时间戳格式表示
25 MONITOR 实时打印出 Redis 服务器接收到的命令,调试用
26 ROLE 返回主从实例所属的角色
27 SAVE 同步保存数据到硬盘
28 [SHUTDOWN NOSAVE] [SAVE] 异步保存数据到硬盘,并关闭服务器
29 SLAVEOF host port 将当前服务器转变为指定服务器的从属服务器(slave server)
30 [SLOWLOG subcommand argument] 管理 redis 的慢日志
31 SYNC 用于复制功能(replication)的内部命令

GEO

Redis GEO 主要用于存储地理位置信息,并对存储的信息进行操作,该功能在 Redis 3.2 版本新增。

Redis GEO 操作方法有:

  • geoadd:添加地理位置的坐标。
  • geopos:获取地理位置的坐标。
  • geodist:计算两个位置之间的距离。
  • georadius:根据用户给定的经纬度坐标来获取指定范围内的地理位置集合。
  • georadiusbymember:根据储存在位置集合里面的某个地点获取指定范围内的地理位置集合。
  • geohash:返回一个或多个位置对象的 geohash 值。

stream

Redis Stream 是 Redis 5.0 版本新增加的数据结构。

Redis Stream 主要用于消息队列(MQ,Message Queue),Redis 本身是有一个 Redis 发布订阅 (pub/sub) 来实现消息队列的功能,但它有个缺点就是消息无法持久化,如果出现网络断开、Redis 宕机等,消息就会被丢弃。

简单来说发布订阅 (pub/sub) 可以分发消息,但无法记录历史消息。

而 Redis Stream 提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失。

Redis Stream 的结构如下所示,它有一个消息链表,将所有加入的消息都串起来,每个消息都有一个唯一的 ID 和对应的内容:

img

上图解析:

  • Consumer Group :消费组,使用 XGROUP CREATE 命令创建,一个消费组有多个消费者(Consumer)。
  • last_delivered_id :游标,每个消费组会有个游标 last_delivered_id,任意一个消费者读取了消息都会使游标 last_delivered_id 往前移动。
  • pending_ids :消费者(Consumer)的状态变量,作用是维护消费者的未确认的 id。 pending_ids 记录了当前已经被客户端读取的消息,但是还没有 ack (Acknowledge character:确认字符)。

消息队列相关命令:

  • XADD - 添加消息到末尾
  • XTRIM - 对流进行修剪,限制长度
  • XDEL - 删除消息
  • XLEN - 获取流包含的元素数量,即消息长度
  • XRANGE - 获取消息列表,会自动过滤已经删除的消息
  • XREVRANGE - 反向获取消息列表,ID 从大到小
  • XREAD - 以阻塞或非阻塞方式获取消息列表

消费者组相关命令:

  • XGROUP CREATE - 创建消费者组
  • XREADGROUP GROUP - 读取消费者组中的消息
  • XACK - 将消息标记为"已处理"
  • XGROUP SETID - 为消费者组设置新的最后递送消息ID
  • XGROUP DELCONSUMER - 删除消费者
  • XGROUP DESTROY - 删除消费者组
  • XPENDING - 显示待处理消息的相关信息
  • XCLAIM - 转移消息的归属权
  • XINFO - 查看流和消费者组的相关信息;
  • XINFO GROUPS - 打印消费者组的信息;
  • XINFO STREAM - 打印流信息

高级教程

备份与恢复

备份

Save 命令会把在redis安装目录创建dump.rdb文件, 在前台运行。

bgsave是在后台运行。

CONFIG GET dir查看备份目录。

恢复

dump.rdb文件复制到安装目录,然后启动服务即可。

安全

config get requirepass 查看密码配置。。默认无需密码。

设置密码
config set requirepass "youpass"

设置完密码。客户端需要先Auth youpass认证通过才可以调用其他命令。

性能测试

redis 性能测试工具可选参数如下所示:

序号	选项	描述	默认值
1	-h	指定服务器主机名	127.0.0.1
2	-p	指定服务器端口	6379
3	-s	指定服务器 socket	
4	-c	指定并发连接数	50
5	-n	指定请求数	10000
6	-d	以字节的形式指定 SET/GET 值的数据大小	2
7	-k	1=keep alive 0=reconnect	1
8	-r	SET/GET/INCR 使用随机 key, SADD 使用随机值	
9	-P	通过管道传输 <numreq> 请求	1
10	-q	强制退出 redis。仅显示 query/sec 值	
11	--csv	以 CSV 格式输出	
12	-l	生成循环,永久执行测试	
13	-t	仅运行以逗号分隔的测试命令列表。	
14	-I	Idle 模式。仅打开 N 个 idle 连接并等待。	

Redis 客户端连接

Redis 通过监听一个 TCP 端口或者 Unix socket 的方式来接收来自客户端的连接,当一个连接建立后,Redis 内部会进行以下一些操作:

  • 首先,客户端 socket 会被设置为非阻塞模式,因为 Redis 在网络事件处理上采用的是非阻塞多路复用模型。
  • 然后为这个 socket 设置 TCP_NODELAY 属性,禁用 Nagle 算法
  • 然后创建一个可读的文件事件用于监听这个客户端 socket 的数据发送

最大连接数

在 Redis2.4 中,最大连接数是被直接硬编码在代码里面的,而在2.6版本中这个值变成可配置的。

maxclients 的默认值是 10000,你也可以在 redis.conf 中对这个值进行修改。

config get maxclients

1) "maxclients"
2) "10000"

客户端命令

S.N. 命令 描述
1 CLIENT LIST 返回连接到 redis 服务的客户端列表
2 CLIENT SETNAME 设置当前连接的名称
3 CLIENT GETNAME 获取通过 CLIENT SETNAME 命令设置的服务名称
4 CLIENT PAUSE 挂起客户端连接,指定挂起的时间以毫秒计
5 CLIENT KILL

Redis 管道技术

Redis是一种基于客户端-服务端模型以及请求/响应协议的TCP服务。这意味着通常情况下一个请求会遵循以下步骤:

  • 客户端向服务端发送一个查询请求,并监听Socket返回,通常是以阻塞模式,等待服务端响应。
  • 服务端处理命令,并将结果返回给客户端。

Redis 管道技术

Redis 管道技术可以在服务端未响应时,客户端可以继续向服务端发送请求,并最终一次性读取所有服务端的响应。

** 实例**

查看 redis 管道,只需要启动 redis 实例并输入以下命令:

$(echo -en "PING\r\n SET runoobkey redis\r\nGET runoobkey\r\nINCR visitor\r\nINCR visitor\r\nINCR visitor\r\n"; sleep 10) | nc localhost 6379

+PONG
+OK
redis
:1
:2
:3

以上实例中我们通过使用 PING 命令查看redis服务是否可用, 之后我们设置了 runoobkey 的值为 redis,然后我们获取 runoobkey 的值并使得 visitor 自增 3 次。

在返回的结果中我们可以看到这些命令一次性向 redis 服务提交,并最终一次性读取所有服务端的响应

Redis 分区

分区是分割数据到多个Redis实例的处理过程,因此每个实例只保存key的一个子集。

分区的优势

  1. 通过利用多台计算机内存的和值,允许我们构造更大的数据库。
  2. 通过多核和多台计算机,允许我们扩展计算能力;通过多台计算机和网络适配器,允许我们扩展网络带宽。

分区的不足

  1. redis的一些特性在分区方面表现的不是很好:涉及多个key的操作通常是不被支持的。举例来说,当两个set映射到不同的redis实例上时,你就不能对这两个set执行交集操作。
  2. 涉及多个key的redis事务不能使用。
  3. 当使用分区时,数据处理较为复杂,比如你需要处理多个rdb/aof文件,并且从多个实例和主机备份持久化文件。
  4. 增加或删除容量也比较复杂。redis集群大多数支持在运行时增加、删除节点的透明数据平衡的能力,但是类似于客户端分区、代理等其他系统则不支持这项特性。然而,一种叫做presharding的技术对此是有帮助的。

分区类型
Redis 有两种类型分区。

  1. 范围分区
    最简单的分区方式是按范围分区,就是映射一定范围的对象到特定的Redis实例。

比如,ID从0到10000的用户会保存到实例R0,ID从10001到 20000的用户会保存到R1,以此类推。

这种方式是可行的,并且在实际中使用,不足就是要有一个区间范围到实例的映射表。这个表要被管理,同时还需要各 种对象的映射表,通常对Redis来说并非是好的方法。

  1. 哈希分区
    另外一种分区方法是hash分区。这对任何key都适用,也无需是object_name:这种形式,像下面描述的一样简单:

用一个hash函数将key转换为一个数字,比如使用crc32 hash函数。对key foobar执行crc32(foobar)会输出类似93024922的整数。
对这个整数取模,将其转化为0-3之间的数字,就可以将这个整数映射到4个Redis实例中的一个了。93024922 % 4 = 2,就是说key foobar应该被存到R2实例中。注意:取模操作是取除的余数,通常在多种编程语言中用%操作符实现。

持久化

2种持久化方式:闪存快照(Snapshotting)和日志追加(Append only file)。

2种方式都有丢数据的风险,aof风险低一些,但是可能会导致备份文件不断膨胀。

解决方案是调用bgrewriteaof命令,用快照的方式替换aof文件。

闪存快照

闪存快照是将内存中的数据以快照方式写入二进制文件中,默认文件名为dump.rdb。

自动快照

save <seconds> <changes>配置指定,过了seconds或者数据更改changes次进行一次内存快照操作。

可以配置多个。

主动快照

save or bgsave,一般都是调用bgsave后台保存。

日志追加

日志追加(aof)方式是把增加、修改数据的命令通过write函数追加到文件尾部(默认是appendonly.aof)。redis重启时读取appendonly.aof 文件中的所有命令并且执行,从而把数据写入内存中。

配置

appendonly yes # 启动日志追加持久化方式
#appendfsync always #每次收到增加或者修改命令就立刻强制写入磁盘
appendfsync everysec #每秒强制写入磁盘一次
#appendfsync no #是否写入磁盘完全依赖操作系统

扩展库phpredis安装和使用

略。

使用参考phpredis

应用

list可以做队列

可以先入先出, 当异步队列用。也可以当栈用。

可以做关注列表什么的。

如果是后台需要一直轮询消费消息的,可以用blpopbrpop, 在没消息时自动休眠,有消息时自动唤醒。降低cpu消耗。(但是空闲久了,服务端会主动kill客户端连接,所以需要捕获异常然后重新连接。)

set去重,做投票

投票。 滤重挺合适。

sorted set 可以做优先级队列

可以做优先级队列,也可以做延迟队列。这里有个注意的。

多线程时怎么避免同时消费。方法时利用zrem的原子操作,如果成功,说明删除成功,可以处理消息。

如果删除失败,说明消息被别的线程处理了。

string incr key原子自增可以做分布式自增id。

有限制。最大值和最小值是unsigned long的最大和最小值。0~264, 感觉够用了。

hash 存对象

string可以把对象序列化后存下来。

hash可以把对象,按字段存下来,方便只读取某个/某几个值,网络传输低些,同时存储会更高。

分布式锁

利用setnx做分布式锁。

setnx: string的操作。给key设置一个值。如果key已经存在就失败。

单机锁是 锁定某个资源,锁住了我就操作,然后释放锁。

setnx的操作流程是:给key设置值(lock),设置成功了,表示我锁定了资源,然后干事。干完事,删除key。(unlock)

考虑到执行流程可能会异常中断,需要加些其他机制。最后的用法示例是:

set lock:codehole true ex 5 nx #锁定资源,并设定5秒的过期时间。这样即使任务异常导致后面的del没执行,也会正常释放资源
.....your task #这里有个注意的,任务不能太长,得低于超时时间,否则超时释放锁了,就不是独占资源了。
del lock:codehole # 释放资源

位图

适合做布隆过滤器 实现可以参考go-zero

参考

redis教程

redis or memcache

PHP 核心技术与最佳实践-第10章 Redis使用与实战

本文链接:http://blog.go2live.cn/post/redis.html

-- EOF --