内存数据库--Redis基础知识总结

133 阅读7分钟

内存数据库--Redis

redis

概念

Redis 是开源的内存数据结构存储,可用作数据库、缓存和消息队列。支持的数据类型有 strings, hashes, lists, sets , Redis具有内置的复制,Lua脚本,LRU逐出,事务和不同级别的磁盘持久性,并通过Redis Sentinel和Redis Cluster自动分区提供高可用性 。

Redis于Memcached的区别

  1. 是否支持服务端操作。两者都支持字符串数据类型,redis还支持hash、list、set、zset,redis支持更丰富的数据操作。在memcached需要将数据拿到数据进行类似的修改再set回去,这大大增加了网络IO的次数和数据体积,而在redis中,复杂的操作和get/set一样高效。
  2. 内存使用效率对比。如果是使用简单的字符串类型,memcached的效率要比redis高,但是redis使用hash机构来进行key-value存储,由于组合式的压缩,其内存利用率会高于memcached。
  3. 性能对比。由于redis使用的是单核,而memcached是多线程的,在每一核平均处理小数据上,redis要比memcached性能要高,如果数据超过了100K,memcached的性能比redis高。
  4. 是否支持集群。redis3.0+支持,memcached不支持集群模式。

数据类型、常用命令和使用场景

  1. String

    常用的操作:

    • set key value //存入字符串键值对
    • Mset key value [key value] //批量操作
    • setnx key value //存入一个不存在的字符串键值对
    • get key //根据键获取值
    • mget key [key ...]
    • del key [key...]
    • expipe key seconds //设置键过去时间

    原子加减

    • incr key
    • decr key
    • incrby key increment //加上increment
    • decrby key increment //减去increment

    应用的场景:

    • 单值缓存
    • 对象缓存
    • 分布式锁
  2. hash

    常用操作

    • hset key field value
    • hsetnx key field value //存储一个不存在哈希表key的键值
    • hmset key field value field value
    • hdel key field
    • hget key field
    • hmget key field [field..]
    • hgetall key
    • hlen key
    • hincrby key field increment //为哈希表中的field键的值增加increment

    优点

    • 同类数据归类整合储存,方便数据管理
    • 相比String,消耗cpu更少,占用空间更小

    劣势

    • 过期功能只能用在key上,不能用在field上
    • 集群模式下不适合大规模使用

    应用场景:用户对象,如用户信息对象,用户ID为key,name为field,张三为value。

  3. list

    常用操作

    • lpush
    • rpush
    • lpop
    • rpop
    • lrange key stat stop //返回列表key中指定区间内的元素,区间偏移量以为start和stop指定
    • blpop
    • rlpop key [key...] timeout //从key列表表位弹出一个元素,如果没有元素可取,则等待timeout秒。timeout=0为一直等待

    应用场景: 关注列表,粉丝列表

  4. set

    常用操作

    • sadd key member [member...]
    • srem key member
    • smembers key
    • scard key //查看个数
    • sismember key member //判断是否是集合元素
    • srandmember key [count] //随机选出元素,不删除
    • spop key [count} //随机选出元素,删除
    • sinter key [key..] //交集
    • sinterstore destination key [key..] //将交集的结果存入新集合destination中
    • sunion key [key..] //合集
    • sunionstore destination key [key..]
    • sdiff key [key..] //差集
    • sdiffstore destination key [key..]

    应用场景:点赞数、共同关注、收藏、标签

  5. zset

    常用命令

    • zadd
    • zrange
    • zrem
    • zcard

    应用场景:根据时间排序的发表文章

性能优化

高可用

数据持久化(rdb&& aof)

​ 持久化功能有效避免因进程退出造成的数据丢失问题,当下次重启时利用持久化文件就能恢复之前的数据。redis支持rdb和aof两种持久化机制。

1、rdb

