Java最新查缺补漏!读懂这篇文,谁问你Redis知识体系你都能倒答如流(1),金九银十旗开得胜

最后

俗话说,好学者临池学书,不过网络时代,对于大多数的我们来说,我倒是觉得学习意识的觉醒很重要,这是开始学习的转折点,比如看到对自己方向发展有用的信息,先收藏一波是一波,比如如果你觉得我这篇文章ok,先点赞收藏一波。这样,等真的沉下心来学习,不至于被找资料分散了心神。慢慢来,先从点赞收藏做起,加油吧!

另外,给大家安排了一波学习面试资料:

image

image

以上就是本文的全部内容,希望对大家的面试有所帮助,祝大家早日升职加薪迎娶白富美走上人生巅峰!

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

if (incr > MAX_LIMITTIME) {
return “Failure Request”;
} else {
return “Success Request”;
}
}

// 设置Key 起始请求为1,10秒过期 -> 实际写法肯定封装过,这里就是随便一写
jedis.set(uuid, “1”);
jedis.expire(uuid, 10);
return “Success Request”;
}

String - 分布式锁 (重点)

/***

  • 核心思路:
  • 分布式服务调用时setnx,返回1证明拿到,用完了删除,返回0就证明被锁,等...
    
  • SET KEY value [EX seconds] [PX milliseconds] [NX|XX]
    
  • EX second:设置键的过期时间为second秒
    
  • PX millisecond:设置键的过期时间为millisecond毫秒
    
  • NX:只在键不存在时,才对键进行设置操作
    
  • XX:只在键已经存在时,才对键进行设置操作
    
  • 1.设置锁
  • A. 分布式业务统一Key
    
  • B. 设置Key过期时间
    
  • C. 设置随机value,利用ThreadLocal 线程私有存储随机value
    
  • 2.业务处理
  • ...
    
  • 3.解锁
  • A. 无论如何必须解锁 - finally (超时时间和finally 双保证)
    
  • B. 要对比是否是本线程上的锁,所以要对比线程私有value和存储的value是否一致(避免把别人加锁的东西删除了)
    

*/
@RequestMapping(“/redisLock”)
public String testRedisLock () {
try {
for(;😉{
RedisContextHolder.clear();
String uuid = UUID.randomUUID().toString();

String set = jedis.set(KEY, uuid, “NX”, “EX”, 1000);
RedisContextHolder.setValue(uuid);

if (!“OK”.equals(set)) {
// 进入循环-可以短时间休眠
} else {
// 获取锁成功 Do Somethings…
break;
}
}
} finally {
// 解锁 -> 保证获取数据,判断一致以及删除数据三个操作是原子的, 因此如下写法是不符合的
/if (RedisContextHolder.getValue() != null && jedis.get(KEY) != null && RedisContextHolder.getValue().equals(jedis.get(KEY))) {
jedis.del(KEY);
}
/

// 正确姿势 -> 使用Lua脚本,保证原子性
String luaScript = “if redis.call(‘get’, KEYS[1]) == ARGV[1] then return redis.call(‘del’,KEYS[1]) else return 0 end”;
Object eval = jedis.eval(luaScript, Collections.singletonList(KEY), Collections.singletonList(RedisContextHolder.getValue()));
}
return “锁创建成功-业务处理成功”;
}

String - 分布式Session(重点)

// 1.首先明白为什么需要分布式session -> nginx负载均衡 分发到不同的Tomcat,即使利用IP分发,可以利用request获取session,但是其中一个挂了,怎么办?? 所以需要分布式session

注意理解其中的区别 A服务-用户校验服务 B服务-业务层

情况A:
A,B 服务单机部署:
cookie:登录成功后,存储信息到cookie,A服务自身通过request设置session,获取session,B服务通过唯一key或者userid 查询数据库获取用户信息

cookie+redis:登录成功后,存储信息到cookie,A服务自身通过request设置session,获取session,B服务通过唯一key或者userid 查询redis获取用户信息

情况B:
A服务多节点部署,B服务多节点部署
B服务获取用户信息的方式其实是不重要的,必然要查,要么从数据库,要么从cookie

A服务:登录成功后,存储唯一key到cookie, 与此同时,A服务需要把session(KEY-UserInfo)同步到redis中,不能存在单纯的request(否则nginx分发到另一个服务器就完犊子了)

官方实现:
spring-session-data-redis
有一个内置拦截器,拦截request,session通过redis交互,普通使用代码依然是request.getSession… 但是实际上这个session的值已经被该组件拦截,通过redis进行同步了

List 简单队列-栈

// 说白了利用redis - list数据结构 支持从左从右push,从左从右pop
@Component
public class RedisStack {

@Resource
Jedis jedis;

private final static String KEY = “Stack”;

/** push **/
public void push (String value) {
jedis.lpush(KEY, value);
}

/** pop **/
public String pop () {
return jedis.lpop(KEY);
}
}

@Component
public class RedisQueue {

@Resource
JedisPool jedisPool;

private final static String KEY = “Queue”;

/** push **/
public void push (String value) {
Jedis jedis = jedisPool.getResource();
jedis.lpush(KEY, value);
}

/** pop **/
public String pop () {
Jedis jedis = jedisPool.getResource();
return jedis.rpop(KEY);
}
}

List 社交类APP - 好友列表

根据时间显示好友,多个好友列表,求交集,并集 显示共同好友等等…
疑问:难道大厂真的用redis存这些数据吗???多大的量啊… 我个人认为实际是数据库存用户id,然后用算法去处理,更省空间

Set 抽奖 | 好友关系(合,并,交集)

// 插入key 及用户id
sadd cat:1 001 002 003 004 005 006

// 返回抽奖参与人数
scard cat:1

// 随机抽取一个
srandmember cat:1

// 随机抽取一人,并移除
spop cat:1

Zset 排行榜

根据分数实现有序列表
微博热搜:每点击一次 分数+1 即可

— 不用数据库目的是因为避免order by 进行全表扫描

常见面试题

Q1:为什么Redis能这么快

1.Redis完全基于内存,绝大部分请求是纯粹的内存操作,执行效率高。
2.Redis使用单进程单线程模型的(K,V)数据库,将数据存储在内存中,存取均不会受到硬盘IO的限制,因此其执行速度极快,另外单线程也能处理高并发请求,还可以避免频繁上下文切换和锁的竞争,同时由于单线程操作,也可以避免各种锁的使用,进一步提高效率
3.数据结构简单,对数据操作也简单,Redis不使用表,不会强制用户对各个关系进行关联,不会有复杂的关系限制,其存储结构就是键值对,类似于HashMap,HashMap最大的优点就是存取的时间复杂度为O(1)
5.C语言编写,效率更高
6.Redis使用多路I/O复用模型,为非阻塞IO
7.有专门设计的RESP协议

针对第四点进行说明 ->

常见的IO模型有四种:

  • 同步阻塞IO(Blocking IO):即传统的IO模型。

  • 同步非阻塞IO(Non-blocking IO):默认创建的socket都是阻塞的,非阻塞IO要求socket被设置为NONBLOCK。注意这里所说的NIO并非Java的NIO(New IO)库。

  • IO多路复用(IO Multiplexing):即经典的Reactor设计模式,有时也称为异步阻塞IO,Java中的Selector和Linux中的epoll都是这种模型。

  • 异步IO(Asynchronous IO):即经典的Proactor设计模式,也称为异步非阻塞IO

同步异步,阻塞非阻塞的概念:

假设Redis采用同步阻塞IO:

Redis主程序(服务端 单线程)-> 多个客户端连接(真实情况是如开发人员连接redis,程序 redispool连接redis),这每一个都对应着一个客户端,假设为100个客户端,其中一个进行交互时候,如果采用同步阻塞式,那么剩下的99个都需要原地等待,这势必是不科学的。

IO多路复用

Redis 采用 I/O 多路复用模型

I/O 多路复用模型中,最重要的函数调用就是 select,该方法的能够同时监控多个文件描述符的可读可写情况,当其中的某些文件描述符可读或者可写时,select 方法就会返回可读以及可写的文件描述符个数

注:redis默认使用的是更加优化的算法:epoll

selectpollepoll
操作方式遍历遍历回调
底层实现数组链表哈希表
IO效率每次调用都进行线性遍历,时间复杂度为O(n)每次调用都进行线性遍历,时间复杂度为O(n)事件通知方式,每当fd就绪,系统注册的回调函数就会被调用,将就绪fd放到readyList里面,时间复杂度O(1)
最大连接数1024(x86)或2048(x64)无上限无上限

所以我们可以说Redis是这样的:服务端单线程毫无疑问,多客户端连接时候,如果客户端没有发起任何动作,则服务端会把其视为不活跃的IO流,将其挂起,当有真正的动作时,会通过回调的方式执行相应的事件

Q2:从海量Key里查询出某一个固定前缀的Key

A. 笨办法:KEYS [pattern] 注意key很多的话,这样做肯定会出问题,造成redis崩溃

B. SCAN cursor [MATCH pattern][COUNT count] 游标方式查找

Q3:如何通过Redis实现分布式锁

见上文

Q4:如何实现异步队列

上文说到利用 redis-list 实现队列
假设场景:A服务生产数据 - B服务消费数据,即可利用此种模型构造-生产消费者模型

1. 使用Redis中的List作为队列
2.使用BLPOP key [key…] timeout -> LPOP key [key …] timeout:阻塞直到队列有消息或者超时
(方案二:解决方案一中,拿数据的时,生产者尚未生产的情况)

3.pub/sub:主题订阅者模式
基于reds的终极方案,上文有介绍,基于发布/订阅模式
缺点:消息的发布是无状态的,无法保证可达。对于发布者来说,消息是“即发即失”的,此时如果某个消费者在生产者发布消息时下线,重新上线之后,是无法接收该消息的,要解决该问题需要使用专业的消息队列

Q5:Redis支持的数据类型?

见上文

Q6:什么是Redis持久化?Redis有哪几种持久化方式?优缺点是什么?

持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。

Redis 提供了两种持久化方式:RDB(默认) 和AOF

RDB:

rdb是Redis DataBase缩写

功能核心函数rdbSave(生成RDB文件)和rdbLoad(从文件加载内存)两个函数

RDB: 把当前进程数据生成快照文件保存到硬盘的过程。分为手动触发和自动触发

手动触发 -> save (不推荐,阻塞严重) bgsave -> (save的优化版,微秒级阻塞)

shutdowm 关闭服务时,如果没有配置AOF,则会使用bgsave持久化数据

bgsave - 工作原理

会从当前父进程fork一个子进程,然后生成rdb文件

缺点:频率低,无法做到实时持久化

AOF:

Aof是Append-only file缩写,AOF文件存储的也是RESP协议

每当执行服务器(定时)任务或者函数时flushAppendOnlyFile 函数都会被调用, 这个函数执行以下两个工作

aof写入保存:

WRITE:根据条件,将 aof_buf 中的缓存写入到 AOF 文件

SAVE:根据条件,调用 fsync 或 fdatasync 函数,将 AOF 文件保存到磁盘中。

存储结构:

内容是redis通讯协议(RESP )格式的命令文本存储

原理:

相当于存储了redis的执行命令(类似mysql的sql语句日志),数据的完整性和一致性更高

比较

1、aof文件比rdb更新频率高

2、aof比rdb更安全

3、rdb性能更好

PS:正确停止redis服务 应该基于连接命令 加再上 shutdown -> 否则数据持久化会出现问题

Q7:redis通讯协议(RESP)

Redis 即 REmote Dictionary Server (远程字典服务);

而Redis的协议规范是 Redis Serialization Protocol (Redis序列化协议)

RESP 是redis客户端和服务端之前使用的一种通讯协议;

RESP 的特点:实现简单、快速解析、可读性好

协议如下:

客户端以规定格式的形式发送命令给服务器

set key value 协议翻译如下:

  • 3 -> 表示以下有几组命令

$ 3 -> 表示命令长度是3
SET

$6 -> 表示长度是6
keykey

$5 -> 表示长度是5
value

完整即:

  • 3
    $ 3
    SET
    $6
    keykey
    $5
    value

服务器在执行最后一条命令后,返回结果,返回格式如下:

For Simple Strings the first byte of the reply is “+” 回复

For Errors the first byte of the reply is “-” 错误

For Integers the first byte of the reply is “:” 整数

For Bulk Strings the first byte of the reply is “$” 字符串

For Arrays the first byte of the reply is “*” 数组

// 伪造6379 redis-服务端,监听 jedis发送的协议内容
public class SocketApp {

/***

  • 监听 6379 传输的数据
  • JVM端口需要进行设置
    */
    public static void main(String[] args) {
    try {
    ServerSocket serverSocket = new ServerSocket(6379);
    Socket redis = serverSocket.accept();
    byte[] result = new byte[2048];
    redis.getInputStream().read(result);
    System.out.println(new String(result));
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }

// jedis连接-发送命令
public class App {
public static void main(String[] args){
Jedis jedis = new Jedis(“127.0.0.1”);
jedis.set(“key”, “This is value.”);
jedis.close();
}
}

// 监听命令内容如下:
*3
$3
SET
$3
key
$14

Q8:redis架构有哪些

单节点
主从复制

Master-slave 主从赋值,此种结构可以考虑关闭master的持久化,只让从数据库进行持久化,另外可以通过读写分离,缓解主服务器压力

哨兵

Redis sentinel 是一个分布式系统中监控 redis 主从服务器,并在主服务器下线时自动进行故障转移。其中三个特性:

监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。

提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。

自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作。

特点:
1、保证高可用
2、监控各个节点
3、自动故障迁移

缺点:主从模式,切换需要时间丢数据
没有解决 master 写的压力

集群

从redis 3.0之后版本支持redis-cluster集群,Redis-Cluster采用无中心结构,每个节点保存数据和整个集群状态,每个节点都和其他所有节点连接。

特点:

1、无中心架构(不存在哪个节点影响性能瓶颈),少了 proxy 层。

2、数据按照 slot 存储分布在多个节点,节点间数据共享,可动态调整数据分布。

3、可扩展性,可线性扩展到 1000 个节点,节点可动态添加或删除。

4、高可用性,部分节点不可用时,集群仍可用。通过增加 Slave 做备份数据副本

5、实现故障自动 failover,节点之间通过 gossip 协议交换状态信息,用投票机制完成 Slave到 Master 的角色提升。

缺点:

1、资源隔离性较差,容易出现相互影响的情况。

2、数据通过异步复制,不保证数据的强一致性

Q9:Redis集群-如何从海量数据里快速找到所需?

  • 分片

按照某种规则去划分数据,分散存储在多个节点上。通过将数据分到多个Redis服务器上,来减轻单个Redis服务器的压力。

  • 一致性Hash算法

既然要将数据进行分片,那么通常的做法就是获取节点的Hash值,然后根据节点数求模,但这样的方法有明显的弊端,当Redis节点数需要动态增加或减少的时候,会造成大量的Key无法被命中。所以Redis中引入了一致性Hash算法。该算法对2^32 取模,将Hash值空间组成虚拟的圆环,整个圆环按顺时针方向组织,每个节点依次为0、1、2…2^32-1,之后将每个服务器进行Hash运算,确定服务器在这个Hash环上的地址,确定了服务器地址后,对数据使用同样的Hash算法,将数据定位到特定的Redis服务器上。如果定位到的地方没有Redis服务器实例,则继续顺时针寻找,找到的第一台服务器即该数据最终的服务器位置。

Hash环的数据倾斜问题

Hash环在服务器节点很少的时候,容易遇到服务器节点不均匀的问题,这会造成数据倾斜,数据倾斜指的是被缓存的对象大部分集中在Redis集群的其中一台或几台服务器上。


如上图,一致性Hash算法运算后的数据大部分被存放在A节点上,而B节点只存放了少量的数据,久而久之A节点将被撑爆。 引入虚拟节点

例如上图:将NodeA和NodeB两个节点分为Node A#1-A#3 NodeB#1-B#3。

Q10:什么是缓存穿透?如何避免?什么是缓存雪崩?如何避免?什么是缓存击穿?如何避免?

缓存穿透

一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如DB)。一些恶意的请求会故意查询不存在的key,请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透。

如何避免?

1:对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert了之后清理缓存。

2:对一定不存在的key进行过滤。可以把所有的可能存在的key放到一个大的Bitmap中,查询时通过该bitmap过滤。

3:由于请求参数是不合法的(每次都请求不存在的参数),于是我们可以使用布隆过滤器(Bloomfilter)或压缩filter提前进行拦截,不合法就不让这个请求进入到数据库层

缓存雪崩

当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,会给后端系统带来很大压力。导致系统崩溃。

如何避免?

1:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。

2:做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期

3:不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

4:启用限流策略,尽量避免数据库被干掉

缓存击穿

概念 一个存在的key,在缓存过期的一刻,同时有大量的请求,这些请求都会击穿到DB,造成瞬时DB请求量大、压力骤增。

解决方案 A. 在访问key之前,采用SETNX(set if not exists)来设置另一个短期key来锁住当前key的访问,访问结束再删除该短期key

B. 服务层处理 - 方法加锁 + 双重校验:

// 锁-实例
private Lock lock = new ReentrantLock();

public String getProductImgUrlById(String id){
// 获取缓存
String product = jedisClient.get(PRODUCT_KEY + id);
if (null == product) {
// 如果没有获取锁等待3秒,SECONDS代表:秒
try {
if (lock.tryLock(3, TimeUnit.SECONDS)) {
try {
// 获取锁后再查一次,查到了直接返回结果
product = jedisClient.get(PRODUCT_KEY + id);
if (null == product) {
// …
}
return product;
} catch (Exception e) {
product = jedisClient.get(PRODUCT_KEY + id);
} finally {
// 释放锁(成功、失败都必须释放,如果是lock.tryLock()方法会一直阻塞在这)
lock.unlock();
}
} else {
product = jedisClient.get(PRODUCT_KEY + id);
}
} catch (InterruptedException e) {
product = jedisClient.get(PRODUCT_KEY + id);
}
}
return product;
}

解释基础解决方案
缓存穿透访问一个不存在的key,缓存不起作用,请求会穿透到DB,流量大时DB会挂掉1.采用布隆过滤器,使用一个足够大的bitmap,用于存储可能访问的key,不存在的key直接被过滤; 2.访问key未在DB查询到值,也将空值写进缓存,但可以设置较短过期时间
缓存雪崩大量的key设置了相同的过期时间,导致在缓存在同一时刻全部失效,造成瞬时DB请求量大、压力骤增,引起雪崩可以给缓存设置过期时间时加上一个随机值时间,使得每个key的过期时间分布开来,不会集中在同一时刻失效
缓存击穿一个存在的key,在缓存过期的一刻,同时有大量的请求,这些请求都会击穿到DB,造成瞬时DB请求量大、压力骤增在访问key之前,采用SETNX(set if not exists)来设置另一个短期key来锁住当前key的访问,访问结束再删除该短期key

Q11:缓存与数据库双写一致

如果仅仅是读数据,没有此类问题

如果是新增数据,也没有此类问题

当数据需要更新时,如何保证缓存与数据库的双写一致性?

三种更新策略:

  1. 先更新数据库,再更新缓存 ->
  2. 先删除缓存,再更新数据库
  3. 先更新数据库,再删除缓存

方案一:并发的时候,执行顺序无法保证,可能A先更新数据库,但B后更新数据库但先更新缓存

加锁的话,确实可以避免,但这样吞吐量会下降,可以根据业务场景考虑

方案二:该方案会导致不一致的原因是。同时有一个请求A进行更新操作,另一个请求B进行查询操作。那么会出现如下情形: (1)请求A进行写操作,删除缓存 (2)请求B查询发现缓存不存在 (3)请求B去数据库查询得到旧值 (4)请求B将旧值写入缓存 (5)请求A将新值写入数据库

因此采用:采用延时双删策略 即进入逻辑就删除Key,执行完操作,延时再删除key

方案三:更新数据库 - 删除缓存 可能出现问题的场景:

(1)缓存刚好失效 (2)请求A查询数据库,得一个旧值 (3)请求B将新值写入数据库 (4)请求B删除缓存 (5)请求A将查到的旧值写入缓存

先天条件要求:请求第二步的读取操作耗时要大于更新操作,条件较为苛刻

但如果真的发生怎么处理?

A. 给键设置合理的过期时间

B. 异步延时删除key

Q12:何保证Redis中的数据都是热点数据

A. 可以通过手工或者主动方式,去加载热点数据

B. Redis有其自己的数据淘汰策略:

redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略(回收策略)。redis 提供 6种数据淘汰策略:

  1. volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
  2. volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
  3. volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
  4. allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
  5. allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
  6. no-enviction(驱逐):禁止驱逐数据

Q13:Redis的并发竞争问题如何解决?

即多线程同时操作统一Key的解决办法:

Redis为单进程单线程模式,采用队列模式将并发访问变为串行访问。Redis本身没有锁的概念,Redis对于多个客户端连接并不存在竞争,但是在Jedis客户端对Redis进行并发访问时会发生连接超时、数据转换错误、阻塞、客户端关闭连接等问题,这些问题均是由于客户端连接混乱造成

对此有多种解决方法:
A:条件允许的情况下,请使用redis自带的incr命令,decr命令
B:乐观锁方式
watch price
get price $price
$price = $price + 10
multi
set price $price
exec

C:针对客户端,操作同一个key的时候,进行加锁处理
D:场景允许的话,使用setnx 实现

Q14:Redis回收进程如何工作的? Redis回收使用的是什么算法?

Q12 中提到过,当所需内存超过配置的最大内存时,redis会启用数据淘汰规则

默认规则是:# maxmemory-policy noeviction

即只允许读,无法继续添加key

因此常需要配置淘汰策略,比如LRU算法

LRU算法最为精典的实现,就是HashMap+Double LinkedList,时间复杂度为O(1)

Q15:Redis大批量增加数据

使用管道模式,运行的命令如下所示:

cat data.txt | redis-cli --pipe

data.txt文本:

SET Key0 Value0
SET Key1 Value1

SET KeyN ValueN

或者是 RESP协议内容 - 注意文件编码!!!

*8
$5
HMSET
$8
person:1
$2
id
$1
1

这将产生类似于这样的输出:

All data transferred. Waiting for the last reply…
Last reply received from server.
errors: 0, replies: 1000000

redis-cli实用程序还将确保只将从Redis实例收到的错误重定向到标准输出

演示:

cat redis_commands.txt | redis-cli -h 192.168.127.130 -p 6379 [-a “password”] -n 0 --pipe

All data transferred.Waiting for the last reply…
Last reply received from server.
errors:0,replies:10000000

mysql数据快速导入到redis 实战:

1.准备一个table

create database if not exists test;
use test;
CREATE TABLE person (
id int(10) unsigned NOT NULL AUTO_INCREMENT,
name varchar(200) NOT NULL,
age varchar(200) NOT NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

2.插入七八万条数据

3.SQL查询,将其转化为 RESP协议命令 Linux 版本: -> 不要在windows环境试,没啥意义

SELECT CONCAT(
“*8\r\n”,
KaTeX parse error: Undefined control sequence: \n at position 24: …(redis_cmd),'\r\̲n̲',redis_cmd,'\r…’,LENGTH(redis_key),‘\r\n’,redis_key,‘\r\n’,
KaTeX parse error: Undefined control sequence: \n at position 20: …NGTH(hkey1),'\r\̲n̲',hkey1,'\r\n',…’,LENGTH(hval1),‘\r\n’,hval1,‘\r\n’,
KaTeX parse error: Undefined control sequence: \n at position 20: …NGTH(hkey2),'\r\̲n̲',hkey2,'\r\n',…’,LENGTH(hval2),‘\r\n’,hval2,‘\r\n’,
KaTeX parse error: Undefined control sequence: \n at position 20: …NGTH(hkey3),'\r\̲n̲',hkey3,'\r\n',…’,LENGTH(hval3),‘\r\n’,hval3,‘\r’
)FROM(
SELECT ‘HMSET’ AS redis_cmd,
concat_ws(‘:’,‘person’, id) AS redis_key,
‘id’ AS hkey1, id AS hval1,
‘name’ AS hkey2, name AS hval2,
‘age’ AS hkey3, age AS hval3
From person
)AS t

4.如果用的就是线上数据库+线上Linux -> 把sql存到 order.sql,进行执行

mysql -uroot -p123456 test --default-character-set=utf8 --skip-column-names --raw < order.sql
|
redis-cli -h 127.0.0.1 -p 6379 -a 123456 --pipe

5.本地数据库+线上redis

利用Navicat导出数据 -> data.txt,清理格式(导出来的数据里面各种 " 符号),全局替换即可
cat data.txt | redis-cli -h 127.0.0.1 -p 6379 -a 123456 --pipe

81921条数据 一瞬间导入完成

注意事项: RESP协议要求,不要有莫名其妙的字符,注意文件类型是Unix编码类型
复制代码

Q16:延申:布隆过滤器

数据结构及算法篇 / 布隆过滤器

Redis 实现

redis 4.X 以上 提供 布隆过滤器插件

centos中安装redis插件bloom-filter:blog.csdn.net/u013030276/…

语法:[bf.add key options]

语法:[bf.exists key options]

注意: redis 布隆过滤器提供的是 最大内存512M,2亿数据,万分之一的误差率

Q17:Lua脚本相关

使用Lua脚本的好处:

  • 减少网络开销。可以将多个请求通过脚本的形式一次发送,减少网络时延
  • 原子操作,redis会将整个脚本作为一个整体执行,中间不会被其他命令插入。因此在编写脚本的过程中无需担心会出现竞态条件,无需使用事务
  • 复用,客户端发送的脚本会永久存在redis中,这样,其他客户端可以复用这一脚本而不需要使用代码完成相同的逻辑

@RequestMapping(“/testLua”)
public String testLua () {

String key = “mylock”;
String value = “xxxxxxxxxxxxxxx”;

// if redis.call(‘get’, KEYS[1]) == ARGV[1]
// then
// return redis.call(‘del’, KEYS[1])
// else
// return 0
// end

// lua脚本,用来释放分布式锁 - 如果使用的较多,可以封装到文件中, 再进行调用
String luaScript = “if redis.call(‘get’, KEYS[1]) == ARGV[1] then return redis.call(‘del’,KEYS[1]) else return 0 end”;
Object eval = jedis.eval(luaScript, Collections.singletonList(key), Collections.singletonList(value));
return eval.toString();
}

Q18:性能相关 - Redis慢查询分析

redis 命令会放在redis内置队列中,然后主线程一个个执行,因此 其中一个 命令执行时间过长,会造成成批量的阻塞

命令:slowlog get 获取慢查询记录 slowlog len 获取慢查询记录量 (慢查询队列是先进先出的,因此新的值在满载的时候,旧的会出去)

Redis 慢查询 -> 执行阶段耗时过长

conf文件设置: slowlog-low-slower-than 10000 -> 10000微秒,10毫秒 (默认) 0 -> 记录所有命令 -1 -> 不记录命令 slow-max-len 存放的最大条数

总结

面试前的“练手”还是很重要的,所以开始面试之前一定要准备好啊,不然也是耽搁面试官和自己的时间。

我自己是刷了不少面试题的,所以在面试过程中才能够做到心中有数,基本上会清楚面试过程中会问到哪些知识点,高频题又有哪些,所以刷题是面试前期准备过程中非常重要的一点。

面试题及解析总结

三年Java开发,刚从美团、京东、阿里面试归来,分享个人面经

大厂面试场景

三年Java开发,刚从美团、京东、阿里面试归来,分享个人面经

知识点总结

三年Java开发,刚从美团、京东、阿里面试归来,分享个人面经

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

Q18:性能相关 - Redis慢查询分析

redis 命令会放在redis内置队列中,然后主线程一个个执行,因此 其中一个 命令执行时间过长,会造成成批量的阻塞

命令:slowlog get 获取慢查询记录 slowlog len 获取慢查询记录量 (慢查询队列是先进先出的,因此新的值在满载的时候,旧的会出去)

Redis 慢查询 -> 执行阶段耗时过长

conf文件设置: slowlog-low-slower-than 10000 -> 10000微秒,10毫秒 (默认) 0 -> 记录所有命令 -1 -> 不记录命令 slow-max-len 存放的最大条数

总结

面试前的“练手”还是很重要的,所以开始面试之前一定要准备好啊,不然也是耽搁面试官和自己的时间。

我自己是刷了不少面试题的,所以在面试过程中才能够做到心中有数,基本上会清楚面试过程中会问到哪些知识点,高频题又有哪些,所以刷题是面试前期准备过程中非常重要的一点。

面试题及解析总结

[外链图片转存中…(img-VWkXAa2v-1715436946252)]

大厂面试场景

[外链图片转存中…(img-rnrGyk6y-1715436946252)]

知识点总结

[外链图片转存中…(img-JDT28Jlb-1715436946253)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 27
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值