1、redis的使用场景
限流 降级 秒杀 排行榜
2、限流
流量达到一定的阀值时,会拒绝一部分流量
限流的算法
- 漏桶
计数器,请求来了+1操作,超出时间间隔的,充置。如一分钟的访问次数不能超过100个
当有突发性并发时,如1秒内瞬间发送200个请求。
会有临界问题,漏桶算法中的临界问题指的是当桶中的数据量接近桶的最大容量时,由于数据处理和发送速度是固定的,这时就有可能发生大量的丢包现象。这是因为此时新到来的数据包会被直接丢弃,而且由于数据包的到达速度很快,桶中的数据量无法及时降低,导致后续的数据包也无法被处理和发送出去。因此,在设计漏桶算法时,需要合理设置桶的大小和处理速率,以避免发生临界问题。
2)滑动窗口
可以解决临界问题
滑动窗口机制是一种常见的网络协议机制,用于在不可靠的网络环境中进行可靠的数据传输。
该机制将数据流分割成多个数据包,并在发送端和接收端维护一个固定大小的窗口。发送端通过窗口大小控制发送数据包的数量,接收端通过窗口大小控制接收数据包的数量。具体来说,发送端会在发送数据包后将窗口向前滑动,接收端会在成功接收数据包后将窗口向前滑动。
滑动窗口机制的基本思想是,发送方和接收方之间维护一个滑动窗口,发送方发送数据时,将数据分成多个数据包,每次只发送窗口内的数据包,等接收方确认收到数据包后,发送方将窗口滑动到下一个未发送的数据包位置。接收方收到数据后,会回复一个确认包,确认包中会包含一个序列号,表示接收方已经成功接收到该序列号之前的数据包。发送方接收到确认包后,将窗口向前滑动,将已经成功发送并收到确认的数据包从窗口中移除,并继续发送窗口内的未发送的数据包。如果发送方在规定时间内没有收到接收方的确认包,就会重传相应的数据包,直到接收方确认收到该数据包。
对内存占用会比较多
3)令牌桶每一个请求的到来,都会先取令牌,桶中没有令牌后,没令牌的会丢弃
如果流量较为平稳,可以选择漏桶算法;如果需要对突发性流量有较好的适应能力,可以选择滑动窗口算法;如果需要平滑流量并对突发性流量有一定的适应能力,可以选择令牌桶算法。
3、秒杀有哪些特点
- 突然多了很多的访问,导致商城瘫痪
- 带宽问题
- 大部分请求不会生成订单
- 超卖问题
4、秒杀系统实现的思路,行业主流解决方案
- 请求负载大的行业解决方法
突然多了很多访问,导致商城瘫痪,可以使用负载均衡
带宽问题,可以使用CDN限流
大部分请求不会生成订单,ngnix接入层限流/队列
- 超卖问题的行业主流解决方法
mysql悲观锁,是对数据库提供的锁
mysql乐观锁,不锁数据,而是通过版本号控制
php+队列
php+redis分布式锁 setnx
php+redis乐观锁 watch multi set exec
ngnix+lua+redis乐观锁
限流,加载nignix+lua限流模块,里面有个函数可以设置每秒请求数,漏桶容量,里面有个delay值,超过等待时间,排除
redis乐观锁,redis可以通过watch来实现乐观锁,它会监视指定的key,看是否有被改动过;在watch和exec之间有修改,事务就会失败。
5、redis的线程模型
单线程方式执行,但是通过使用IO多路复用监听多个socket
6、IO多路复用是什么意思
可以同时监控多个输进输出流。会将多个IO流集中在一起,然后去监听具体是哪个流有事件发生。如果有一个事件发生了,就会在对应的IO流上进行读取或者写入操作。避免了使用多个线程去等待一个IO事件的发生。
在IO多路复用机制中,通过使用select,poll,epoll去监听多个IO事件。
7、redis的优缺点
优点:
1)高性能的读写。将数据保存在内存,每秒可以处理数百万个键值对。
2)数据结构丰富 string list hash set zset
3)支持数据持久化 支持AOF和RDB两种持久化方式
4)支持事务
5)内存淘汰机制
缺点:
1)因为数据是保存在内存,只能存储较少量的数据,如果数据量过大的话,则需要升级redis服务器
2)数据持久化问题。redis遇到异常奔溃,会导致数据丢失。虽然也提供多种持久化方法来解决,但是在某些情况下,持久化的开销会降低性能
3)redis不支持完整的ACID事务,虽然只提供了一些基本的事务支持,但是在某些情况下可能无法满足需求。
8、redis的list队列先进先出如何解决插队问题
- 单一列表实现
队列正常操作是左进右出 lpush rpop
遇到高优先级任务时 rpush rpop
- 使用两个队列
一个普通队列 一个高级队列
9、使用redis,lpop一条数据后,插入数据库失败怎么办
当lpop没有消息的时候,需要适当sleep一会再试
在消息者下线的情况下,生产的消息丢失,需要使用专业的rabbitmq
10、缓存击穿
缓存被击穿,里面的数据没有了。表示缓存中没有数据,但数据库中有数据,很多数据从缓存中查不到从而查数据库
指的是并发时,查询的是同一条数据;而缓存雪崩指的是不同的数据都过期。
解决方案:
设置热点数据永远不会过期
11、缓存雪崩
不同数据的缓存在同一时间内大面积失效,后面的请求都会落在数据库上
解决方案:
缓存数据的过期时间错开,防止同一时间大量数据过期现象发生
12、缓存穿透
指缓存和数据库都没有数据,导致所有的请求都落在数据库上,造成数据库短时间内承受大量请求而奔溃
解决方案:
采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个不存在的数据就会被这个bitmap拦截。
13、redis的内存淘汰策略有哪些/内存不足/内存机制
当内存不足以容纳新写入数据时,新写入操作会报错;
当内存不足以容纳新写入数据时,在键空间中,随机移除某个key
当内存不足以容纳新写入数据时,在键空间中,移除最近最少用的key
当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key
当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除
14、redis的内存用完会怎样,内存不足
升级内存
内存淘汰策略
15、redis的分布式锁
使用setnx实现
应用场景是:可以控制用户的频繁操作,也可以解决高并发下带来的问题
16、redis和mongoDB的区别
- 内存管理机制
redis会把数据存放在内存,当内存不足时,可以选择指定的lru算法删除数据;
mongoDB会把数据存放在内存,当内存不足时,只会将热点数据放入内存,其他数据放在磁盘;
- 支持的数据结构类型
redis支持的数据结构丰富 string hash list set zset
mongoDB数据结构单一 json
- 持久化
redis依赖快照进行持久化,aof增强可靠性
mongoDB采用binlog方式持久化,增加可靠性
- 事务支持
redis事务支持弱,只能保证事务中的每个操作连续执行
mongoDB不支持事务
17、redis事务的弱点
原子性弱。虽然提供了multi和exec来实现一组操作原子执行,但是如果中间断电,网络抖动,就有可能导致部分操作成功,部分操作失败,也就是说redis事务并没有提供真正的原子性保证。
隔离性弱。事务开启后,即使客户端在事务执行期间修改了相同的数据,也不会阻止这个事务的执行,这可能会导致数据的不一致性。
持久性弱。不保证写操作的持久化。如果在事务执行后发生了断电,那么之前的操作会被覆盖或者丢失。
multi开启事务
exec提交事务
discard放弃事务
watch监视key的变化
redis支持多用户,在执行事务过程中,不希望其他用户修改我们正在操作的key,可以通过这个命令监听多个key的变化,如果发现key修改过,将会放弃执行事务。
unwatch解除watch状态
18、redis和memcache的区别
redis有着丰富的数据类型
支持数据持久化
19、redis的数据类型
1、string
简单的key-value存储
set get
setnx setex
incr incrby
setbit getbit
type
scan smembers keys
redis是单线程的。因此在使用一些时间复杂度为O(N)的命令时要非常谨慎。可能一不小心就会阻塞进程,导致redis卡顿。
keys / smembers在处理一个大的集合时,会阻塞服务器;
scan虽然时间复杂度也是o(n),但是它是分批次进行的,不会阻塞线程。scan命令提供了limit参数,控制每次返回结果的最大条数,是增量迭代命令。
2、hash
类似数据库中表的一条记录,可以存储复杂的数组结构
hset hget
hmset
hsetnx
hincrby
单页缓存,为什么用mongoDB
因为mongoDB可以存储数据量大的数据
3、list
特性:
元素是有序的,而且列内元素是可以重复的
运用场景:
消息队列 评论列表 消息传递
lpush lrange
4、sorted set有序集合
特性:
元素是有序的,列内元素不可以重复,有权重,可以按照优先级执行
运用场景:
排行榜
zadd zrange
zrem
zunionstore
zinterstore
5、set集合
特性:
元素是无序的,列内元素不可以重复
运用场景:
提供了交集,并集,差集等操作
可用于微博共同好友,二度好友
利用唯一性,可以统计出访问网站的所有独立IP
sadd smembers
srem
spop
smove
scard
sinter
sunion
sdiff
srandmember
20、统计出访问网站的所有独立ip
1)将IP地址添加到red is的set中
sadd website:unique_ips xxxxx;
2)统计出当前独立IP数量
scard website:unique_ips;
21、记录每个IP地址的访问次数
hincryby website:ip_count xxxx 1;
22、统计访问次数最多的IP地址
zincrby website:tp_ips 1 xxxxxx
然后可以使用zrevrangebyscor命令,按分数从高到低返回,即反问次数最多的IP地址。
23、redis的主从复制
- 什么是主从复制
redis数据复制是单向的,只能由主节点到从节点;且每台redis服务器都是主节点;一个主节点有多个从节点,但一个从节点只能有一个主节点。
- 主从复制的作用
冗余 备份 安全 分离 故障 高可用
- 主从复制原理流程
准备阶段,主从需要建立连接
数据同步阶段,发送ping命令->权限验证->同步数据
命令传播阶段
- redis实现主从复制的步骤
分别运行redis容器
配从库不配主库
slaveof 主库IP 主库端口
- redis主从复制常见问题解决
- 数据延迟
编写监测程序,监听主从节点的偏移量
info_replication_offset
master_repl_offset
slave_repl_offset
connected_slaves
slave-server-stale-data
从节点的slave-server-stale-data,从库同主机失去连接,从库的运行方式
yes 从库会继续响应客户端的请求
no 除去info和slaveof命令
- 数据丢失
最少有多少台机器才能写入
min_slave_to_write xxx
数据复和同步延迟不能超过10秒,否则主库就会拒绝写的请求
min_slaves_max_lag 10
- 主从配置不一致
maxmemory 等内存相关配置必须要一致
- 规避全量复制
- 规避复制风暴
24、复制偏移量
master_repl_offset
slave_repl_offset
25、复制积压缓冲区
主节点在发送命令到从节点时候,还会写入到复制积压缓冲区,保留着最近的写命令+偏移量
26、全量复制开销,主要有以下几项
bgsave异步执行时间
RDB快照文件网络传输时间
从节点清空数据的时间
从节点加载RDB时间
27、正常情况下redis是如何决定是全量复制还是部分复制
偏移量在缓冲范围内就会部分复制
28、redis持久化RDB AOF的区别
- 保存到硬盘的数据不一致(数据,写命令)
- RDB适合大规模的数据恢复,但是他的数据一致性和完整性差;AOF的数据完整性比RDB高,但记录内容多了,影响到数据恢复到效率。
- 默认开启到是RDB持久化方式,在指定到时间间隔内,执行指定次数到写操作,则会将内存中的数据写入到磁盘。AOF持久化方式,默认是每秒将写操作日志追加到AOF文件中
- 对AOF文件大的问题,提供了重写的瘦身机制
29、为什么开启了主从复制,实现数据备份,还需要持久化呢
主节点和从节点在同一个机房
主机误重启
异地灾备
30、RDB优缺点
优点:
保存了某个时间节点数据
恢复数据的速度比aof快
缺点:
无法做到毫秒级别持久化
数据量太大,fork子进程会阻塞,由子进程负责持久化
31、AOF优缺点
优点:
是一个追加日志的文件
文件过大,会进行压缩瘦身
缺点:
文件体积比RDB大
文件效率比RDB大
32、持久化的配置方案
save 60 1000
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
33、redis配置优化
1)maxmemory设置redis使用的最大物理内存
2)客户端设置一个超时时间
3)maxclients 限制客户端连接数
4)键名保持简短
5)设置key有效期
6)是否进行压缩存储
7)取消AOF持久化
8)设置bit级别的存储 setbit getbit
9)想要一次性添加多条数据时,可以使用管道
34、* zset为什么用跳表,不用b树 / 红黑树
跳表的时间复杂度是o(logn)
跳表的实现更加简单,效率更高,不需要旋转节点,只需要维护相邻前后的两个节点就可以。平衡树和红黑树的插入和删除,都需要去维护节点的旋转
查询范围效率高于红黑树,因为跳表是从上往下查找的,上层范围更广
35、* hashmap为什么用红黑树,而不是跳表
空间
红黑树不占用多余空间;跳表,是链表的数据结构,需要额外的多层链表,空间换时间
+
排序
hashmap是无序的,时间复杂度是o(1),如 set
无法使用跳表 以为跳表本身存在排序关系,时间复杂度是o(logn),例如zset
36、* 红黑树和普通的平衡二叉树有什么区别
旋转:普通的平衡二叉树中,为了保持平衡,需要在节点插入或删除后通过旋转来调整树的平衡。而在红黑树中,通过对节点颜色的约束和旋转来保持树的平衡。
平衡条件:在普通的平衡二叉树中,平衡条件是左右子树高度之差不超过1,而在红黑树中,平衡条件是任何一个节点到其叶子节点的路径上黑色节点数量相同。
37、* 树和图的区别
树必须有一个根节点,图没有
树可以遍历,由一个特定节点到其他节点
树是一个分层的模型结构,图是网络模型
38、为什么用lua,而不用ngnix的limit模块 或者 为什么不用redis队列限流
ngnix的模块limit是写死的,lua是可以定义的。
用redis队列不是很合适,因为那不是它的专项应用场景,队列的专项是异步任务处理,并不是限流
39、ngnix + lua +redis乐观锁 实现单台机器QPS达到20000的负载,而且这20000的负载是如何计算得出来的
限流 降级 缓存
20000QPS表示ngnix服务器可以处理的请求数
计算QPS可以使用ab等基准测试,压力测试工具模拟大量并发请求,测量服务器等响应时间和吞吐量。将成功请求的数量除以所花费的时间来计算QPS。
40、布隆过滤器在项目哪里,有用到
布隆过滤器是一种数据结构,用于快速检查某个元素是否属于一个集合中。在游戏开发中,可以使用布隆过滤器来实现快速查找游戏玩家的数据。
ß
1、安装布隆过滤器扩展包:可以使用composer安装布隆过滤器扩展包,例如PHPBloomFilter或php-bloom-filter。
2、创建布隆过滤器对象,指定布隆过滤器的大小和哈希函数的数量等参数。
3、将游戏玩家的数据添加到布隆过滤器中:在将游戏玩家数据添加到布隆过滤器之前,需要先将数据进行哈希处理。可以选择多个哈希函数(md5 sha1)对数据进行哈希,将哈希结果映射到布隆过滤器的位数组中。在哈希结果映射到位数组中时,将对应的位设置为1。
4、检查游戏玩家的数据是否存在于布隆过滤器中:当需要查找某个游戏玩家的数据时,将其进行哈希处理并检查布隆过滤器中对应的位是否为1。如果所有对应的位都为1,则说明该游戏玩家的数据可能存在于布隆过滤器中,需要进一步检查确认。如果至少有一个对应的位为0,则说明该游戏玩家的数据一定不存在于布隆过滤器中,可以直接返回不存在。
41、布隆过滤器存的是什么怎么存
1)布隆过滤器的原理:
如果布隆说没有,直接返回没有;如果布隆说有,才会去mysql查询数据;
新增数据时,会同步给布隆,但是布隆并不会保存这条数据的内容,存的是商品编号。布隆算法,类似一个hash set,用来判断某个元素是否在某个集合中。
到那时和一般hash set不同,这个算法不存储key的值,每个存储一个标志,用来判断key是否存在集合中。
不需要存储key值,节省空间
算法判断key在集合中时,也会有一定概率key其实不再集合中
2)布隆过滤器的数据和算法:
位向量bit bit数据结构
3)空间复杂度都是一样的,都是O(1),为什么不用hash,而是基于bit位运算
存储空间
4)布隆过滤器实操的几种方法
1)php+redis实现布隆过滤器
2)利用插件,安装redis插件bloom-filter
3)php-redis扩展中有个函数可以调用原始的redis命令
$redis->rawCommand(‘bf.exits’ , ‘xxxxx’, ‘yyyyyyy’ )
42、redis的慢查询日志
超过多少微妙,命令会被记录到日志
slow_log_lower_than
控制命令的数量
slow_log_max_len
43、redis也可以实现分布式锁,为什么还用mq
redis的吞吐里更大,但使用rabbitmq,最重要的是对消息的确认
44、redis持久化了,那么过期时间的key会删除吗
持久化只是保存当前这一时间点的数据,如果到期了是不会放进去的,而且过期的可以有对应的淘汰策略;
45、redis连接时的connect和pconnect的区别
使用connect,设置的时间到则释放连接
使用pconnect,设置的5秒钟到了,不会释放redis的连接资源,而是由php-fpm管理。下次如果还连接这个redis,则使用它直到php-fpm释放了redis连接才释放。
46、redis的hash底层实现
当数据量比较小的时候,采用ziplist压缩列表
另一种采用dict来实现
47、rabbitMQ如何保证消息的顺序性
在生产者端,根据消息的hashkey进行消息分组,确保有依赖关系的信息分到同一个组。每个组对应一个队列,一个消费者消费一个队列,使得消息顺序消费。
48、如何提高消费的消费速率
增加消费者的数量提高消费速率
设置每次拉取消息的条数来减少网络传输
通过协程来并发处理消息
49、rabbitmq有哪几种路由方式
direct 根据路由模式完全匹配
fanout 忽略路由模式
topic 根据路由模式模糊匹配
50、rabbitMQ消息基于什么传输
基于信道channel的方式传输数据,排除了使用tcp传输数据;
因为tcp连接创建和销毁对于系统性能的开销大
51、rabbitMQ多个消费者监听一个队列时,消息如何分发
轮询 轮流,平均地接收信息
公平分发 根据消费者的能力
52、消息在什么时候会变成死信,死信的来源
消息被拒绝
消息超时过期,如下单未支付
消息队列长度达到限制
53、如何自动删除长时间没有消费的消息
通过队列属性设置消息时间
对每条消息设置过期时间
54、延时队列的实现
ttl+死信
过期消息转移到死信exchange,然后再由队列去消费完成后期的业务逻辑
55、rabbitmq有哪些高级特性
1)消息可靠性的传递
生产者 消息的发送方为杜绝消息的丢失或者投递失败的场景,提供了confirm和return两种解决方式;
整个消息的投递路径为:
生产者-> mq broker->exchange->queue->consumer
消息从生产者到交换机,会返回一个confirm
消息从生产者到队列,会返回一个return
我们就是利用这两个来保证消息的可靠性传递
消费者 消费者有三种接收信息的方式:自动确认,手动确认,根据异常情况确认
2)消费端限流
请求瞬间增多,达到每秒50000个请求
利用mq,可以每秒从mq中只是拉取1000个请求,因为服务器每秒最大处理是1000个请求。
3)延时队列
MQ(消息队列)延时队列主要用于需要在一定时间后再处理消息。
延时队列的实现主要是通过 ttl+死信队列
生产者将消息发送到队列后,在规定的时间内没有被消费,超过ttl设置的时间,就会进入到死信交换机,然后交由相应的队列进行消费。
下面是一些使用场景:
订单超时处理:下单30分钟未支付。在订单创建后,可以将订单信息发送到延时队列中,设置一定的超时时间,如果在超时时间内未支付,则将订单状态设置为超时。
限时活动:在一些限时活动中,可以将活动信息发送到延时队列中,设置活动结束的时间,这样就可以保证活动在指定的时间结束,同时也可以减轻后台系统的负担。
4)消息的幂等性
多次执行的结果和进行一次的执行结果应该相同
避免重复消费
在mq中指,多次消费一条信息 和 消费一条 消息的结果 应该是一样的
消息幂等性的保障,可以使用乐观锁机制
comfirm机制和ack机制
5)消息的积压
解决方案:
上多个消费者
将消息先取出来,然后放在数据库处理
6)重复消费
在第一次消费消息时,可以以消息ID,这个ID需要保证是全局唯一ID,作为key放在redis中,并且设置过期时间,下次再消费之前判断这个key是否在redis中存值,存在就过滤。
或者设置数据库唯一主键,主键是不能冲突的,重复的数据也是无法插入的。
56、分布式事务解决方案
2pc
协调者单点故障问题:
一旦事务协调者节点挂掉,会导致参与者接收不到提交和回滚的通知。会让事务无法完成;
参与者丢失数据导致的数据不一致的问题:
网络问题,一部分事务参与者接收到了提交信息,另一部分事务参与者没有接收到提交消息。
3pc
参与者没有接收到协调者的commit请求,就会自动进行本地的commit
2pc中只有协调者可以超时,参与者没有超时限制
tcc
与2pc类似,2pc通常是在数据库层面,而tcc就是一个应用层
mq
消息百分百投递成功,结合confirm机制
消息百分百消费成功,结合ack机制
57、如何确保消息百分百发送成功
生产者投递信息给到mq,生产者会把投递的消息都订单号保存,本地数据库或者缓存保存了订单投递的状态。
mq会把投递状态发送给到PHP监听,监听器会把订单号的状态改为已经投递。另外会有个脚本,经常去查询哪些订单没有成功,然后重新投递。
消费者失败,调用函数nack,告诉mysql不要删除信息,然后就可以二次尝试继续消费消息;消费成功,调用函数ack,那么mq会删除消息。
58、mq架构流程图 设计分析
前端下单 下单微服务,完成插入订单表并且把消息推送给到rabbitMQ
rabbitMQ中间件 利用rabbitMQ confirm机制,确保消息百分百投递到派单信息
派单微服务 利用rabbitMQ的ack机制,确保消息百分百消费成功,这里还需要实现幂等性操作。
插入派单表
59、mq事务最终一致性的优点
消息队列异步,响应时间快
可靠性,最终一致性
不会存在大量的锁
60、高峰值时,大流量时,rabbitmq容易爆掉,而kafka不会
这个都是相对的,如果高峰很大,不管什么东西都会爆掉。rabbitMQ是用内存做存储持久化的,所以比Kafka更容易出现爆掉的情况,而Kafka是直接搞到磁盘里面去的。
61、消息堆积太多,多个消费者都消费不掉,应该怎么办
限流机制 + 多个消费者负载
多线程协程等方式
任务不是均匀分配的,而是根据处理能力来的,能力好,消费快
62、不用监听器可以吗
不用监听器也是可以推送消息的,只是生产者不会知道有没推送成功
63、rabbitMQ有几种集群方案
主备
远程
镜像
保证数据100%不丢失,一般互联网大厂都会用这种模式,目的是为了保证rabbitmq数据的高可靠性,实现数据的同步。
主节点通过镜像队列把数据同步到其他的mq节点
多活