<返回更多

一篇文章读懂redis

2020-04-17    
加入收藏

缓存穿透

高并发下查询一个值,缓存中没有,数据库中也没有,布隆过滤器

解决方案:

缓存雪崩

缓存中大量数据同时到期,高并发下,所有请求都走向数据库

解决方案:

尽量不要把所有缓存都设置在同一时间过期, 通过加锁或者队列只允许一个线程查询数据库和写缓存, 其他线程等待.

通过加锁或者队列只允许一个线程查询数据库和写缓存,其他线程等待。

热点缓存(缓存击穿)

双重检测锁解决热点缓存问题,需要加volatile防止指令重排

高并发下,一个热点缓存到期,然后去数据库中去取,当还没有放入缓存中时,大量请求过来

解决方案:

Integer count = redis.get("key");
if (count == null) {
  synchronized {
    count = redis.get("key");
    if (count == null) {
      count = repo.getCount();
      redis.put("key", count);
    }
  }
}

 

if (redis.setnx(lockKey, requestId, NX, PX) == 1) {
}

 

缓存双写一致性

解决方案:

延时双删策略, 先更新数据库,再删缓存

public void write(String key,Object data){
  redis.delKey(key);
  db.updateData(data);
  // 可以将以下两步作为异步处理
  Thread.sleep(1000);
  redis.delKey(key);
}

Redis简介

Redis是一种用C语言开发的,高性能的,键值对key-value形式的noSql数据库

支持5种stringhashsetlist, 有序集合类型(sorted set, 简称zset)等数据类型

劣势就是存储的数据缺少结构化

应用场景:

redis常用命令

redis数据类型及常用操作

 

 

redis事务介绍(指一组命令的集合)

redis使用multiexecdiscardwatchunwatch实现事务

redis不支持事务回滚

执行multi后,Redis会将命令逐个放入队列中,然后用exce执行这个队列中的命令

而watch是在multi之前,watch某个属性,表示我这个multi块中可能要修改该属性,如果multi块中的命令在未执行前有客户端修改了该请求,那么该multi块中的命令就会执行失败。

redis持久化(指的是持久化到磁盘

redis持久化的方式有两种,RDBAOF

RDB(redis默认方式)

rdb是使用快照(snapshotting)的方式进行持久化的

触发快照的时机

redis获取所有数据库:

config get databases(默认有16个数据库,index从0开始)

select 0选择数据库

快照规则(或的关系)

save 900 1 “**15分钟内有1次修改就进行快照”**

save 300 10 “**5分钟内有10次修改就进行快照”**

save 60 10000 “**1分钟内有10000次修改就进行快照”**

dir ./ 指定快照地址(rdb文件地址)

dbfilename dump.rdb

快照过程

  1. Redis调用系统fork函数复制出一份当前进程的副本(子进程)
  2. 子进程开始将内存中的数据写入到硬盘中的临时文件
  3. 用临时文件替代旧的rdb文件(经过压缩的二进制文件)

优缺点

AOF

AOF: 每执行一条更改,Redis就会将该命令写入AOF文件. 实际上是先写入到硬盘缓存,然后通过硬盘缓存刷新机制保存到文件。

appendfsync always

appendfsync everysec(默认)

appendfsync no(由系统进行sync)

默认关闭,打开是appendonly yes

在数据量比较大的时候,频繁的写入和修改,aof文件会变得非常臃肿,所以我们可以设置重写规则:

 

RDB 和 AOF比较

RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。

AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。

 

数据库备份和灾难恢复

定时生成RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快。

Redis 支持同时开启 RDB 和 AOF,系统重启后,Redis 会优先使用 AOF 来恢复数据,这样丢失的数据会最少。

RDB 和 AOF ,我应该用哪一个

如果你非常关心你的数据,但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久。

AOF 将 Redis 执行的每一条命令追加到磁盘中,处理巨大的写入会降低 Redis 的性能,不知道你是否可以接受。

redis主从复制

原理:

分为全量同步和增量同步

redis哨兵机制

 

 

sentinel一些配置

Redis 集群

redis 集群保证了高可用

客户端连接集群

redis实现分布式锁

redis 过期策略

 

redis cluster对mget的操作

Redis cluster不支持mget操作. 最初是facebook, 2010年使用memcache作缓存, 共有3000个节点. 发现节点太多, 连接频率下降. 继续增加节点, 并没有改善, 是因为IO的成本已经超过数据传输.

所以redis cluster也因此不支持mget操作.redis引入cluster模式后, 是将数据hash到16384个slot上, 每个node负责一部分slot.

mget优化方案:

  1. n个key, 传统IO, 分别获取, 时间复杂度为O(n)
  2. n个key, 通过Redis的hash算法可以得出各个key所对应的节点, 这样时间复杂度就位O(node.size())
  3. 在B方案的基础之上并发处理

redis的redlock

Martin和Redis作者antirez之间的争辩:

martin挑了两个缺点:

1. 对于提升效率的场景, redlock太重

2. 对于正确性要求极高的场景, redlock并不能保证正确性;

问题: 在client1获取锁之后, 由于某种原因发生系统停顿, 锁过期, 然后client1执行操作; client2这时候也会拿到锁, 就会出现问题)

问题: A, B, C, D, E 5个redis节点,如果C的时间走得快, client1拿到锁(A, B, C), C节点先过期, client2又拿到了(C, D, E)这样就出问题了;

所以Redis从根本上来说是AP, 而分布式锁是要求CP的.

redis各种数据类型的数据结构

Redis的底层数据结构

redis各种数据类型使用的数据结构

用ziplist代替key-value减少80%内存占用的案例

背景: 因业务原因, 需要大量存储key-value数据, key和value都为string, 如果存储1千万条数据,占用了redis共计1.17G的内存. 当数据量变成1个亿时,实测大约占用8个G. 但是修改为key(int), value 为ziplist时, 内存占用为123M, 减少了85%.

步骤:

  1. 要将1千万个键值对, 放到N个bucket中, 但是为了防止ziplist变为hashtable, 每个bucket不能超过512个键值对, 1千万 / 512 = 19531. 将所有key hash到所有bucket中, 但由于hash函数的不确定性, 可能出现不均等分配, 可以分配25000个bucket, 或者30000个bucket.
  2. 选用hash算法, 决定将key放到哪个bucket. 这里我们采用高效而且均衡的知名算法crc32. 通过获取原有md5(key)的crc32后, 再对bucket的数量进行取余.
  3. 第2步确定了外层的key, 内部的field我们选用bkdr哈希算法. public static int BKDRHash(String str) {
    int seed = 131;
    int hash = 0;
    for (int i = 0; i < str.length; i++) {
    hash = (hash * seed) + str.charAt(i);
    }
    return (hash & 0X7FFFFFFF);
    }
  4. 测试装入1000万条数据, 内存降低了85%; 查询测试, 查100万条数据, 对比查询速度: key-value耗时:10653、10790、11318、9900、11270、11029毫秒 hash-field耗时:12042、11349、11126、11355、11168毫秒

Redis高延迟原因

redis命令执行过程

 

一篇文章读懂redis

 

 

蓝色的表示可能发生高延迟的地方

redis提供的慢查询统计功能: slowlog get {n}, 默认返回执行超过10ms(可配置)的命令.

slowlog get会返回值如下:

> slowlog get
1) (integer) 26 # 在慢日志中的序列号
2) (integer) 1450253133 # 该记录执行的系统时间
3) (integer) 43097 # 该记录执行所消耗的时间
4) "flushdb" # 执行的操作

redis高延迟原因

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>