Redis设计思路结构原理集群原理和应用场景

1.1. 技术说明

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

它支持存储的value类型相对更多,包括string(字符串)list(链表)set(集合)zset(sorted set --有序集合)hash(哈希类型)。这些数据类型都支持push/popadd/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步保证数据备份

1.2. 技术内部架构

1.2.1. 设计思想

无论从设计还是源码,Redis都尽量做到简单,其中运用到的原理也通俗易懂。

Redis非常精细地考虑了压缩数据、减少内存碎片等问题

Redis本质上是一个数据结构服务器(data structures server),以高效的方式实现了多种现成的数据结构,没有MySQL那样的索引机制,因为其内建一个基于hash的字典

Redis采用单线程的设计带来的好处是,极大简化了数据结构和算法的实现。相反,Redis通过异步IOpipelining等机制来实现高速的并发访问。

Redis使用dict基础数据结构,解决了算法中的查找问题并且实现了快速响应时间

1.2.2. 系统组成

l 网络模型

Redis是典型的基于Reactor的事件驱动模型,是高效的单进程单线程框架,整体分为接受请求处理器、响应处理器和应答处理器三个同步模块,每一个请求都是要经历这三个部分。

Redis集成了libevent/epoll/kqueue/select等多种事件管理机制,可以根据操作系统 版本自由选择合适的管理机制,其中libevent是最优选择的机制。

 

Redis的网络模型有着所有事件驱动模型的优点,高效低耗。但是面对耗时较长的 操作的时候,同样无法处理请求,只能等到事件处理完毕才能响应,比如删除redis 中全量的key-value,整个操作时间较长,操作期间所有的请求都无法响应。所以 了解清楚网络模型有助于在业务中扬长避短,减少长耗时的请求,尽可能多一些简 单的短耗时请求发挥异步模型的最大的威力,事实上在Redis的设计中也多次体现 这一点

l 数据类型

Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)

Ø String Redis最基本的数据类型,一个键最大能存储512MBString类型是 二进制安全的。意思是redisstring可以包含任何数据。比如jpg图片或 者序列化的对象一个key对应一个value

 

 

Ø Hash Redis hash是一个键值(key=>value)对集合,string类型的fieldvalue 的映射表,hash 特别适合用于存储对象。每个 hash 可以 存储 232 -1 键值对(40多亿)

 

Ø List Redis List列表是简单的字符串列表,按照插入顺序排序。你可以添加一 个元素到列表的头部(左边)或者尾部(右边),列表最多可存储 232 - 1 元素(4294967295, 每个列表可存储40多亿)

 

Ø Set RedisSetstring类型的无序集合。

集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)

根据集合内元素的唯一性,第二次插入的相同元素将被忽略

集合中最大的成员数为 232 - 1(4294967295, 每个集合可存储40多亿个 成员)

Sadd:命令添加一个string元素到,key对应的set集合中,成功返回1,如果 元素已经在集合中返回0,key对应的set不存在返回错误。

 

 

Ø Zset Redis zset set 一样也是string类型元素的集合,且不允许重复的成员。

不同的是每个元素都会关联一个double类型的分数。redis正是通过分数 来为集合中的成员进行从小到大的排序,zset的成员是唯一的,但分数 (score)却可以重复。

zadd命令:添加元素到集合,元素在集合中存在则更新对应score

 

l Redis的持久化方案

    Redis的所有数据都是保存到内存中的。

    Rdb:快照形式,定期把内存中当前时刻的数据保存到磁盘。Redis默认支持的持久化方案。

    aof形式:append only file。把所有对redis数据库操作的命令,增删改操作的命令。保存到文件中。数据库恢复时把所有的命令执行一遍即可。

1.2.4. 系Redis的持久化方案

Redis的所有数据都是保存到内存中的。

Rdb:快照形式,定期把内存中当前时刻的数据保存到磁盘。Redis默认支持的持久化方案。

aof形式:append only file。把所有对redis数据库操作的命令,增删改操作的命令。保存到文件中。数据库恢复时把所有的命令执行一遍即可。

 在redis.conf配置文件中配置。

Rdb:

 

Aof的配置:

 

两种持久化方案同时开启使用aof文件来恢复数据库。

RDB持久化配置

Redis会将数据集的快照dump到dump.rdb文件中。此外,我们也可以通过配置文件来修改Redis服务器dump快照的频率,在打开6379.conf文件之后,我们搜索save,可以看到下面的配置信息:

save 900 1              #在900秒(15分钟)之后,如果至少有1个key发生变化,则dump内存快照。

save 300 10            #在300秒(5分钟)之后,如果至少有10个key发生变化,则dump内存快照。

save 60 10000        #在60秒(1分钟)之后,如果至少有10000个key发生变化,则dump内存快照。

AOF持久化配置

在Redis的配置文件中存在三种同步方式,它们分别是:

appendfsync always     #每次有数据修改发生时都会写入AOF文件。

appendfsync everysec  #每秒钟同步一次,该策略为AOF的缺省策略。

appendfsync no          #从不同步。高效但是数据不会被持久化



l Key命令

设置key的过期时间。(-1 代表持久化,-2代表不存在,0代表操作失败)

Expire key second:设置key的过期时间

Ttl key:查看key的有效期

