redis 入门学习笔记

redis 是什么?

  • redis 是 "Remote Dictionary Server" 的缩写,它以字典的结构存储数据
  • redis 的全部数据都存储在内存中,在性能上相对其它硬盘存储的数据库有很大的优点
  • redis 能够对内存中的数据进行持久化
  • redis 支持主从复制功能,实现高可用
  • redis 键值支持的数据类型有:字符串类型、散列类型、列表类型、集合类型、有序集合类型
  • redis 的主要用于实现缓存、队列、消息订阅等功能
  • redis 提供了以下一些可执行程序:
redis-server:redis 服务端,用于启动 redis 服务
redis-cli:redis 命令行客户端,能够直接链接到 redis 服务,提供了丰富的键值操做的命令
redis-benchmark: redis 提供的性能测试工具
redis-check-aof:aof 文件修复工具
redis-check-dump:adb 文件检查工具
redis-sentinel:哨兵服务器,能够启动哨兵用于监控 redis 服务的运行状况
复制代码
  • 一个 redis 能够配置多个数据库:
redis 默认支持 16 个数据库,能够经过启动参数 databases 来修改该值
数据库编号从 0 开始,不支持自定义名称
在客户端能够经过 select 来随时切换数据库
数据库之间的数据不是彻底隔离的,咱们能够经过 flushAll 命令清空一个实例下全部数据库的数据
这些数据库更像一个命名空间,不适合存放不一样应用下的数据
复制代码

redis-cli 中经常使用的命令

  • 字符串类型

字符串类型的键容许存放的最大数据类型为 512 M,经常使用命令以下:php

SET key value                    # 设置键值
GET key                          # 获取键值
INCR numKey                      # 让键值递增,返回递增后的数值,键值非数字会报错,不存在时默认为 0
INCRBY numKey num                # 和 INCR 相似,支持每次动态加指定数值的数据
DECR numKey                      # 自减
DECRBY numKey num                # 减小指定数值
INCRBYFLOAT numKey num           # 增长指定的浮点数值
APPEND key value                 # 向尾部追加值,返回追加后的字符长度
STRLEN key                       # 返回键值的字符串长度
MSET/MGET                        # 和 GET/SET 相似,批量设置和获取
GETBIT key offset                # 获取一个字符串指定位置的二进制值
SETBIT key offset value          # 设置指定位置的二进制的值
BITCOUNT key                     # 统计键值对应的二进制位数
BITOP operation destkey key1...  # 对多个键 key1,key2... 对应的值进行位运算,并存储在 destkey 键对应的值中
复制代码
  • 散列类型

散列类型的键值是也是一种字典类型,存储了字段和字段值的映射关系,字段值只支持字符串,散列类型适合存储对象,能够每次获取或者更新某个属性的值,减小解析整个对象的时间,经常使用命令以下:mysql

HSET key field value             # 设置散列类型 key 对应的对象的某个属性
HGET key field                   # 获取散列类型 key 对应的对象的某个属性
HMSET key field value ...        # 批量设置散列类型 key 对应的多个属性的值
HMGET key field ...              # 批量获取散列类型 key 对应的多个属性的值
HGETALL key                      # 获取散列类型中某个 key 对应的全部属性及值,也就是整个对象
HEXISTS key field                # 判断散列类型中某个字段是否存在
HSETNX key field value           # 判断散列类型中某个字段是否存在,不存在则赋值
HDEL key field ...               # 删除散列类型中对象里的一个或者多个字段
HKEYS key                        # 获取散列类型中对象里的全部字段属性名
HVALS key                        # 获取散列类型中对象里的全部字段属性对应的值
HLEN                             # 获取散列类型中对象里的字段数量
复制代码
  • 列表类型

列表类型能够存储一个有序的字符串列表,经常使用的操做是向列表两头添加元素或者列表某个片断,列表类型使用双向链表实现,访问首尾元素的速度很是快,经常使用命令以下:redis

