- 概述
Redis是速度非常快的非关系型(NoSQL)内存键值数据库,可以存储键和五种不同类型的值之间的值。
键的类型只能为字符串,值支持五种数据类型:字符串、列表、集合、散列表、有序集合
Redis支持很多种特性,例如将内存的数据持久化到硬盘中,使用复制来扩展读性能,使用分片来扩展写性能.
优点:异常快,丰富的数据类型,多种使用工具(缓存、消息队列)
- 数据类型
- 字符串:
可以存储的值:字符串、整数或者浮点数。

用处:如缓存用户信息,将信息使用json序列化成String型,放入redis/计数器的自增自减
对整个字符串或者字符串的其中一部分执行操作对整数和浮点数执行自增或者自减操作
> set hello world
OK
> get hello
"world"
> del hello
(integer) 1
> get hello
(nil)
- 列表
可以存储的值:列表

用处:如用做异步队列使用
从两端压入或者弹出元素 对单个或者多个元素进行修剪,只保留一个范围内的元素
> rpush list-key item
(integer) 1
> rpush list-key item2
(integer) 2
> rpush list-key item
(integer) 3
> lrange list-key 0 -1
1) "item"
2) "item2"
3) "item"
> lindex list-key 1
"item2"
> lpop list-key
"item"
> lrange list-key 0 -1
1) "item2"
2) "item"
- 集合
可以存储的值:无序集合

用处:用来存储活动中奖ID(去重功能)
添加、获取、移除单个元素
检查一个元素是否存在于集合中
计算交集、并集、差集从集合里面随机获取元素
> sadd set-key item
(integer) 1
> sadd set-key item2
(integer) 1
> sadd set-key item3
(integer) 1
> sadd set-key item
(integer) 0
> smembers set-key
1) "item"
2) "item2"
3) "item3"
> sismember set-key item4
(integer) 0
> sismember set-key item
(integer) 1
> srem set-key item2
(integer) 1
> srem set-key item2
(integer) 0
> smembers set-key
1) "item"
2) "item3"
- 字典
可以存储的值:包含键值对的无序散列表

用处:如存放某一对象具体属性
添加、获取、移除单个键值对
获取所有键值对
检查某个键是否存在
> hset hash-key sub-key1 value1
(integer) 1
> hset hash-key sub-key2 value2
(integer) 1
> hset hash-key sub-key1 value1
(integer) 0
> hgetall hash-key
1) "sub-key1"
2) "value1"
3) "sub-key2"
4) "value2"
> hdel hash-key sub-key2
(integer) 1
> hdel hash-key sub-key2
(integer) 0
> hget hash-key sub-key1
"value1"
> hgetall hash-key
1) "sub-key1"
2) "value1"
- 有序集合
可以存储的值:有序集合

用处如:粉丝列表
添加、获取、删除元素
根据分值范围或者成员来获取元素
计算一个键的排名
> zadd zset-key 728 member1
(integer) 1
> zadd zset-key 982 member0
(integer) 1
> zadd zset-key 982 member0
(integer) 0
> zrange zset-key 0 -1 withscores
1) "member1"
2) "728"
3) "member0"
4) "982"
> zrangebyscore zset-key 0 800 withscores
1) "member1"
2) "728"
> zrem zset-key member1
(integer) 1
> zrem zset-key member1
(integer) 0
> zrange zset-key 0 -1 withscores
1) "member0"
2) "982"
- 数据结构
跳跃表:是有序集合的底层实现之一。
跳跃表是基于多指针有序链表实现的,可以看成多个有序链表.
在查找时,从上层指针开始查找,找到对应的区间之后再到下一层去查找。下图演示了查找 22 的过程。

