7.面试总结分享之 —中间件

7.中间件

1.redis

1.购物车在redis中是怎么存的?

我们的购物车,用的是redis 来实现的。 当加入购物车的时候 用户id作为redis 的key,产品集合作为redis的value。商品存的是 ,商品id 商品名称,和商品购买数量。

当加入商品到购物车的时候,首先判断当前用户id对应的的产品集合里面是否含有当前产品,有则数量加一。没有则新添加该商品。

2,说说Redis哈希槽的概念?

Redis集群没有使用一致性hash,而是引入了哈希槽的概念,Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽,集群的每个节点负责一部分hash槽。

3.怎么测试Redis的连通性?

ping

4.redis相比memcached有哪些优势?
  • memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型
  • redis的速比memcached快很多
  • redis可以持久化其数据,也可以做数据备份
  • 单个value的最大限制是1GB,不像 memcached只能保存1MB的数据
5.使用过Redis分布式锁么,它是怎么实现的?

先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。

6.使用过Redis做异步队列么,你是怎么用的?有什么缺点?

一般使用list结构作为队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试。

缺点:在消费者下线的情况下,生产的消息会丢失,得使用专业的消息队列如rabbitmq等。

7.什么是缓存穿透?如何避免?什么是缓存雪崩?何如避免?

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

如何避免?

  1. 对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert了之后清理缓存。
  2. 对一定不存在的key进行过滤。可以把所有的可能存在的key放到一个大的Bitmap中,查询时通过该bitmap过滤。

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

如何避免?

  1. 在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
  2. 做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期
  3. 不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。(可以在设置缓存时间的时候再加上一个随机的时间值,保证缓存的失效时间不过度集中)
8.redis 内存淘汰机制(MySQL里有2000w数据,Redis中只存20w的数据,如何保证Redis中的数据都是热点数据?)

redis 提供 6种数据淘汰策略:

  • volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
  • volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
  • volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
  • allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是最常用的)
  • allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
  • no-eviction:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。这个应该没人使用吧!

4.0版本后增加以下两种:

  • volatile-lfu:从已设置过期时间的数据集(server.db[i].expires)中挑选最不经常使用的数据淘汰
  • allkeys-lfu:当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的key
9.redis 事务

Redis 通过 MULTI、EXEC、WATCH 等命令来实现事务(transaction)功能。事务提供了一种将多个命令请求打包,然后一次性、按顺序地执行多个命令的机制,并且在事务执行期间,服务器不会中断事务而改去执行其他客户端的命令请求,它会将事务中的所有命令都执行完毕,然后才去处理其他客户端的命令请求。

在传统的关系式数据库中,常常用 ACID 性质来检验事务功能的可靠性和安全性。在 Redis 中,事务总是具有原子性(Atomicity)、一致性(Consistency)和隔离性(Isolation),并且当 Redis 运行在某种特定的持久化模式下时,事务也具有持久性(Durability)。

10.Memcache与Redis的区别都有哪些?
  • 存储方式 Memecache把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。Redis有部份存在硬盘上,这样能保证数据的持久性。
  • 数据支持类型 Memcache对数据类型支持相对简单。Redis有复杂的数据类型。
  • 使用底层模型不同 它们之间底层实现方式 以及与客户端之间通信的应用协议不一样。Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。
11.redis的并发竞争问题如何解决?

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

对此有2种解决方法:

  1. 客户端角度,为保证每个客户端间正常有序与Redis进行通信,对连接进行池化,同时对客户端读写Redis操作采用内部锁synchronized。
  2. 服务器角度,利用setnx实现锁。
12.redis集群中一致性hash的使用

redis集群中存储的文件,加入数量很大的时候,由于我们定义的规则是随机的,所以我们的数据有可能存储在任何一组Redis中查询数据时就需要遍历每一个集群中的结点去寻找对应的数据。显然,查询数据过程中对redis集群进行遍历并不是我们想要的,所以我们会想到按某一个字段值进行Hash值、取模。
使用hash的redis集群

7.面试总结分享之 —中间件

从上图中,我们需要查询的是图product.png,由于我们有6台主服务器,所以计算的公式为:hash(product.png) % 6 = 5, 我们就可以定位到是5号主从,这们就省去了遍历所有服务器的时间,从而大大提升了性能。

使用Hash时遇到的问题

在上述hash取模的过程中,我们虽然不需要对所有Redis服务器进行遍历而提升了性能。但是,使用Hash算法缓存时会出现一些问题,Redis服务器变动时,所有缓存的位置都会发生改变。
比如,现在我们的Redis缓存服务器增加到了8台,我们计算的公式从hash(product.png) % 6 = 5变成了hash(product.png) % 8 = ? 结果肯定不是原来的5了。

再者,6台的服务器集群中,当某个主从群出现故障时,无法进行缓存,那我们需要把故障机器移除,所以取模数又会从6变成了5。我们计算的公式也会变化。由于上面hash算法是使用取模来进行缓存的,为了规避上述情况,Hash一致性算法就诞生了

一致性Hash算法原理

一致性Hash算法也是使用取模的方法,不过,上述的取模方法是对服务器的数量进行取模,而一致性的Hash算法是对2的32方取模。即,一致性Hash算法将整个Hash空间组织成一个虚拟的圆环,Hash函数的值空间为0 ~ 2^32 - 1(一个32位无符号整型),整个哈希环如下:

7.面试总结分享之 —中间件

一致性Hash算法的容错性和可扩展性

现在,假设我们的Node C宕机了,我们从图中可以看到,A、B不会受到影响,只有Object C对象被重新定位到Node A。所以我们发现,在一致性Hash算法中,如果一台服务器不可用,受影响的数据仅仅是此服务器到其环空间前一台服务器之间的数据(这里为Node C到Node B之间的数据),其他不会受到影响

数据倾斜问题

为了解决数据倾斜问题,一致性Hash算法引入了虚拟节点机制,即对每一个服务器节点计算多个哈希,每个计算结果位置都放置一个此服务节点,称为虚拟节点。

7.面试总结分享之 —中间件

2.kafka

3.MQ

4.zookeeper

1.dubbo和zookeeper

Duboo是一个分布式框架,zookeeper是duboo生产者暴露服务的注册中心。起一个调度和协调功能,当然注册中心也可以用redis 或者duboo自带的Multicast 来注册。

5.dubbo