LPUSH key value1 value2...              # 向列表左边增长多个元素
RPUSH key value1 value2...              # 向列表右边增长多个元素
LPOP key                                # 从列表左边弹出一个元素
RPOP key                                # 从列表右边弹出一个元素
BRPOP key                               # 与 RPOP 相似,只是若是列表中没有元素时会一直等待直到新元素加入,能够接受多个 key 值,优先使用第一个 key
BLPOP key...                            # 与 BRPOP 相似
LLEN key                                # 获取列表中元素个数,时间复杂度为O(1)
LRANGE key start stop                   # 获取列表中从 start 到 stop 之间的元素,从 0 开始索引
LREM key count value                    # 删除列表中前 count 个值为 value 的元素,count>0 从左边删除,count<0 从右边删除,count=0 所有删除
LINDEX key index                        # 获取列表中指定索引的元素
LSET key index value                    # 设置列表中指定索引的元素
LTRIM key start end                     # 删除列表中指定范围之外的全部元素
LINSERT key BEFORE/AFTER pivot value    # 从列表中查找值等于 pivot 的第一个元素,而后在其前面或者后面插入 value 元素
RPOPLPUSH source destination            # 从 source 列表右边弹出一个元素,插入到 destination 列表左边
复制代码
  • 集合类型

集合类型的元素是无序的、惟一的,经常使用的操做是向集合中加入某个元素或者删除某个元素、判断某个元素是否存在,大部分操做的时间复杂度基本都为 O(1),经常使用命令以下:算法

SADD key value1 value2...           # 向集合中加入多个元素
SREM key value1 value2...           # 从集合中删除多个元素
SMEMBERS key                        # 获取集合中的全部元素
SISMEMBER key value                 # 判断元素是否存在集合中
SDIFF key1 key2...                  # 对多个集合求差集运算
SDIFFSTORE destination key1 key2... # 对多个集合求差集运算,并将结果存储在 destination 集合中
SINTER key1 key2...                 # 对多个集合求交集运算
SINTERSTORE destination key1 key2...# 对多个集合交差集运算,并将结果存储在 destination 集合中
SUNION key1 key2...                 # 对多个集合求并集运算
SUNIONSTORE destination key1 key2...# 对多个集合并差集运算,并将结果存储在 destination 集合中
SCARD key                           # 获取集合中的元素个数
SRANDMEMBER key count               # 随机从集合中获取 count 个不相同的元素
SPOP key                            # 随机从集合中弹出一个元素
复制代码
  • 有序集合类型

有序集合类型使用散列表和跳跃表实现的,比列表类型更消耗内存,有序集合经过给每一个元素存放一个 score 进行排序,对于须要排序分页的场景很是适用,经常使用命令以下:sql

ZADD key score member ...        # 向有序集合中添加元素,若是存在则更新元素对应的 score
ZSCORE key member                # 获取有序集合中某个元素的分数
ZRANGE key start stop            # 获取有序集合中排名在某个范围的元素,结果集从小到大排序
ZREVRANGE key start stop         # 获取有序集合中排名在某个范围的元素,结果集从大到小排序
 # 获取有序集合中分数在某个范围的元素,WITHSCORES 表示是否把分数返回,LIMIT 表示是否须要分页
# 默认状况下是包含最大值和最小值,若是想不包好最大值最小值,能够加个左括号:ZRANGEBYSCORE hello 3 (5
# -inf 和 +inf 表示无穷小和无穷大
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count] 
 # ZREVRANGEBYSCORE 和 ZRANGEBYSCORE 类似,只是从大到小排序
ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count] 

ZINCBY key increment member      # 增长有序集合中某个元素的分数
ZCARD key                        # 获取有序集合中元素的数量
ZCOUNT key min max               # 指定分数范围内元素的个数
ZREM key member...               # 删除有序集合中一个或者多个元素
ZREMRANGEBYRANK key start stop   # 删除有序集合中某个排名范围的元素
ZREMRANGEBYSCORE key min max     # 删除有序集合中某个score范围的元素
ZRANK key member                 # 获取某个元素的排名
 # 计算有序集合的交集,能够经过 AGGREGATE 指定聚合类型,默认是求和,最终将key1,key2 集合中的元素经过不一样的聚合方式放入 destinationKey 集合中
