Redis--高性能分布式缓存

12 Feb 2021

缓存原理&设计

缓存基本思想

在互联网技术中,缓存是系统快速响应的关键技术之一 以空间换时间的一种技术(艺术)

使用缓存的优势

使用缓存的代价

缓存的读写模式

Redis基础

Redis介绍

Redis单机版安装和使用

Redis数据类型

Redis是一个Key-Value的存储系统,使用ANSI C语言编写。 key的类型是字符串。
value的数据类型有:
常用的:string字符串类型、list列表类型、set集合类型、sortedset(zset)有序集合类型、hash类 型。
不常见的:bitmap位图类型、geo地理位置类型。
Redis5.0新增一种:stream类型

注意:Redis中命令是忽略大小写,(set SET),key是不忽略大小写的 (NAME name)

Redis常用命令

官方命令大全网址:http://www.redis.cn/commands.html

缓存过期和淘汰策略

Redis性能高:
官方数据
读:110000次/s
写:81000次/s

Redis扩展特性

发布与订阅

Redis提供了发布订阅功能,可以用于消息的传输
Redis的发布订阅机制包括三个部分,publisher,subscriber和Channel

发布者和订阅者都是Redis客户端,Channel则为Redis服务器端。
发布者将消息发送到某个的频道,订阅了这个频道的订阅者就能接收到这条消息。

事务

所谓事务(Transaction) ,是指作为单个逻辑工作单元执行的一系列操作

pipeline

使用pipeline,可以在客户端使用。减少和服务器的数据传输次数,一次性提交批量任务

Lua脚本

由于redis本身提供的事务太弱,如果对事务有较高的需求,可以使用lua脚本

监视器monitor

Redis客户端通过执行MONITOR命令可以将自己变为一个监视器,实时地接受并打印出服务器当前处理 的命令请求的相关信息。
此时,当其他客户端向服务器发送一条命令请求时,服务器除了会处理这条命令请求之外,还会将这条
命令请求的信息发送给所有监视器。

慢查询日志

Redis持久化机制

为什么要持久化

Redis是内存数据库,宕机后数据会消失。
Redis重启后快速恢复数据,要提供持久化机制
Redis持久化是为了快速的恢复数据而不是为了存储数据
Redis有两种持久化方式:RDB和AOF

注意:Redis持久化不保证数据的完整性。
当Redis用作DB时,DB数据要完整,所以一定要有一个完整的数据源(文件、mysql) 在系统启动时,从这个完整的数据源中将数据load到Redis中
数据量较小,不易改变,比如:字典库(xml、Table)

RDB

RDB(Redis DataBase),是redis默认的存储方式,RDB方式是通过快照( snapshotting )完成 的。
这一刻的数据 不关注过程

AOF

AOF(append only file)是Redis的另一种持久化方式。Redis默认情况下是不开启的。开启AOF持久 化后
Redis 将所有对数据库进行过写入的命令(及其参数)(RESP)记录到 AOF 文件, 以此达到记录数据 库状态的目的,
这样当Redis重启后只要按顺序回放这些命令就会恢复到原始状态了。 AOF会记录过程,RDB只管结果

混合持久化

RDB和AOF各有优缺点,Redis 4.0 开始支持 rdb 和 aof 的混合持久化。如果把混合持久化打开,aof rewrite 的时候就直接把 rdb 的内容写到 aof 文件开头。

RDB的头+AOF的身体—->appendonly.aof

AOF文件的载入与数据还原

因为AOF文件里面包含了重建数据库状态所需的所有写命令,所以服务器只要读入并重新执行一遍AOF 文件里面保存的写命令,就可以还原服务器关闭之前的数据库状态 Redis读取AOF文件并还原数据库状 态的详细步骤如下:
1、创建一个不带网络连接的伪客户端(fake client):因为Redis的命令只能在客 户端上下文中执行,而载入AOF文件时所使用的命令直接来源于AOF文件而不是网络连接,所以服 务器 使用了一个没有网络连接的伪客户端来执行AOF文件保存的写命令,伪客户端执行命令 的效果和带网络 连接的客户端执行命令的效果完全一样
2、从AOF文件中分析并读取出一条写命令
3、使用伪客户端执 行被读出的写命令 4、一直执行步骤2和步骤3,直到AOF文件中的所有写命令都被处理完毕为止 当完成 以上步骤之后,AOF文件所保存的数据库状态就会被完整地还原出来

