java常见疑难面试题及答案(阿里、蚂蚁、百度、美团)(二)

11.redis持久化,RDB和AOF有什么区别

RDB持久化(效率优先):指定的时间间隔内fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。

优势:

1)数据都存储在一个文件中,便于灾难恢复。

2)不会对性能造成太大的影响,持久化是通过fork出子进程完成的,可以极大的避免服务进程执行IO操作。

3)当数据集较大时,启动效率高于AOF。

劣势:

1)定时持久化前宕机的话,没有保存的数据会全部丢失

2)由于是fork子进程来协助完成数据集持久化工作,当数据集较大时,可能会导致整个服务器停止服务。

AOF持久化(一致性优先):以日志的形式记录服务器所处理的每一个写、删除操作,保留详细的操作记录(格式清晰、易于理解)

优势:

1)数据安全性高,写入操作采用的是append模式,出现宕机现象,也不会破坏日志文件中已经存在的记录。

2)如果日志过大,Redis可以自动启用rewrite机制(以append模式将修改数据写入到老的磁盘文件中,同时会创建一个新的文件用于记录此期间有哪些修改命令被执行)。

3)可以根据日志文件完成数据重建:

劣势:

1)因为需要记录每条操作,文件会比RDB大,灾难恢复速度也会被较慢。

2)AOF运行效率会比RDB稍慢。

12.Redis部署模式有哪些?

主从模式:设置一个主节点,N个从节点,写主读从。必须保证主节点不会宕机一旦主节点宕机,其它节点不会竞争成为主节点,Redis将丧失写的能力

哨兵模式:比主从模式多了一个竞选机制,主节点宕机,所有的从节点会竞选出新的主节点。(依赖于在系统中启动一个sentinel进程)sentinel进程会监听主从之间是否正常工作,实例出了问题时会通过API通知。主节点出问题后,sentinel会在所有的从节点中竞选出一个节点,并将其作为新的主节点。它还能够向使用者提供当前主节点的地址,故障转移后使用者不用做任何修改就可以知道当前主节点地址。

cluster(集群)模式:自动分割数据到不同的节点上(集群有16384个哈希槽,每个key完成CRC16校验后对16384取模来决定放置哈希槽),主从复制模型,每个节点都会有N-1个复制品,整个集群的部分节点失败或者不可达的情况下能够继续处理命令。但是因为是集群使用了异步复制,所以不能保证数据的强一致性。

13.nosql是否了解?项目实际运用?

nosql泛指非关系型的数据库。

1)高性能,高可用性和可伸缩性

2)没有声明性查询语言(sql)

3)存储格式为键 - 值对存储(redis)、列式存储(HBase)、文档存储(MongDB)、图形数据库(Neo4j)

4)最终一致性,并非遵循ACID(原子、一致、隔离、持久)

数据库选型

1)数据量少,并发少建议选择关系型数据库

2)流量大系统后台建议关系型数据库

3)批量数据处理、离线计算、即时查询、监控,建议选列式存储

4)事务性系统建议选择关系型数据库

5)数据量很大或者未来会变得很大,且表结构不明确,且字段在不断增加,建议使用文档存储

6)关系性强、记录大量基于事件的数据、推荐引擎推荐使用图形数据库

14.tomcat集群怎么保证同步?

增量复制:只同步会话增量,集群中一个节点发生改变后,在一个请求被响应之前会同步到其余全部节点。但是因为备份的网络流量会随着节点数的增加而急速增加,无法构建较大规模集群。