ZINTERSTORE destinationKey numkeys key1 key2...  [AGGREGATE SUM | MIN | MAX]
复制代码
  • 通用的命令
CONFIG set loglevel warning      # 动态修改 redis 的部分配置
CONFIG get loglevel              # 获取 redis 的部分配置
SELECT 1                         # 更改数据库编号,默认从 0 开始
KEYS pattern                     # 获取知足 glob 风格的全部键值,当键值较多时会影响性能,生产不建议这样作
EXISTS key                       # 判断某个键值是否存在,存在返回 1, 不然返回 0
DEL key1 key2                    # 能够删除一个或者多个键,返回删除的个数
KEYS "user*" | xargs | del       # 实现通配符匹配删除多个键值
TYPE key                         # 获取键值的数据类型,string | hash | list | set | zset(有序集合)
复制代码

redis 中事务

  • redis 中事务是一组命令的集合
  • 事务以 MULTI 命令开始,以 EXEC 命令结束
  • 事务的原理是先将属于一个事务的全部命令暂时存起来,等到 EXEC 命令再以此执行
  • redis 的事务没有提供关系型数据库事务的回滚功能
  • redis 中的事务的执行结果是一块儿返回的,所以没法将前一个命令的结果做为下一个命令的参数
  • WATCH 命令用于监控一个或者多个键,一旦其中一个键被修改,以后的事务就不会执行,监控一直持续到 EXEC 命令
  • WATCH 命令主要用于防止竞态条件,保证一个事物执行前某些键值不被修改
> MULTI
> SADD "user:1" 2
> SADD "user:2" 1
> EXEC
复制代码

redis 中的过时时间

  • EXPIRE key seconds 用于设置键的过时时间,单位为秒
  • PEXPIRE key milliSeconds 单位为毫秒
  • TTL key 用于获取键的过时时间,返回 -1 表示过时时间为永久,-2 表示键值不存在
  • PTTL key 获取过时时间,单位为毫秒
  • PERSIST key 用于清空过时时间,设为永久
  • SET 命令一样会清空过时时间

排序

  • SORT 命令能够对列表类型,集合类型和有序集合类型键进行排序
  • 利用排序能够完成与关系型数据库中链接查询相相似的任务
  • SORT 命令默认是对键值为数字的序列进行排序,非数字的排序会报错
  • ALPHA 参数,能够按照字典顺序排序字符串类型的键值
  • DESC 参数,实现元素从大到小排序
  • LIMIT offset count 参数,实现排序分页
  • “BY 参考值” 参数,参考值能够是字符串类型的键,也能够是散列类型的某个键对应的字段
# 经过 BY 咱们能够实现使用其余参考键值进行排序
# 使用列表中的每一个元素替换参考值中的第一个 *,并获取对应的散列类型的 time 字段进行排序
SORT tag:ruby:posts BY post:*-> time DESC  
复制代码
  • GET 参数,经过给 SORT 命令加 GET 参数,返回再也不是元素自身的值,而是 GET 参数中指定的键值
# 经过 post:* 中 time 字段进行排序,并返回 post:* 中的 title 字段,同时返回原始列表中的信息(#)
# 同一个 SORT 命令能够返回使用多个 GET 参数
SORT tag:ruby:posts BY post:*-> time DESC GET post:*->title GET #
复制代码
  • STORE 参数,排序后的结果不直接返回排序结果,存储在对应的键中(列表类型)
  • 使用 SORT 命令,关于性能方面注意的几点:
- 尽可能减小排序键中元素的个数
- 使用 LIMIT 参数获取必要的数据
- 若是排序结果较大,使用 STORE 参数进行缓存,以避免屡次排序
复制代码

redis 中的消息通知

  • 使用列表类型实现任务队列(LPUSH/RPOP/BRPOP)
  • 使用 BLPOP/BRPOP 实现优先级队列
  • 实现发布订阅机制(PUBLISH/SUBSCRIBE/UNSUBSCRIBE/PSUBSCRIBE/PUNSUBSCIBE)

redis 中编码存储优化

