准备网络面试题
如果让你实现一个MQ,怎么样保证消息不丢失?
MQ丢失数据存在两种情况,消费端丢失消息和MQ服务器丢失数据;
- 生产者弄丢数据:在消息网络传输过程中因网络问题导致消息丢失。
- MQ服务器弄丢数据:例如rabbitmq没有开启消息持久化,在服务器宕机后重启服务丢失;kafka某个broke宕机,重新选举partition leader时选举了一个还么有同步完消息的fllower作为leader就会丢失消息。
- 消费端弄丢消息:消费端接收到消息,在业务处理过程中宕机 导致 消息丢失情况。
rabbitmq 如何防止消息丢失
生产者保证消息不丢失
- rabbitmq提供是事物功能,在发送消息的时候开启事务,如果发送时出现异常则回滚日志并尝试重新发送。发送消息变为同步阻塞过程,影响吞吐量
- confirm机制,rabbitmq开启confirm机制后每次发送消息,如果消息发送成功会毁掉ack接口,失败则毁掉nack接口。通过异步的方式保证消息发送
rabbitmq 服务器保证消息不丢失
rabbitmq开启消息持久化功能,将消息持久化到磁盘。并且可以结合confirm机制,在持久化成功后才毁掉ack接口通知成功。
消费者保证消息不丢失
rabbitmq提供ack机制,首先关闭自动ack机制,在每次消息处理完成后手动调用ack接口。
kafka 如何防止消息丢失
消费端保证消息不丢失
kafka关闭自动提交offset,在每次消息发送成功后手动提交offset。
kafka 保证消息不丢失
- kafka配置replication.factor 大于1,也就是每个topic有多个副本。
- kafka服务器配置min.isync.replicas 大于1,也就是保证至少有一个fllower可用
- 在生产者端设置acks=all,也就是要求全部副本写入之后才认为成功
- 在生产者端设置retries=MAX,表示失败无限重试写入
生产者保证消息不丢失
在生产者端设置retries=MAX,写入消息失败则多次尝试 保证写入消息成功。
mysql的innodb索引数据结构为什么是b+树,用hash来实现可以吗?
什么是索引
索引是为了提高mysql查询效率而存储在磁盘上的数据结构。为提高查询效率应该尽可能减少磁盘io。
索引常见数据结构
二叉树
二叉树采用二分法思想,O(log N)的复杂度就可以完成对数据的查找任务,查找所需的最大次数等同于二叉查找树的高度。
数的查询效率取决于数的高度,在极端情况下二叉树会退化为线性表。平衡二叉树
平衡二叉查找树(AVL树)在符合二叉查找树的条件下,还满足任何节点的两个子树的高度最大差为1。红黑树
红黑树是一种自平衡的二叉查找树。红黑树和平衡二叉树的区别如下:
- AVL是严格平衡树,因此在增加或者删除节点的时候,根据不同情况,旋转的次数比红黑树要多;
- 而红黑是弱平衡的,用非严格的平衡来换取增删节点时候旋转次数的降低;
- 查找的次数远远大于插入和删除,那么选择AVL树;如果搜索、插入删除次数几乎差不多,应该选择RB树。
为什么使用B+树作为索引
B+树只需要遍历叶子节点就可以实现整棵树的遍历,而不需要遍历所有节点。B+树非叶子节点存储key而不存储data数据,相比于B-树他高度更矮 io效率更少。
hash作为索引:虽然hash可以快速定位但是无序 ,对于一次索引获取多个连续数据就会需要多次io
二叉树索引:不能自平衡,io代价高
秒杀如何防止超卖
秒杀系统超卖产生的原因
秒杀系统卖货是一个事务操作,涉及查询秒杀库存、更新购买后库存。例如库存是10个 在并发情况下,线程A查询到库存为10个 则生成订单并扣减库存8个;线程B在同一时刻也查询到库存为10个,也生成订单并扣减库存8个;两个线程执行完成后库存为-6 出现超卖问题。
超卖问题解决
序号 | 方法 | 优点 | 缺点 |
---|---|---|---|
1 | 悲观锁 | 在更新库存期间加锁,不允许其它线程修改;select * for update | 高并发情况下会导致多个请求等待数据库链接,数据库成为性能瓶颈 |
2 | 乐观锁 | 在数据库中添加版本号字段,修改数据时判断版本号 | ---------- |
3 | 分布式锁 | 分布式锁是在业务代码中手动获取锁,并在业务处理完成后释放锁,在这一过程中其他线程无法获取锁 | 对同一商品的秒杀会出现多个线程等待分布式锁,系统吞吐量下降 |
4 | FIFO 队列 | 引入串行化队列将所有的写数据库的请求在队列里边穿行化执行 | 性能受限于队列处理机处理性能和DB的写入性能中最短的那个 |
5 | Redis原子操作 | 利用redis的事务特性,将库存数据缓存中redis中。秒杀库存直接操作redis,异步更新数据到db | 保证数据一致性 |
ThreadLocal原理以及oom
ThreadLocal是操作线程的局部变量入口,可以为每个线程提供一个独立的变量副本。
ThreadLocal原理
ThreadLocal类在线程中声明,要注意不同实例的ThreadLocal 存储的变量副本不同。原理是ThreadLocal是一个操作线程本地变量ThreadLocalMap(一个Entity数组存储数据,可以理解为HashMap)的入口,并且以ThreadLocal 实例this作为key(弱引用);存储的具体值value为强引用。
ThreadLocal产生oom原因
ThreadLocalMap的生命周期于线程的生命周期一致,当应用ThreadLocal的对象被回收时,ThreadLocalMap还持有ThreadLocal的弱引用以及value的强引用;弱引用会在下次垃圾回收时回收,但强应用value无法回收 造成泄漏。
HashMap实现原理
数组+链表的散列存储结构,数组初始容量16,扩容因子0.75;超过最大存储容量则进行2被扩容处理;如果链表length>8 hash碰撞冲突太多,转换为红黑树存储(查询效率高于链表)。