绑定:每个会话只有一个备份,利用负载均衡的源地址Hash算法实现,整个会话期间,用户所有的请求都来自一台歌节点。(宕机会导致节点上的数据全部丢失

15.如何解决超卖问题?

当商品库存接近0时,如果多个买家同时付款购买此宝贝,会出现超卖缺货的现象。

sql适合流量少的情况,秒杀的情况下,数据库扛不住:

排他锁

update goods set num = num - 1 WHERE id = 1001 and num > 0;

乐观锁

select version from goods where id = 1001;
update goods set num = num - 1, version = version + 1 WHERE id = 1001 AND num > 0 AND version = 1;

为什么通过新增字段version控制,而不是利用原有num字段?

存在ABA问题:A线程获取num为3,B线程获取num也为3,B线程先将num-1=2,处理失败又将库存数恢复成3,A线程在进行更新操作时num=3,但是操作期间num已经有了变化。

悲观锁

select * from goods where id = 1001 for update;

update goods set num = num - 1, version = version + 1 WHERE id= 1001;

redis:

锁 将商品数量放入缓存中,使用锁来处理其并发情况。当接到买家提交订单的情况下,先加锁,然后将商品数量递减,解锁后进行其他处理。如果处理失败加锁后将数据递增1再解锁。当商品数量递减到0时,表示商品秒杀完毕,拒绝其他用户的请求。

队列 Redis 队列中加入商品数量相等的元素,请求进入从队列上 pop 出一个元素,获得就代表成功。

异步:

将购买请求放入消息队列之中,异步处理结果。

16.分布式id生成方式

1)数据库自增

优势:

实现简单、自增方便排序

劣势:

分库分表、数据迁移的时候会出现问题,且难以扩展

2)uuid

优势:

实现简单、拥有唯一性,分库分表和数据迁移无影响

劣势:

没有排序,无法保证趋势递增,长度较长,存储、查询效率较低,作为id性能差

3)Redis的原子操作 INCR

优势:

性能好,递增保证排序

劣势:

需要引入redis,增加复杂度

4)snowflake算法(百度uid-generator和美团ecp-uid都是基于snowflake实现的)

使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0

优势:

性能好、单机递增

劣势:

要求系统时间只能增不能减,无法应对时间回退(修改机器时间)问题(官方scala代码会对比时间,如果发生回退回抛InvalidSystemClock异常)

17.int的范围?

-2^31-2^31-1

18.java常用数据结构

List、Set、Map

19.ConcurrentHashMap

线程安全且高效的HashMap实现,数组+链表(链表节点数超过指定阈值8的话,也是会转换成红黑树

 Java 5 之后,引用了内部的 Segment ( ReentrantLock )  分段锁,操作同段 map 的时候,进行锁的竞争和等待。

jdk8重新使用synchronized+cas

1)多个分段锁浪费内存空间,而且影响gc效率

2)同时map 在放入时竞争同一个锁的概率非常小,分段锁反而会造成更新等操作的长时间等待

20.ConcurrentHashMap扩容

1)如果新增节点之后,所在链表的元素个数达到了阈值 8,则会调用treeifyBin方法把链表转换成红黑树。

2)如果数组长度n小于阈值MIN_TREEIFY_CAPACITY(默认是64),则会调用tryPresize方法把数组长度扩大到原来的两倍,并触发transfer方法,重新调整节点的位置。

3)新增节点之后,当数组元素个数达到阈值时,会触发transfer方法。

transfer方法:

1)新建一个长度为2n的数组。

2)线程获取一个扩容子任务,设置当前处理子任务的下界并更新当前处理节点所在的索引位置。(每迁移一个元素,元素会被设置为ForwardingNode,方便迁移过程中get)

3)对子任务中的每个节点,扩容线程从后向前依次判断该节点是否已经转移,如果没有转移,则对该节点进行加锁,并且把节点对应的链表或红黑树迁移到新数组中。

4)如果线程处理的节点索引已经到达子任务的下界,则子任务执行结束,并尝试去领取新的子任务,若领取不到再判断当前线程是否是最后一个扩容线程,若是则最后扫描一遍数组,执行清理工作,否则直接退出。

发布了43 篇原创文章 · 获赞 0 · 访问量 3920

猜你喜欢

转载自blog.csdn.net/zhangdx001/article/details/104907732