RDB与AOF对比

1、RDB存某个时刻的数据快照,采用二进制压缩存储,AOF存操作命令,采用文本存储(混合)
2、RDB性能高、AOF性能较低
3、RDB在配置触发状态会丢失最后一次快照以后更改的所有数据,AOF设置为每秒保存一次,则最多 丢2秒的数据
4、Redis以主服务器模式运行,RDB不会保存过期键值对数据,Redis以从服务器模式运行,RDB会保 存过期键值对,当主服务器向从服务器同步时,再清空过期键值对。
AOF写入文件时,对过期的key会追加一条del命令,当执行AOF重写时,会忽略过期key和del命令。

高可用方案

“高可用性”(High Availability)通常来描述一个系统经过专门的设计,从而减少停工时间,而保持其服 务的高度可用性。
单机的Redis是无法保证高可用性的,当Redis服务器宕机后,即使在有持久化的机制下也无法保证不丢 失数据。
所以我们采用Redis多机和集群的方式来保证Redis的高可用性。 单进程+单线程 + 多机 (集群)

主从复制

Redis支持主从复制功能,可以通过执行slaveof(Redis5以后改成replicaof)或者在配置文件中设置 slaveof(Redis5以后改成replicaof)来开启复制功能。

哨兵模式

哨兵(sentinel)是Redis的高可用性(High Availability)的解决方案: 由一个或多个sentinel实例组成sentinel集群可以监视一个或多个主服务器和多个从服器。
在主从模式开启的前提下开启哨兵模式。
当主服务器进入下线状态时,sentinel可以将该主服务器下的某一从服务器升级为主服务器继续提供服 务,从而保证redis的高可用性。

集群与分区

分区是将数据分布在多个Redis实例(Redis主机)上,以至于每个实例只包含一部分数据。

Redis经典问题

缓存问题

数据并发竞争

这里的并发指的是多个redis的client同时set 同一个key引起的并发问题。 多客户端(Jedis)同时并发写一个key,一个key的值是1,本来按顺序修改为2,3,4,最后是4,但是顺序变成了4,3,2,最后变成了2。

Hot Key

当有大量的请求(几十万)访问某个Redis某个key时,由于流量集中达到网络上限,从而导致这个redis的 服务器宕机。造成缓存击穿,接下来对这个key的访问将直接访问数据库造成数据库崩溃,或者访问数 据库回填Redis再访问Redis,继续崩溃。

Big Key

大key指的是存储的值(Value)非常大,常见场景:

大key的影响:

分布式锁

底层数据结构

基本架构

Redis没有表的概念,Redis实例所对应的db以编号区分,db本身就是key的命名空间。 比如:user:1000作为key值,表示在user这个命名空间下id为1000的元素,类似于user表的id=1000的行。

RedisDB结构

Redis中存在“数据库”的概念,该结构由server.h中的redisDb定义。 当redis 服务器初始化时,会预先分配 16 个数据库, 所有数据库保存到结构 redisServer 的一个成员 redisServer.db 数组中, redisClient中存在一个名叫db的指针指向当前使用的数据库
RedisDB结构体源码:

typedef struct redisDb {  
    dict *dict;                 /* The keyspace for this DB */  
    dict *expires;              /* Timeout of keys with a timeout set */  
    dict *blocking_keys;        /* Keys with clients waiting for data (BLPOP)*/  
    dict *ready_keys;           /* Blocked keys that received a PUSH */  
    dict *watched_keys;         /* WATCHED keys for MULTI/EXEC CAS */  
    int id;                     /* Database ID 为0-15(默认Redis有16个数据库)*/  
    long long avg_ttl;          /* Average TTL, just for stats */  
    list *defrag_later;         /* List of key names to attempt to defrag one by one, gradually. */  
} redisDb;  

RedisObject结构

Value是一个包含字符串,列表,哈希,集合和有序集合等结构的对象

typedef struct redisObject {  
    unsigned type:4;  
    unsigned encoding:4;  
    unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or  
                            * LFU data (least significant 8 bits frequency  
                            * and most significant 16 bits access time). */  
    int refcount;  
    void *ptr;  
} robj;  

7种type

10种encoding

encoding 表示对象的内部编码,占 4 位。
Redis通过 encoding 属性为对象设置不同的编码
对于少的和小的数据,Redis采用小的和压缩的存储方式,体现Redis的灵活性
大大提高了 Redis 的存储量和执行效率