Persist key:清除key的过期时间。Key持久化。

更多参考:http://doc.redisfans.com/

 

 

1.2.3. 架构图

 

1.2.3.1Redis内部结构图

各功能模块说明:

 

File Event: 处理文件事件(在多个客户端中实现多路复用,接受它们发来的命令请求(读事 件),并将命令的执行结果返回给客户端(写事件))

 

Time Event: 时间事件(更新统计信息,清理过期数据,附属节点同步,定期持久化等)

 

AOF: 命令日志的数据持久化

 

RDB:实际的数据持久化

 

Lua Environment : Lua 脚本的运行环境. 为了让 Lua 环境符合 Redis 脚本功能的需求, Redis Lua 环境进行了一系列的修改, 包括添加函数库、更换随机函数、 保护全局变量, 等等

 

Command table(命令表):在执行命令时,根据字符来查找相应命令的实现函数。

 

Share Objects(对象共享):主要存储常见的值:a.各种命令常见的返回值,例如返回值OKERRORWRONGTYPE等字符;b. 小于 redis.h/REDIS_SHARED_INTEGERS (默认1000)的所有整数。通过预分配的一些常见的值对象,并在多个数据结构 之间共享对象,程序避免了重复分配的麻烦。也就是说,这些常见的值在内存 中只有一份。

 

DatabasesRedis数据库是真正存储数据的地方。当然,数据库本身也是存储在内存中的。 (结构图见1.2.3.2数据库内存数据结构图)

 

 

1.2.3.2数据库内存数据结构图

 

Database的内容要点包括:

 

Ø 数据库主要由 dict expires 两个字典构成,其中 dict 保存键值对,而 expires 则保存键的过期时间。

 

Ø 数据库的键总是一个字符串对象,而值可以是任意一种 Redis 数据类型,包括字符串、哈希、集合、列表和有序集。

 

Ø expires 的某个键和 dict 的某个键共同指向同一个字符串对象,而 expires键的值则是该键以毫秒计算的 UNIX 过期时间戳。

 

Ø Redis 使用惰性删除和定期删除两种策略来删除过期的键。

 

Ø 更新后的 RDB 文件和重写后的 AOF 文件都不会保留已经过期的键。

 

Ø 当一个过期键被删除之后,程序会追加一条新的 DEL 命令到现有 AOF 文件末尾。

 

Ø 当主节点删除一个过期键之后,它会显式地发送一条 DEL 命令到所有附属节点。

 

Ø 附属节点即使发现过期键,也不会自作主张地删除它,而是等待主节点发来 DEL 命令,这样可以保证主节点和附属节点的数据总是一致的。

 

Ø 数据库的dict 字典和expires 字典的扩展策略和普通字典一样。它们的收缩策略是:当节点的填充百分比不足 10% 时,将可用节点数量减少至大于等于当前已用节点数量。

 

 


1.2.3.2 Redis集群结构图

 

架构细节:

(1)所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.

(2)节点的fail是通过集群中超过半数的节点检测失效时才生效.

(3)客户端与redis节点直连,不需要中间proxy.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可

(4)redis-cluster把所有的物理节点映射到[0-16383]slot,cluster 负责维护node<->slot<->value

Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点如图1.2.3.4哈希槽映射图

 

 

 

 

 

1.2.3.4哈希槽映射图

1.3. 应用场景

1.3.1. 会话缓存(Session Cache

l 热点数据(经常会被查询,但是不经常被修改或者删除的数据)另外,内存中的数据也提供了AOFRDB等持久化机制可以选择

Select 数据库前查询redis,有的话使用redis数据,放弃select 数据库,没有的话,select 数据库,然后将数据插入redis

update或者delete数据库钱,查询redis是否存在该数据,存在的话先删除redis中数据,然后再update或者delete数据库中的数据

1.3.2. 计数/排行榜

诸如统计点击数等应用。由于单线程,可以避免并发问题,保证不会出错,100%毫秒级性能。

l Redis在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单,Redis只是正好提供了这两种数据结构。所以,我们要从排序集合中获取到排名最靠前的10个用户–我们称之为“user_scores”,我们只需要像下面一样执行即可:

当然,这是假定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的 分数,你需要这样执行:

ZRANGE user_scores 0 10 WITHSCORES

1.3.3. 队列

相当于消息系统,ActiveMQRocketMQ等工具类似,但是个人觉得简单用一下还行,如果对于数据一致性要求高的话还是用ActiveMQ专业系统。

由于redis把数据添加到队列是返回添加元素在队列的第几位,所以可以做判断用户是第几个访问这种业务

队列不仅可以把并发请求变成串行,并且还可以做队列或者栈使用

1.3.4. 分布式锁与单线程机制

验证前端的重复请求(可以自由扩展类似情况),可以通过redis进行过滤:每次请求将request Ip、参数、接口等hash作为key存储redis(幂等性请求),设置多长时间有效期,然后下次请求过来的时候先在redis中检索有没有这个key,进而验证是不是一定时间内过来的重复提交

秒杀系统,基于redis是单线程特征,防止出现数据库“爆破”

1.3.5. 发布/订阅

l Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。Redis 客户端可以订阅任意数量的频道


猜你喜欢

转载自blog.csdn.net/hiqingtian/article/details/79459392