Redis基础

為{幸葍}努か 提交于 2019-12-22 10:52:35

1 概要

1.1 简介

Redis 是使用ANSI C语言编写、支持网络、基于内存、可持久化的日志型、Key-Value数据库。

  • 安装在磁盘
  • 数据存储在内存

1.2 特性

  • 速度快
  • 键值对格式存储
  • 功能丰富
  • 简单稳定
  • 持久化
  • 主从复制
  • 高可用分布式转移
  • 客户端语言多

1.3 应用场景

  • 缓存数据库
  • 排行耪
  • 计数器
  • 社交网络
  • 消息队列

1.4 启动、配置

1.5 全局指令

指令 说明 备注
keys * 查看所有键
dbsize 键总数 如果存在大量键,线上禁止使用
exists key 检查键是否存在
del key 删除键
expire key seconds 设置键过期
ttl key 查看过期时间
type key 查看键数据类型 不存在返回none

1.6 数据库管理

  • select 0 选择数据库 默认有16个数据库
  • flushdb 只删除当前db
  • flushall 删除所有db

2 5种数据结构

key value 指令
String name set name zhangch
Hash user:1 hmset user:1 name zhangch age 18
List testKey1 lpush testKey1 a b c d
Set testKey2 zadd testKey2 a b c
ZSet testKey3 zadd testKey3 2 a 4 b 5 c

2.1 字符串String类型

字符串类型,实际上可以是json,xml,数字,二进制(图片,音频,视频),大小限制512M
命令:
set key valueset name zhangch

  • ex 设置过期时间 秒
  • px 设置过期时间 毫秒
  • nx 仅当key不存在时设置 Not eXist
  • xx 仅当key存在时设置
    批量设置 mset k1 v1 k2 v2 mset name zhangch age 26 sex male
    批量获取同理 mget k1 k2 k3 mget name age sex

计数

  • incr key 整数自增1,非整数报错,无key0自增到1
  • decr key 同上,减法
  • incrby key num 加给定的值
  • decrby key num 同上
  • incrbyfloat key num 加给定的值,用于浮点数

追加
append key value 追加
strlen key 获取长度
getrange str beginIndex endIndex 截取字符串长度 从0开始,包含尾

2.2 哈希Hash类型

1.命令
有用户表如下:

使用String类型来存储,使用如下命令。

哈希类型的数据结构维护了一个String类型的field-value的映射表,适合存储对象。

  • hset key filed value 设值,成功返回1,失败返回0
  • hget key filed 取值,返回value
  • hdel key 删值,返回成功的个数
  • hdel key field... 删值,返回成功的个数
  • hlen key 返回映射个数
  • hmset key f1 v1 f2 v2 批量设值
  • hmget key f1 f2 批量取值
  • hexists key field 判断field是否存在
  • hkeys key 获取所有field
  • hvalues key 获取所有value
  • hgetall key 获取所有field-value
  • hincrby key field num 增加
  • hincrbyfloat key field num 增加浮点数

2.内部编码
ziplist<压缩列表>和hashtable<哈希表>
redis初始创建hash表,有序集合,链表时, 存储结构采用一种ziplist的存储结构, 这种结构内存排列更紧密, 能提高访存性能。

  • field个数少且没有大的value时,内部编码为ziplist
    如:hmset user:3 name zhangch age 27;
    object encoding user:3 //返回ziplist
  • value大于64字节,内部编码由ziplist变成hashtable

2.3 列表List类型

用来存储多个有序的字符串,一个列表最多存2的32次方减一个元素。

因为有序,所以可以使用下标来获取元素,也可获取范围内的元素。

命令:

  • lpush user:1:love sing jumb rap basketball 从列表左边开始逐一放入元素
    列表元素为 basketball rap jumb sing

  • rpush key value 同上,从右侧插入

  • linsert key before oldValue newValue 在old前面插入new

  • linsert key after oldValue newValue 在old后面插入new

  • llen key 返回列表长度

  • lindex key index 从左侧获取下标index的元素

  • lrange key beginIndex endIndex 获取列表指定的索引 index:[0,n-1]

  • lpop key 删除左侧第一个元素,并返回它

  • rpop key 删除右侧第一个元素,并返回它

2.4 集合Set