与红黑树相比,跳跃表具有以下优点:
1. 插入速度非常快速,因为不需要进行旋转等操作来维护平衡性;2. 更容易实现; 3. 支持无锁操作。
部分底层数据结构:动态字符串、链表、字典、跳跃表、整数集合、压缩列表
- 使用场景
计数器:可以对 String 进行自增自减运算,从而实现计数器功能。
Redis 这种内存型数据库的读写性能非常高,很适合存储频繁读写的计数量。
缓存:将热点数据放到内存中,设置内存的最大使用量以及淘汰策略来保证缓存的命中率。
查找表:例如 DNS 记录就很适合使用 Redis 进行存储。
查找表和缓存类似,也是利用了 Redis 快速的查找特性。但是查找表的内容不能失效,而缓存的内容可以失效,因为缓存不作为可靠的数据来源
消息队列
List 是一个双向链表,可以通过 lpush 和 rpop 写入和读取消息
不过最好使用 Kafka、RabbitMQ 等消息中间件。
会话缓存
可以使用 Redis 来统一存储多台应用服务器的会话信息。
当应用服务器不再存储用户的会话信息,也就不再具有状态,一个用户可以请求任意一个应用服务器,从而更容易实现高可用性以及可伸缩性。
分布式锁实现
在分布式场景下,无法使用单机环境下的锁来对多个节点上的进程进行同步。
可以使用 Redis 自带的 SETNX 命令实现分布式锁,除此之外,还可以使用官方提供的 RedLock 分布式锁实现。
其它
Set 可以实现交集、并集等操作,从而实现共同好友等功能。
ZSet 可以实现有序性操作,从而实现排行榜等功能。
- Redis与Memcached
两者都是非关系型内存键值数据库,主要有以下不同:
- 数据类型|redis支持物种不同的数据类型,可以更灵活解决问题|memcached仅支持字符串类型
- 数据持久化|redis支持两种持久化:RDB快照和AOF日志|memcached不支持持久化
- 分布式|memcached不支持分布式,只能通过再客户端使用一致性哈希来实现分布式存储,这种方式在存储和查询时都需要现在客户端计算一次数据所在的节点|redis cluster实现了分布式的支持
- 内存管理机制|redis 并不是所有数据都一直存储在内存中,可以将一些很久没用的value交换到磁盘,memcached的数据则会一直在内存中|
- 键的过期时间
redis可以为每个键设置过期时间,当键过期时,会自动删除该键。
对于散列表这种容器,只能为整个键设置过期时间(list),而不能为里面的单个元素设置过期时间
- 数据淘汰策略
可以设置内存最大使用量,当内存使用量超出时,会施行数据淘汰策略
六种淘汰策略
策略 描述
volatile-lru 从已设置过期时间的数据集中挑选最近最少使用的数据淘汰述
volatile-ttl 从已设置过期时间的数据集中挑选将要过期的数据淘汰述
volatile-random 从已设置过期时间的数据集中任意选择数据淘汰述
allkeys-lru 从所有数据集中挑选最近最少使用的数据淘汰述
allkeys-random 从所有数据集中任意选择数据进行淘汰
noeviction 禁止驱逐数据述
- 持久化
Redis 是内存型数据库,为了保证数据在断电后不会丢失,需要将内存中的数据持久化到硬盘上.
RDB持久化:生成一个经过压缩的二进制文件
- 将某个时间点的所有数据都存放到硬盘上
- 可以将快照复制到其他服务器从而创建具有相同数据的服务器副本
- 如果系统发生故障,将会丢失最后一次创建快照之后的数据
- 如果数据量很大,保存快照的时间会很长
AOF持久化:保存写命令添加到AOF文件的末尾
使用 AOF 持久化需要设置同步选项,从而确保写命令同步到磁盘文件上的时机。这是因为对文件进行写入并不会马上将内容同步到磁盘上,而是先存储到缓冲区,然后由操作系统决定什么时候同步到磁盘。有以下同步选项:
always 每个写命令都同步
everysec 每秒同步一次
no 让操作系统来决定何时同步
- always 选项会严重减低服务器的性能;
- everysec 选项比较合适,可以保证系统崩溃时只会丢失一秒左右的数据,并且 Redis 每秒执行一次同步对服务器性能几乎没有任何影响;
- no 选项并不能给服务器性能带来多大的提升,而且也会增加系统崩溃时数据丢失的数量。
随着服务器写请求的增多,AOF 文件会越来越大。Redis 提供了一种将 AOF 重写的特性,能够去除 AOF 文件中的冗余写命令。
- 事务
可以让一个客户端不被其他客户端打断的情况下执行多个民工,只有当此事务结束后,Redis才会处理其他客户端的命令.
事务中的多个命令被一次性发送给服务器,而不是一条一条发送,这种方式被称为流水线,它可以减少客户端与服务器之间的网络通信次数从而提升性能。
Redis 最简单的事务实现方式是使用 MULTI 和 EXEC 命令将事务操作包围起来。
- 事件
Redis 服务器是一个事件驱动程序。
文件事件
服务器通过套接字与客户端或者其他服务器进行通信,文件事件就是对套接字操作的抽象