​ rdb是把当前线程数据生成快照保存到磁盘中。触发机制有手动和自动。手动触发对应save(会阻塞redis服务,不建议使用)和bgsave命令。bgsave是redis主线程进行fork(稍微有点阻塞)操作创建子进程来进行rdb持久化。自动触发的场景有使用save相关配置、主从复制时主节点自动执行、执行重载redis命令时和执行shutdown命令。

​ 保存:rdb文件保存在dir配置的指定目录下,文件名通过dbfilename配置指定。

​ 优点:二进制文件,适用于备份、全量复制,将rdb文件上传到远程服务器用于灾难恢复;恢复数据远远快于AOF方式。

​ 缺点:不能做到实时/秒级持久化;二进制格式文件存在和redis版本可能出现兼容性问题。

2、aof

​ 是以独立的方式记录每次写命令,重启是在重新执行aof文件中的命令达到快速恢复数据的目的。主要解决实时性。

​ 默认不开启,需要配置 appendonly yes,保存路径和rdb一样通过dir配置指定,文件名通过dbfilename配置指定。

​ 工作流程:所有的写入命令都会追加到缓冲区中,缓冲区根据对应的策略(每秒)同步到硬盘,定期对aof文件进行重写以压缩大小。

主从复制

集群模式

​ Redis 集群是一个提供在多个Redis间节点间共享数据的程序集。

​ Redis 集群通过分区来提供一定程度的可用性,在实际环境中当某个节点宕机或者不可达的情况下继续处理命令. Redis 集群的优势:

  • 自动分割数据到不同的节点上。
  • 整个集群的部分节点失败或者不可达的情况下能够继续处理命令。

Redis 集群没有使用一致性hash, 而是引入了 哈希槽的概念。

​ Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽.集群的每个节点负责一部分hash槽。

集群宕机,数据迁移

旧数据回收策略

​ redis中的数据,对于过期的数据,当 所有改变key的值的操作都会使他清除 ,其他还有定期删除和惰性删除两种。

​ 定期删除:具体就是Redis每秒10次做的事情:

  1. 测试随机的20个keys进行相关过期检测。
  2. 删除所有已经过期的keys。
  3. 如果有多于25%的keys过期,重复步奏1.

​ 当redis被当做缓冲来使用,新增数据时,redis占用的内存达到了maxmemory上限,需要选择不同的策略(行为)来回收旧数据。

回收策略

​ maxmemory-policy配置指令进行配置。以下是可用的策略:

	*    **noeviction**:返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令(大部分的写入指令,但DEL和几个例外) 
	*     **allkeys-lru**: 尝试回收最少使用的键(LRU),使得新添加的数据有空间存放。 
	*     **volatile-lru**: 尝试回收最少使用的键(LRU),但仅限于在过期集合的键,使得新添加的数据有空间存放。 
	*     **volatile-lru**: 尝试回收最少使用的键(LRU),但仅限于在过期集合的键,使得新添加的数据有空间存放。
	*     **volatile-random**: 回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。  
	*     **volatile-ttl**: 回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。 

一般的经验规则:

  • 使用allkeys-lru策略:当你希望你的请求符合一个幂定律分布,也就是说,你希望部分的子集元素将比其它其它元素被访问的更多。如果你不确定选择什么,这是个很好的选择。.
  • 使用allkeys-random:如果你是循环访问,所有的键被连续的扫描,或者你希望请求分布正常(所有元素被访问的概率都差不多)。
  • 使用volatile-ttl:如果你想要通过创建缓存对象时设置TTL值,来决定哪些对象应该被过期。
回收进程如何工作

理解回收进程如何工作是非常重要的:

  • 一个客户端运行了新的命令,添加了新的数据。
  • Redi检查内存使用情况,如果大于maxmemory的限制, 则根据设定好的策略进行回收。
  • 一个新的命令被执行,等等。
  • 所以我们不断地穿越内存限制的边界,通过不断达到边界然后不断地回收回到边界以下。

如果一个命令的结果导致大量内存被使用(例如很大的集合的交集保存到一个新的键),不用多久内存限制就会被这个内存使用量超越。