与列表List类似,元素不重复,且无序,用于用户标签、社交、查询有共同爱好的人、智能推荐等。最大存储元素2的32次方减1,支持增删改查,对集合求交集、差集、并集。

如上图,有两个key,分别为用户1和用户2的爱好。

命令:
exists key 检查key是否存在
sadd key value1 value2 .... 加入元素,无序,若加入相同元素无效
srem key value1 value2 ... 删除元素,返回成功的个数
smembers key 返回所有元素,无序
scard key 返回元素个数

sinter key1 key2 求交集
sdiff key1 key2 求差集
sunion key1 key2 求并集
sinterstore key3 key1 key2key1key2value相交,结果存储到key3sdiff,sunion同理

2.5 有序集合ZSet

带有分数的set,可用于排行榜,点赞数,不能有重复的成员。

指令

  • key [NX|XX] [CH] [INCR] score member [score member ...]

  • zadd key score1 member1 score2 member2 ... 添加

  • zadd key score3 member3 nx 用于添加,不存在key才添加

  • zadd key score1 member1 xx 用于修改 xx为存在时才添加

  • zrange key beginIndex endIndex withscores 查询指定index,随分数一并

  • zrank key member 返回排名

  • zrevrank key member 逆向返回排名

  • XX: 仅仅更新存在的成员,不添加新成员。

  • NX: 不更新存在的成员。只添加新成员。

  • CH: 修改返回值为发生变化的成员总数,原始是返回新添加成员的总数 (CH 是 changed 的意思)。更改的元素是新添加的成员,已经存在的成员更新分数。 所以在命令中指定的成员有相同的分数将不被计算在内。注:在通常情况下,ZADD返回值只计算新添加成员的数量。

  • INCR: 当ZADD指定这个选项时,成员的操作就等同ZINCRBY命令,对成员的分数进行递增操作。

3 使用场景

key的设计原则,简短明了,节约内存,一般以业务功能为主。
如:user:1:order 标识用户1的订单

3.1 String应用

  • 结构体或对象的存储
    1.set user:1 value value 可以为xmljson
    2.mset user:1:name zhangch user:1:age 27
    3.mget user:1:name user:1:age

  • 计数功能
    incr article:001 文章编号001
    get article:001

  • 各类场景下(单机或分布式)标识号
    incr serialNo 1000

  • 集群环境下的Session共享
    使用spring sessionredis完成session共享

3.2 Set应用~用户标签、喜好、社交

3.2.1 用户标签

  • 给用户添加标签:
    sadd user:1:fav basball fball pq
    sadd user:2:fav basball fball

  • 给标签添加用户
    sadd basball:users user:1 user:2
    sadd fball:users user:1 user:2

  • 计算出两个人相同的兴趣:
    sinter user:1:fav user2:fav

3.2.2 微信抽奖活动

  • 活动001 ,member为参加用户id
    sadd act:001 1 2 3 4 四个用户参加了这个活动

  • 随机抽取2位
    srandmember act:001 2spop act:001 2

  • 查看活动参与用户
    smembers act:001

3.2.3 朋友圈点赞

  • 朋友圈消息ID 008,点赞统计
    sadd thumb:008 user:001 user:002 user:003 三个用户点了这个消息的赞

  • 取消点赞
    srem thumb:008 user:001 用户001取消了这个赞

  • 统计点赞个数
    scard thumb:008

  • 统计点赞的人
    smembers thumb:008

3.3 Hash应用

  • 购物车

    用户001 购物车:cart
    hmset cart:001 prod:01 1 prod:02 1 prod:03 1
    1.全选功能-获取所有该用户的所有购物车商品
    hgetall cart:001
    2.商品数量-购物车图标上要显示购物车里商品的总数
    hvals cart:001
    3.删除-要能移除购物车里某个商品
    hdel cart:001 prod:03
    4.增加或减少某个商品的数量
    hincrby cart:001 prod:01 2

3.4 List应用

  • 实现栈
    lpush + lpop

  • 实现队列
    lpush + rpop

  • 实现阻塞队列
    lpush + brpop

  • 微信订阅号信息

    用户微信id001,关注了CSDN,男子别输在说话上,如何设计?
    1.男子别输在说话上发布一条消息 id 101
    lpush message:001 101
    2.CSDN发布一条消息 id 102
    lpush message:001 102
    3.查询001用户的微信消息列表
    lrange message:001 0 -1

3.5 Zset应用