redis 对不一样的数据类型都提供了多种编码方式,以节省空间和加快查询效率,经过命令 OBJECT ENCODING key 命令能够查看某个键值对应的编码方式shell

如下是每种数据类型可能才用的内部编码方式:数据库

数据类型 内部编码方式 OBJECT ENCODING 命令结果
字符串类型 REDIS_ENCODING_RAW "raw"
REDIS_ENCODING_INT "int"
REDIS_ENCODING_EMBSTR "embstr"
散列类型 REDIS_ENCODING_HT(散列表) "hashtable"
REDIS_ENCODING_ZIPLIST(紧凑顺序表) "ziplist"
列表类型 REDIS_ENCODING_LINKEDLIST(双向链表) "linkedlist"
REDIS_ENCODING_ZIPLIST "hashtable"
集合类型 REDIS_ENCODING_HT "hashtable"
REDIS_ENCODING_INTSET "intset"
有序集合类型 REDIS_ENCODING_ZIPLIST "ziplist"
REDIS_ENCODING_SKIPLIST(跳跃表) “skiplist”
  • 每种类型的内部编码方式通常至少有两种以上
  • 当元素较少时,redis 通常会采用一种更为紧凑但性能较差的编码方式
  • redis 启动后会预先创建一个 0 到 9999 这些数字的共享对象,所以若是要设置的键值在这些数字范围内时,redis 就直接引用他们不须要再创建对象
  • 当字符串的键值内容不超过 39 字节时,redis 采用 REDIS_ENCODING_EMBSTR 编码方式
  • 当散列类型键的字段个数少于 hash-max-ziplist-entries 参数值且每一个字段名和字段值的长度都小于 hash-max-ziplist-value 参数值时,采用 REDIS_ENCODING_ZIPLIST 编码方式,不然使用 REDIS_ENCODING_HT 编码
  • 当列表类型键的元素个数少于 list-max-ziplist-entries 参数值且每一个元素的长度都小于 list-max-ziplist-value 参数值时,采用 REDIS_ENCODING_ZIPLIST 编码方式,不然使用 REDIS_ENCODING_LINKEDLIST 编码
  • 当集合类型中的全部元素为整数且元素的个数小于配置 set-max-insert-entries 时,采用 REDIS_ENCODING_INTSET 编码方式,不然采用 REDIS_ENCODING_HT 编码方式
  • 一样有序集合类型能够经过参数 zset-max-ziplist-value 和 zset-max-ziplist-entries 来控制使用 REDIS_ENCODING_ZIPLIST 编码方式仍是 REDIS_ENCODING_SKIPLIST 编码方式

redis 与 Lua 脚本

  • 在 Lua 脚本中能够经过 redis.call('get', 'foo') 的方式调用 redis 命令
  • redis.pcall 和 redis.call 相似,不一样之处是执行失败时记录失败消息并继续执行
  • 在 redis 中使用 Lua 脚本时禁止使用全局变量和文件系统调用相关函数,为了保持状态安全一致性
  • 经过 eval 命令可让开发者像调用其它 redis 命令同样调用 Lua 脚本
# 第一个参数是要执行的脚本,第二个参数表示后面传入 key 的数量,后面是 key 和 arg 传入的参数,能够在脚本里直接使用
eval 脚本内容  key参数数量  [key...] [arg...]
复制代码
  • evalsha 命令
- 和 eval 同样是执行 Lua 脚本,只不过每次执行时是将脚本的摘要传递给 redis 服务端
- redis 服务端会检查缓存是否存在该摘要的脚本并执行,不存在则抛出异常
- 由于 eval 命令每次都会将脚本发到远端,带宽消耗大,因此通常 evalsha 命令执行失败时再使用 eval 命令并设置缓存
复制代码
  • SCRIPT lOAD:将脚本的 SHA1 摘要加入到脚本缓存中
  • SCRIPT EXSITS: 判断某个脚本的 SHA1 摘要是否被缓存
  • SCRIPT FLUSH:清除 SHA1 脚本本地缓存
  • SCRIPT KILL: 中止脚本的执行
  • 使用脚本开发的优势:
- 减小网络开销
- 原子操做
- 代码的复用
复制代码

