2019年03月03日面试题目汇总
常见分布式全局唯一ID生成策略以及优缺点
方法一:用数据库自带的 auto_increment 来生成,
优点:
1 此方法使用数据库原有的功能,所以相对简单
2 能够保证唯一性,数据库唯一控制、为了保证唯一性,大量添加时候性能不佳
3 能够保证递增性,对数据库索引结构变更影响较小。
4 id之间的步长是固定且可自定义的
缺点:
1 该方式与数据库耦合,不同数据库的实现不一样,当切换数据库时候工作量较大。
2 扩展性差,性能有上限:因为写入是单点,数据库主库的写性能决定ID的生成性能上限,并且 难以扩展
3 自增的方式,数据是连续的。非常容易被恶意用户爬取数据
方法二: 使用uuid,uuid是一种常见的本地生成ID的方法。UUID uuid = UUID.randomUUID()
优点:
1 本地生成ID,不需要进行远程调用,时延低
2 扩展性好,与数据库无关,基本可以认为没有性能上限
缺点:
1 无法保证趋势递增,无序。增删的时候索引变更影响较大
2 uuid过长(不推荐主键过长,占用空间),往往用字符串表示,作为主键建立索引查询效率低
方法三:Twitter 开源的 Snowflake 算法,核心思想:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID), 12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。
优点:
1 速度快,保证唯一性。性能好
2 没有啥依赖,实现也特别简单。与数据库无关
缺点:
1 只能趋势递增。字段较长,作为主键建立索引查询效率低
2 依赖机器时间,如果发生回拨会导致可能生成id重复
缓存穿透、缓存击穿、缓存雪崩区别和解决方案
缓存:将一些常用但不常修改、非强一致性的数据缓存起来加快查询,减轻数据库压力,
缓存穿透:缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。
解决方案
1 接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
2 从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点。
缓存击穿:缓存中没有但数据库中有的数据(一般是缓存时间到期),大量并发用户同时读缓存没读到数据, 又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。(指并发查同一条数据)
解决方案
1 对于一些数据设置永久过期、过期时间设置在人流量少(推荐)的时候
2 加互斥锁,防止同一数据并发访问数据库。
缓存雪崩:缓存中数据大批量到过期时间,很多数据都查不到从而查数据库,而查询数据量巨大,引起数据库压力过大甚至down机。
解决方案
1 缓存过期时间分散或者集中在人流量很少的时候
2 一主多重,分表分库,读写分离。热点数据分布式部署。
注:缓存雪崩和缓存击穿不同的是缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
谈谈分布式事务和分布式锁
分布式锁:控制分布式系统有序的去对共享资源进行操作,通过互斥来保持一致性。一个资源同一时间只能被一个线程使用 高可用高性能的获取、释放锁。具备失效机制避免死锁。解决的是多进程的并发问题。
实现的三种方式:
1. 基于数据库实现分布式锁;
2. 基于缓存(Redis等)实现分布式锁;
3. 基于Zookeeper实现分布式锁
Redis与Zookeeper对比:Redis基于内存,性能比Zookeeper好。但是Redis的有效时间控制有延迟,可靠性Zookeeper更佳
分布式事务:事务是达到以下目的的最好方法即保证执行结果的正确性;保证数据的一致性;ACID
在CAP定理中,一致性、可用性、分区容错性是不可能同时存在的。但在实际的应用场景中,数据的一致性是需要保证的。
实现方案:
TCC 方案
消息队列
说一下HashMap,ConCurrentHashMap 1.7和1.8的区别
HashMap的区别
1 数据结构不一样了, 1.7是数组+链表,1.8是数组+链表+红黑树(当链长超过8时候转化为红黑树,小于等于6时,树结构还原成链表形式。)
2 扩容的时机:1.7在插入数据之前扩容,而1.8插入数据成功之后扩容。
3 扩容后数据存储位置的计算方式也不一样:
ConCurrentHashMap的区别
1.7基于Segment + HashEntry实现,对segment加锁
1.8基于Node + CAS + Synchronized实现