面试题整理 3
总结了某公司面试遇到的值得整理记录的面试题,比较侧重于Redis方面。
目录
Redis持久化配置
RDB
AOF
Redis rdb日志文件路径编辑
命令行参数设置
Redis事务
Redis事务介绍
Redis事务阶段
watch监听
Mysql隔离级别
1.READ UNCOMMITTED
2.READ COMMITTED
3.REPEATABLE READ
4.SERIALIZABLE
App登录验签 踢出并保持30分钟不能登录实现方案
Redis磁盘空间满清理冷数据
删除过期的键:
使用LFU算法删除冷门键:
使用volatile-lru或volatile-lfu策略控制过期键的删除:
定期进行数据持久化:
Redis 确定哪些是热key
缓存雪崩
产生原因
影响
防范策略
设置不同的过期时间:
使用热备份:
数据预热:
使用限流和熔断机制:
缓存击穿
产生原因
影响
防范策略
设置热点数据永不过期:
使用互斥锁:
缓存穿透
产生原因
影响
防范策略
缓存空值:
使用布隆过滤器:
来源分组 只要十个分组
一条sql计算两种条件的数量
总结
Redis持久化配置
Redis支持两种持久化方式:RDB(Redis DataBase)和AOF(Append Only File)。
RDB
根据配置定时将内存中的数据快照保存到磁盘的一个压缩二进制文件中。
Redis的redis.conf配置文件中相关的RDB持久化配置参数:
# 是否开启RDB持久化
save <seconds> <changes>
# 例如,如下配置表示900秒内至少1个键被修改则触发保存
save 900 1
# RDB文件名
dbfilename dump.rdb
# RDB文件和AOF文件的保存位置
dir /path/to/your/redis/directory
# 是否在导出.rdb文件时使用LZF压缩
rdbcompression yes
AOF
每个写命令都通过append操作保存到文件中。
Redis的redis.conf配置文件中相关的AOF持久化配置参数:
# 是否开启AOF持久化
appendonly yes
# AOF文件名
appendfilename "appendonly.aof"
# AOF文件的保存位置
dir /path/to/your/redis/directory
# AOF文件的更新频率
appendfsync everysec
# 是否在AOF重写期间对新写操作进行同步
no-appendfsync-on-rewrite no
# AOF文件大小超过此值时触发重写
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
注意:
开启AOF时,appendfsync的设置对性能影响较大,everysec为推荐配置,即每秒同步一次。
Redis rdb日志文件路径编辑
在redis的配置未见redis.conf中可以找到以下配置项:
# 默认的RDB名称dump.rdb
dbfilename dump.rdb
可以将dbfilename配置为自定义的RDB名称,例如:
dbfilename mydata.rdb
命令行参数设置
在启动Redis的命令行中,可以使用参数--dbfilename来设置RDB名称,例如:
redis-server --dbfilename mydata.rdb
Redis事务
事务是指一个完整的动作,要么全部执行,要么什么也没有做。Redis 事务不是严格意义上的事务,只是用于帮助用户在一个步骤中执行多个命令。单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。
Redis事务介绍
Redis 事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。
redis事务的主要作用就是串联多个命令防止别的命令插队。
Redis 在形式上看起来也差不多,MULTI、EXEC、DISCARD
这三个指令构成了 redis 事务处理的基础。
MULTI:用来组装一个事务,从输入Multi命令开始,输入的命令都会依次进入命令队列中,但不会执行,直到输入Exec后,redis会将之前的命令依次执行。
EXEC:用来执行一个事务。
DISCARD:用来取消一个事务。
Redis事务阶段
redis事务分2个阶段:组队阶段、执行阶段;
组队阶段:只是将所有命令加入命令队列;
执行阶段:依次执行队列中的命令,在执行这些命令的过程中,不会被其他客户端发送的请求命令插队或者打断。
所有的指令在 exec 之前不执行,而是缓存在服务器的一个事务队列中,服务器一旦收到 exec 指令,才开执行整个事务队列,执行完毕后一次性返回所有指令的运行结果。因为 Redis 的单线程特性,不用担心自己在执行队列的时候被其它指令打搅,可以保证他们能得到的有顺序的执行。
watch监听
WATCH:在执行multi之前,先执行watch key1 [key2 …],可以监视一个或者多个key,若在事务的exec命令之前这些key对应的值被其他命令所改动了,那么事务中所有命令都将被打断,即事务所有操作将被取消执行。
unwatch:取消 WATCH 命令对所有 key 的监视。如果在执行 WATCH 命令之后, EXEC 命令或 DISCARD 命令先被执行了的话,那么就不需要再执行UNWATCH 了。
Mysql隔离级别
在 MySQL中事务的隔离级别有以下 4 种:
读未提交(READ UNCOMMITTED)
读已提交(READ COMMITTED)
可重复读(REPEATABLE READ)
序列化(SERIALIZABLE)
MySQL 默认的事务隔离级别是可重复读,这4种隔离级别的说明如下。
1.READ UNCOMMITTED
未提交读,该隔离级别的事务可以看到其他事务中未提交的数据。该隔离级别因为可以读取到其他事务中未提交的数据,而未提交的数据可能会发生回滚,因此把该级别读取到的数据称之为脏数据,把这个问题称之为脏读。
2.READ COMMITTED
提交读,该隔离级别的事务能读取到已经提交事务的数据,因此它不会有脏读问题。但由于在事务的执行中可以读取到其他事务提交的结果,所以在不同时间的相同 SQL查询中,可能会得到不同的结果,这种现象叫做不可重复读。
3.REPEATABLE READ
可重复读,是MySQL的默认事务隔离级别,它能确保同一事务多次查询的结果一致。但也会有新的问题,比如此级别的事务正在执行时,另一个事务成功的插入了某条数据,但因为它每次查询的结果都是一样的,所以会导致查询不到这条数据,自己重复插入时又失败(因为唯一约束的原因)。明明在事务中查询不到这条信息,但就是插入不进去,这就叫幻读 (Phantom Read)。
4.SERIALIZABLE
序列化,事务最高隔离级别,它会强制事务排序,使之不会发生冲突,从而解决了脏读、不可重复读和幻读问题,但因为执行效率低,所以真正使用的场景并不多。
App登录验签 踢出并保持30分钟不能登录实现方案
账号密码登录后,通过设置的字符串中取得部分字符串加上通过uniqid函数获得的唯一字符串及随机数字组合成token。设置此token为当前用户的cookie。
并把用户信息数组进行非对称加密处理后返回客户端。
验证是否登录时,客户端需把登录返回的信息进行解密后获取token和用户id及加盐字符串组合后通过hash生成一个签名。并把签名和登录token和用户id组合设置为cookie。通过https协议发送给后端,后端通过相同方式进行验证,以判断请求是否合法及是否登录。
踢出登录:设置用户的状态为禁用,并设置禁止登录的最终时间戳为当前的30分钟后时间戳
Redis磁盘空间满清理冷数据
当Redis的空间满了,需要进行清理工作以确保其正常运行。以下是几种常见的清理方法:
删除过期的键:
Redis支持设置键的过期时间,一旦过期,键会自动被删除。可以使用EXPIRE或PEXPIRE命令设置键的过期时间,或使用TTL命令查看键的剩余过期时间。可以编写一个定时任务来定期检查并删除过期的键。
使用LFU算法删除冷门键:
Redis还支持使用LFU(最近最少使用)算法来删除键,可以在配置文件中设置maxmemory-policy为allkeys-lfu。这样当Redis的内存空间快要满时,会优先删除最近最少使用的键。
使用volatile-lru或volatile-lfu策略控制过期键的删除:
可以在配置文件中设置maxmemory-policy为volatile-lru或volatile-lfu来控制删除过期键时使用的算法。这样Redis会优先删除设置了过期时间的键,以便为新的键腾出空间。
定期进行数据持久化:
可以使用Redis的RDB或AOF持久化方式将数据写入到磁盘上。这样即使Redis的内存空间满了,数据仍然可以从磁盘上读取,避免数据丢失。可以根据实际需求来决定数据持久化的频率和是否进行压缩。
总的来说,清理Redis的空间可以通过删除过期键、使用LRU或LFU算法删除冷门键、控制过期键的删除策略以及进行数据持久化等方式来实现。根据实际情况和需求选择适当的清理方法,以确保Redis的正常运行。
Redis 确定哪些是热key
可以通过分析redis的访问日志或使用redis自带的监控工具来实现。
1.使用info命令获取当前的统计信息,包括所有的key访问次数
2.分析这些信息,找出访问频率高的key
redis-cli info state | grep keyspace
这个命令会列出所有key的访问次数。
然而,redis本身不会跟踪每个key的具体访问频率。
要更具体,需要在应用程序层面进行跟踪,列如通过记录每个key的访问次数。
在应用程序中,通过中间件或拦截器来记录每个key的访问次数,并定期将这些信息发送到后台服务进行统计分析。
缓存雪崩
缓存雪崩是指在某一时刻,大量的缓存数据同时失效,导致大量的请求直接打到数据库上,从而引发数据库的压力激增,可能导致整个系统的崩溃,这种现象被称为缓存雪崩。
产生原因
缓存雪崩通常由于缓存的过期策略或者缓存服务器的故障导致。例如,如果我们将大量的缓存数据设置为在同一时间点过期,那么在这个时间点,这些缓存数据将同时失效,导致大量的请求直接打到数据库上,从而可能引发缓存雪崩。
影响
缓存雪崩的影响是灾难性的。由于大量的请求直接打到数据库上,数据库的压力激增,可能导致数据库崩溃,从而影响整个系统的正常运行。在极端情况下,可能导致整个系统的崩溃。
防范策略
防止缓存雪崩的策略主要有以下几种:
设置不同的过期时间:
通过为每个缓存项设置稍微不同的过期时间,可以避免大量的缓存数据同时失效。
使用热备份:
可以使用热备份的缓存服务器,当主缓存服务器出现问题时,可以立即切换到备份服务器。
数据预热:
在缓存数据过期前,提前将数据加载到缓存中,避免缓存数据的同时失效。
使用限流和熔断机制:
通过限流和熔断机制,可以防止数据库被大量的请求打垮。
缓存击穿
缓存击穿是指一个存在的数据在缓存中过期,导致所有的请求都直接打到数据库,造成数据库短时间内压力过大。这种现象被称为缓存击穿。
产生原因
缓存击穿通常发生在一个热点数据的缓存过期的时候。由于这个数据非常热门,所以在缓存过期的瞬间,大量的请求会直接打到数据库。
影响
缓存击穿会导致大量的请求直接访问数据库,从而增加数据库的负载,可能会导致数据库性能下降,甚至崩溃。
防范策略
防止缓存击穿的策略主要有以下几种:
设置热点数据永不过期:
对于一些访问频率非常高的热点数据,可以设置为永不过期,这样就可以避免因为缓存过期而导致的缓存击穿。
使用互斥锁:
当缓存失效的时候,不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再去load db。这样可以防止大量的并发请求去数据库加载数据。
缓存穿透
缓存穿透是指查询一个数据库中不存在的数据,由于缓存中也没有,所以每次查询都会直接访问数据库。如果有大量此类请求,就会对数据库造成很大压力,这种现象被称为缓存穿透。
产生原因
缓存穿透通常发生在查询一个数据库中不存在的数据时。由于缓存中也没有这个数据,所以每次查询都会直接访问数据库。如果有大量此类请求,就会造成缓存穿透。
影响
缓存穿透会导致大量的请求直接访问数据库,从而增加数据库的负载,可能会导致数据库性能下降,甚至崩溃。
防范策略
防止缓存穿透的策略主要有以下几种:
缓存空值:
即使数据库中没有某个值,也可以在缓存中存储一个空值或特殊标记,这样当查询这个值时,就可以直接从缓存中获取,而不需要访问数据库。
使用布隆过滤器:
布隆过滤器是一种空间效率极高的概率型数据结构,可以用来判断一个元素是否在一个集合中。我们可以将所有可能存在的数据哈希到布隆过滤器中,当查询一个数据时,先判断它是否在布隆过滤器中,如果不在,就可以直接返回,而不需要访问数据库。
来源分组 只要十个分组
SELECT source FROM `service_order` GROUP BY source limit 10;
一条sql计算两种条件的数量
SELECT
count(case when to_state = 2 THEN 0 end) as num1,
count(case when to_state=0 THEN 0 end) as num2
FROM `service_order`;
总结
这家公司的技术似乎比较擅长Redis领域的技术。