排行榜,热门话题,热搜等

  • 日期作为key
    zadd 20191221 10 topic:1 12 topic:2 14 topic:3

  • 点击topic:1
    zincrby 20191221 1 topic:1

  • 统计热搜前10
    zrevrange 20191221 0 9

  • 统计近三天的话题量
    zunionstore topic:3d 3 20191221 20191222 20191223

3.6 Hash与List应用~订单场景

订单 --> 订单详情
用户 --> 订单

  • 有三个订单 ,订单id,订单价格,下单时间
    hmset order:1 oderId 1 price 10 time 2019-12-10
    hmset order:2 oderId 2 price 12 time 2019-12-11
    hmset order:3 oderId 3 price 13 time 2019-12-12

  • 用户1有多个订单
    lpush user:1:order order:1 order:2 order:3

  • 用户1又下单了
    hmset order:3 oderId 4 price 34 time 2019-12-14
    lpush user:1:order order:4

  • 查询用户1的订单记录

List orderKeyList = lrange user:1:order 0 -1 //查询用户1所有订单的key
orderKeyList.forEach(k->{
	orderInfo = hmget k
})

4 使用String Hash 序列化三种方式存储用户信息比较

1.String方式
set user:1:name zhangch
set user:1:age 23
优:简单直观,每个键对应一个值
缺:键数过多,占用内存多,用户信息分散,不用于生成环境

2.将用户序列化后存入
set user:1 (UserObject)
优:编程简单,内存使用率高
缺:序列化反序列化存在开销

3.Hash方式
hset user:1 name zhangch age 26
优:简单直观,使用合理,可减少内存空间消耗
缺:需要控制ziplisthashtable两种编码转换,且hashtable消耗更多内存

5 持久化机制

Redis是一个支持持久化的数据库,可将内存中的数据同步到磁盘中来保证数据持久化,避免进程退出造成的数据丢失。

5.1 RDB

将当前进程数据生成快照.rdb文件保存到硬盘中,有手动触发(savebgsave)和自动触发。

  • save
    阻塞redis,直到rdb持久化完成,若内存实例较大会造成长时间阻塞,线上不建议使用。

  • bgsave
    redis进行fork一个子线程,由子线程完成持久化操作,阻塞时间很短,是save操作的优化,在redis-cli shutdown关闭redis服务时,如果没有开启AOF持久化,会自动执行bgsave

  • 操作
    1.设置RDB文件保存路径:config set dir /usr/local
    2.bgsavedump.rdb 保存到 /usr/local
    3.恢复 :将rdb文件放到redis安装目录与redis.conf同级目录,重启redis即可。

  • 优点
    加载RDB恢复数据速度快于AOF方式。
    RDB文件适用于备份、全量复制,用于灾难恢复。

  • 缺点
    无法实时持久化,每次操作需要fock子进程,操作成本过高。
    保存过后的RDB文件,可能存在新老版本不兼容问题。

5.2 AOF

针对RDB方式不适合实时持久化,Redis提供AOF的方式来解决。
redis.config 设置 appendonly yes (默认不开启,为no
默认文件名 appendfilename "appendonly.aof"

  • 持久化流程:
    1.所有的写入操作,会append追加到aof_buf缓冲区
    2.aof_buf缓冲区向硬盘做sync同步
    3.随着AOF文件越来越大,需要定期对AOF文件rewrite重写,达到压缩
    4.当redis重启,可load加载AOF文件进行恢复

  • 恢复过程
    1.appendonly 设置为yes
    2.将AOF文件放到指定位置
    3.重启redis,redis会自动加载appendonly.aof文件

  • AOF配置
    启用AOF持久化方式
    appendonly yes
    每收到写命令就立即强制写入磁盘,最慢的,但是保证完全的持久化,不推荐使用
    appendfsync always
    每秒强制写入磁盘一次,性能和持久化方面做了折中,推荐
    appendfsync everysec
    正在导出rdb快照的过程中,要不要停止同步AOF
    no-appendfsync-on-rewrite yes
    AOF文件大小比起上次重写时的大小,增长率100%时,重写
    auto-aof-rewrite-percentage 100
    AOF文件,至少超过64M时,重写
    auto-aof-rewrite-min-size 64mb

  • 5.3 RDB 与AOF 恢复顺序

6 分布式锁

todo

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!