持久化

redis 提供两种持久化的方式,一种是 RDB 方式,一种是 AOF 方式:缓存

  • RDB 的方式是定时将内存中的数据存储到磁盘,如下几种状况会进行数据快照:
- 配置指定规则自动同步,好比 save 300 10, 表示每 300 内至少有 10 条数据被修改则进行快照
- 用户执行 SAVE 或者 BGSAVE 命令,SAVE 命令同步执行会阻塞其它客户端的请求,BGSAVE 异步同步数据
- 执行 FLUSHALL 命令
- 主从复制时
复制代码
  • AOF 的方式是每次将更新数据的命令记录到磁盘
- 经过参数 appendonly 开启 AOF 数据备份
- 经过参数 appendfsync 设置磁盘缓存刷新机制
- 由于每条更新数据的命令都会被记录到磁盘,因此磁盘数据会愈来愈大,所以 redis 提供了重写 AOF 的功能
- 经过 auto-aof-rewrite-percentage 参数和 auto-aof-rewrite-min-size 参数能够设置自动重写 AOF 文件策略
复制代码

主从复制

  • 经过在启动 redis 服务端时加入 slaveof 参数设置为其它服务器的从数据库
  • 默认状况下,从数据库是只读的
  • 经过 info replication 命令查看 redis 的主从状态
  • 能够经过参数 slave-read-only 参数设置为可写,可是不建议这样设置会致使数据错乱
  • 一个主数据库能够关联多个从数据库
  • 经过 SLAVEOF NO ONE 命令使当前从数据库中止接收其它数据库的同步并转换为主数据库
  • redis 采用乐观复制策略,主数据库在执行完客户端请求后当即返回给客户端,而不回等待同步到从数据库才返回
  • 乐观复制策略保证了主数据库性能不受影响,可是会使主从数据库有必定时间的数据不一致的窗口
  • 为了尽可能保证主从数据的一致性,redis 提供了两个参数来限制主数据库的可写状态:
- min-slaves-to-write 3:表示只有当 3 个或者 3 个以上的从数据库链接到主数据库时,主数据库才是可写的 
- min-slaves-max-lag 10:表示容许从数据库最长失去链接的时间(秒),超过该时间,主数据库变为只读。
复制代码
  • 从数据库能够做为另一台数据库的主数据库
  • 当主数据库发生故障时,必定不要当即重启,重启后由于主数据库没有开启持久化,因此数据库中的数据会被清空,然而主从数据又保持的联系,导致从数据库中的数据也被清空,使从数据库的持久化失去意义。这种状况下建议先使用 SLAVE NO ONE 使从数据库变为主数据库再重启主数据库
  • 在从数据库与主数据库从新创建链接时,既能够选择全量同步数据,也能够选择增量复制同步数据

哨兵

Redis 2.8 之后提供了哨兵工具来实现自动化监控和故障恢复功能:安全

  • 哨兵系统用户监控系统运行,当主数据库出现故障时自动将从数据库升级转换为主数据库
  • 一个主从的 redis 系统能够部署多个哨兵来进行监控,避免哨兵系统的单点问题
  • 一个哨兵实例也能够监控多个主从 redis 系统
  • 配置哨兵系统时只须要配置主数据库的信息,哨兵系统会自动经过 info replication 命令发现其从数据库的信息
  • 哨兵相关参数:
- slvae-priority:从数据库的优先级设置,当主数据库挂掉后,选择优先级最高的从数据库升级为主数据库
- down-after-milliseconds: 指定时间后,若是 ping 的数据库节点仍然未回复,则认为该数据库实例主观下线
- quorum:多多个哨兵系统都认为某个数据库节点主观下线且超过 quorum 个数,则认为该数据库实例客观下线
复制代码
  • 认为客观下线的前提下,须要保证只有一个哨兵节点来执行故障恢复操做,选举哨兵头领的过程使用 Raft 算法。
  • 哨兵部署建议:
- 为每一个节点部署一个哨兵,避免单点问题
- quorum 的值至少设置为 N/2 + 1, 保证大部分哨兵节点赞成后才进行故障恢复
复制代码