时间事件
服务器有一些操作需要在给定的时间点执行,时间事件是对这类定时操作的抽象。
时间事件又分为:
定时事件:是让一段程序在指定的时间之内执行一次;
周期性事件:是让一段程序每隔指定时间就执行一次。
Redis 将所有时间事件都放在一个无序链表中,通过遍历整个链表查找出已到达的时间事件,并调用相应的事件处理器。
事件的调度与执行
服务器需要不断监听文件事件的套接字才能得到待处理的文件事件,但是不能一直监听,否则时间事件无法在规定的时间内执行,因此监听时间应该根据距离现在最近的时间事件来决定。

- 复制
通过使用 slaveof host port 命令来让一个服务器成为另一个服务器的从服务器。
一个从服务器只能有一个主服务器,并且不支持主主复制。
连接过程
-
主服务器创建快照文件,发送给从服务器,并在发送期间使用缓冲区记录执行的写命令。快照文件发送完毕之后,开始向从服务器发送存储在缓冲区中的写命令;
-
从服务器丢弃所有旧数据,载入主服务器发来的快照文件,之后从服务器开始接受主服务器发来的写命令;
-
主服务器每执行一次写命令,就向从服务器发送相同的写命令。
主从链
随着负载不断上升,主服务器可能无法很快地更新所有从服务器,或者重新连接和重新同步从服务器将导致系统超载。为了解决这个问题,可以创建一个中间层来分担主服务器的复制工作。中间层的服务器是最上层服务器的从服务器,又是最下层服务器的主服务器。

主从复制:master上的数据更新后根据配置文件配置策略,自动同步到slave
- 高可用性:数据在多台服务器存储,一台宕机其余可以顶上
- 读写分离:写数据在master,读在slave上,提升数据服务器的性能
- 容灾恢复;主机宕机,slave选一台作为master,其余slavae作为主机
- Sentinel
sentinel(哨兵)可以监听集群中的服务器,并在主服务器进入下线状态时,自动从从服务器中选举出新的主服务器
- 分片
分片是将数据划分为多个部分的方法,可以将数据存储到多台机器里面,这种方法在解决某些问题时可以获得线性级别的性能提升。
假设有 4 个 Redis 实例 R0,R1,R2,R3,还有很多表示用户的键 user:1,user:2,… ,有不同的方式来选择一个指定的键存储在哪个实例中。
- 最简单的方式是范围分片,例如用户 id 从 0~1000 的存储到实例 R0 中,用户 id 从 1001~2000 的存储到实例 R1 中,等等。但是这样需要维护一张映射范围表,维护操作代价很高
- 还有一种方式是哈希分片,使用 CRC32 哈希函数将键转换为一个数字,再对实例数量求模就能知道应该存储的实例。
根据执行分片的位置,可以分为三种分片方式:
- 客户端分片:客户端使用一致性哈希等算法决定键应当分布到哪个节点。
- 代理分片:将客户端请求发送到代理上,由代理转发请求到正确的节点上
- 服务器分片:Redis Cluster。
904

被折叠的 条评论
为什么被折叠?



