Redis面试合集

概念

Redis是一种key-value型非关系数据库。

特点:

1、速度快,存在于内存中,类似于HashMap,HashMap的操作和查找的时间复杂度都是O(1)

2、支持丰富的数据类型,包括字符串、哈希、列表、集合、有序集合五种数据类型。

3、支持事务,操作都是原子性的,要么都执行要么都不执行。

4、memcached所有值都是简单的字符串,Redis可以持久化数据(RDB、AOF)。

过期策略

定时过期(定时器)、惰性过期(访问时判断)、定期过期(每隔一段时间扫描)

如何保证Redis都是热点数据?(数据回收)

最近最少使用/随机/最近最少使用/更早过期时间的

持久化(RDB和AOF)

RDB:一定时间将内存数据以快照形式保存到硬盘dump.rdb。通过save参数配置快照周期。

保存成一个文件,更安全。数据量大时,启动效率更高。子进程单独进行持久化保证Redis高性能。持久化过程中发生事故数据容易丢失。

AOF:将Redis执行命令写到单独日志文件中。

数据安全。通过append追加到日志,即使服务器宕机也可通过redis-check-aof工具解决数据一致问题。AOF文件更大,恢复更慢,启动效率低。

保证Redis和MYSQL数据一致

缓存单删: 更新DB前先删除缓存,再更新库,查询缓存无数据则直接访问DB。
延时双删: 为了解决缓存单删,在高并发读情况下数据不一致问题。操作数据前,先删除缓存,接着操作DB,然后延迟一段时间,再删除缓存。

定时+增量更新: 主要是利用库里行数据的更新时间字段+定时增量查询。具体为:每次更新库里的行数据,记录当前行的更新时间;然后把更新时间做为一个索引字段(加快查询速度)

定时任务: 每隔几秒,比如5秒(自定义),把库里最近5秒钟的数据查询出来,写入缓存并记录查询结束时间。查询过程和放入缓存都是单线程不存在并发问题。每次同步成功,下次执行把结束时间作为开始时间,当前时间作为结束时间实现增量查询。

优点:架构简单、逻辑和业务解耦、依赖少,最多加个分布式定时任务或者Redis分布式锁。

监听binlog+MQ: 监听MYSQL binlog把数据库的更新插入删除操作通过MQ同步给下游消费者,下游拿到日志和业务数据再放入缓存。

优点:缓存和业务解耦,减少业务代码的侵入性。

缺点:技术和架构复杂,中间件的运维,引入MQ后带来的问题,比如数据乱序:同一条数据先发后至,后发先至到达消费者,通过redis lua+数据的时间戳比较方案,解决并发问题和数据乱序问题

redis缓存三兄弟问题

PHP+Redis分布式锁

Redis分布式锁是通过线程锁来实现,同时只允许一个线程执行,其他线程进入等待状态。

优点:降低MySQL压力,比队列的并发量高。缺点:线程需要排队等待,并发量也不是特别高。

php 复制代码
$key = "test:lock:".$id;$uuid = Uuid::uuid1()->getHex();try {
    $ret = Redis::set($key, $uuid, 'EX', 10, 'NX');
    if (!$ret) {
        usleep(10);
        return $this->test($id);
    }
    $stock = Skill::query()->where('id', $id)->value('stock');
    if ($stock > 0) {
        Skill::query()->where('id', $id)->decrement('stock');
        $msg = '抢购成功';
    } else {
        $msg = '库存不足,抢购失败';
    }
    if (Redis::get($key) == $uuid) {
        Redis::del($key);
    }
    return $msg;} catch (\Exception $exception) {
    return '抢购失败';}

PHP+Redis乐观锁

Redis的乐观锁就是借助Redis事务和watch监控,采用事务打断的方式实现

优点:并没有锁定任何资源,多线程可以并行。缺点:这是PHP层面的控制,而PHP是有性能瓶颈的。

php 复制代码
$key = 'stock:'.$id;Redis::watch($key);$stock = Redis::get($key);
if (is_null($stock)) {
 return '没有商品';
}
if ($stock == 0) {
 return '库存不足';
}
Redis::multi();Redis::decr($key);
$res = Redis::exec();
if ($res) {
 Skill::query()->where('id', $id)->decrement('stock');
 return '抢购成功';
} else {
 return '抢购失败';}

Nginx结合Lua做桶限流+Redis乐观锁(最优方案)

这种方案是最优方案,直接绕过应用层,在接入层实现限流和防止超卖的操作,只消耗很少的服务器性能,但是可抗并发量级特别大,性能上远超上述几种方案。

逻辑分析:先使用 Nginx+Lua 漏桶算法过滤掉大部分请求,再使用Lua连接Redis,使用Redis乐观锁的方式控制库存。假设只有10个秒杀商品,那这里只保留10个请求进入应用层(PHP和MysqL),应用层不需要进行其他操作,直接操作数据库就可以。

项目应用

1、ERP的商品报表模块,API接口处理好数据,序列化成字符串后给定过期时间存储到Redis中。

2、序列号生成器,我们又很多单号,像订单、生产、调拨,但需求层面要求我们的订单尾号按照顺序来,我们生成器中会根据类别将对应序列号hash进行自增。

3、订单提取模块,

持续更新,未完待续~

相关推荐
wilsonzane7 分钟前
Mongodb集群中的分布式读写
数据库·分布式·mongodb
关中雪16 分钟前
【应届应知应会】SQL常用知识点50道
数据库·mysql·nosql·秋招·校招·春招
zxrhhm26 分钟前
MySQL中使用PROFILING来查看SQL执行流程
数据库·mysql
醇氧27 分钟前
【postgresql】表操作
数据库·sql·postgresql
PGCCC27 分钟前
使用预加载库优化 PostgreSQL 函数#postgresql认证
数据库·postgresql
知其然亦知其所以然35 分钟前
深入Kafka:如何保证数据一致性与可靠性?
后端·面试·kafka
baozongwi1 小时前
CTF常用sql注入(一)联合注入和宽字节
数据库·sql·web安全
freesharer1 小时前
Zabbix 配置WEB监控
前端·数据库·zabbix
杰哥在此1 小时前
Java面试题:解释跨站脚本攻击(XSS)的原理,并讨论如何防范
java·开发语言·面试·编程·xss
尾巴尖上的阳光1 小时前
ETCD概述--使用/特性/架构/原理
数据库·架构·etcd