管理工具

  • 记录耗时命令日志
- 和 mysql 同样, redis 也能够记录慢查询日志
- 经过 slowlog-log-slower-than 参数设置多长时间的执行时间会被记录到耗时日志里
- 经过参数 slowlog-max-len 来限制耗时日志记录的条数
- SLOWLOG GET 命令能够获取当前的耗时命令日志
复制代码
  • 命令监控:MONITOR 命令能够监控到全部 REDIS 执行的命令,对系统性能影响比较大
  • phpRedisAdmin 工具,支持以树形结构查看键列表,编辑键值,查看数据库信息和键信息等功能,是 PHP 开发的。
  • Rdbtools 工具,是 Python 工具开发的一个 Redis 快照文件解析器,根据快照文件导出的 JSON 数据,分析 Redis 每一个键的占用空间等
  • Redis 命令属性,每一个命令都有不一样的属性,一个命令同时能够拥有多个属性:
- REDIS_CMD_WRITE:拥有该属性的命令会修改数据库的数据
- REDIS_CMD_DENYOOM:拥有该属性的命令可能会增长 Redis 占用的存储空间
- REDIS_CMD_NOSCRIPT:拥有该属性的命令没法再 Redis 脚本中被执行
- REDIS_CMD_RANDOM:一个脚本执行了拥有了 REDIS_CMD_RANDOM 属性的命令后,就不能执行拥有 REDIS_CMD_WRITE 的命令了
- REDIS_CMD_SORT_FOR_SCRIPT:拥有该属性的命令会产生随机结果,在脚本中调用这些命令时 Redis 会对结果结果进行排序
- REDIS_CMD_LOADING:Redis 会在启动时执行拥有该属性的命令
复制代码

redis 主要配置参数

  • databases:设置 redis 支持的数据库的个数
  • hash-max-ziplist-entries: 散列类型使用 REDIS_ENCODING_ZIPLIST 编码方式时对应的字段个数临界值
  • hash-max-ziplist-value: 散列类型使用 REDIS_ENCODING_ZIPLIST 编码方式时对应的字段名和字段值的长度临界值
  • list-max-ziplist-entries: 列表类型使用 REDIS_ENCODING_ZIPLIST 编码方式时对应的元素个数临界值
  • list-max-ziplist-value: 列表类型使用 REDIS_ENCODING_ZIPLIST 编码方式时对应的元素的长度临界值
  • set-max-ziplist-entries: 散列类型使用 REDIS_ENCODING_INTSET 编码方式时对应的元素个数的临界值
  • zset-max-ziplist-value:有序集合使用编码方式的元素长度临界值
  • zset-max-ziplist-entries:有序集合使用编码方式的元素个数临界值
  • maxmemory: 限制最大可用内存大小(单位为字节)
  • maxmemory-policy 设置在超出最大内存限制时,删除键值的处理方法:
- volatile-lru: 使用 LRU 算法删除一个设置了过时时间的键
- allkeys-lru: 使用 LRU 算法删除一个键
- volatile-random:随机删除一个设置了过时时间的键
- allkeys-random:随机删除一个键
- volatile-ttl:删除过时时间最近的一个键
- noeviction:不删除键值,插入数据时返回错误
复制代码
  • appendonly:等于 = true 开启 AOF 备份模式
  • auto-aof-rewrite-percentage: 当目前 AOF 文件的大小超过上一次重写时 AOF 文件大小的多少比例时进行再次重写
  • auto-aof-rewrite-min-size: 设置最小的 AOF 重写文件大小
  • appendfsync:设置 AOF 缓存刷新机制
everysec: 默认策略,每秒执行一次刷新
always:每次执行写操做都会刷新磁盘缓存
no:不主动刷新磁盘缓存,交个操做系统,即每 30 秒一次
复制代码
  • slaveof:redis-server 启动参数,将当前 redis 实例设置为另一台 redis 实例的备份实例,作主从同步
  • slave-read-only:设置从数据库的读写状态
  • requirepass:给 redis 服务器设置一个密码
相关文章
相关标签/搜索