準(zhǔn)備網(wǎng)絡(luò)面試題
如果讓你實(shí)現(xiàn)一個(gè)MQ,怎么樣保證消息不丟失?
MQ丟失數(shù)據(jù)存在兩種情況,消費(fèi)端丟失消息和MQ服務(wù)器丟失數(shù)據(jù);
- 生產(chǎn)者弄丟數(shù)據(jù):在消息網(wǎng)絡(luò)傳輸過程中因網(wǎng)絡(luò)問題導(dǎo)致消息丟失。
- MQ服務(wù)器弄丟數(shù)據(jù):例如rabbitmq沒有開啟消息持久化,在服務(wù)器宕機(jī)后重啟服務(wù)丟失;kafka某個(gè)broke宕機(jī),重新選舉partition leader時(shí)選舉了一個(gè)還么有同步完消息的fllower作為leader就會(huì)丟失消息。
- 消費(fèi)端弄丟消息:消費(fèi)端接收到消息,在業(yè)務(wù)處理過程中宕機(jī) 導(dǎo)致 消息丟失情況。
rabbitmq 如何防止消息丟失
生產(chǎn)者保證消息不丟失
- rabbitmq提供是事物功能,在發(fā)送消息的時(shí)候開啟事務(wù),如果發(fā)送時(shí)出現(xiàn)異常則回滾日志并嘗試重新發(fā)送。發(fā)送消息變?yōu)橥阶枞^程,影響吞吐量
- confirm機(jī)制,rabbitmq開啟confirm機(jī)制后每次發(fā)送消息,如果消息發(fā)送成功會(huì)毀掉ack接口,失敗則毀掉nack接口。通過異步的方式保證消息發(fā)送
rabbitmq 服務(wù)器保證消息不丟失
rabbitmq開啟消息持久化功能,將消息持久化到磁盤。并且可以結(jié)合confirm機(jī)制,在持久化成功后才毀掉ack接口通知成功。
消費(fèi)者保證消息不丟失
rabbitmq提供ack機(jī)制,首先關(guān)閉自動(dòng)ack機(jī)制,在每次消息處理完成后手動(dòng)調(diào)用ack接口。
kafka 如何防止消息丟失
消費(fèi)端保證消息不丟失
kafka關(guān)閉自動(dòng)提交offset,在每次消息發(fā)送成功后手動(dòng)提交offset。
kafka 保證消息不丟失
- kafka配置replication.factor 大于1,也就是每個(gè)topic有多個(gè)副本。
- kafka服務(wù)器配置min.isync.replicas 大于1,也就是保證至少有一個(gè)fllower可用
- 在生產(chǎn)者端設(shè)置acks=all,也就是要求全部副本寫入之后才認(rèn)為成功
- 在生產(chǎn)者端設(shè)置retries=MAX,表示失敗無限重試寫入
生產(chǎn)者保證消息不丟失
在生產(chǎn)者端設(shè)置retries=MAX,寫入消息失敗則多次嘗試 保證寫入消息成功。
mysql的innodb索引數(shù)據(jù)結(jié)構(gòu)為什么是b+樹,用hash來實(shí)現(xiàn)可以嗎?
什么是索引
索引是為了提高mysql查詢效率而存儲(chǔ)在磁盤上的數(shù)據(jù)結(jié)構(gòu)。為提高查詢效率應(yīng)該盡可能減少磁盤io。
索引常見數(shù)據(jù)結(jié)構(gòu)
二叉樹
二叉樹采用二分法思想,O(log N)的復(fù)雜度就可以完成對(duì)數(shù)據(jù)的查找任務(wù),查找所需的最大次數(shù)等同于二叉查找樹的高度。
數(shù)的查詢效率取決于數(shù)的高度,在極端情況下二叉樹會(huì)退化為線性表。平衡二叉樹
平衡二叉查找樹(AVL樹)在符合二叉查找樹的條件下,還滿足任何節(jié)點(diǎn)的兩個(gè)子樹的高度最大差為1。紅黑樹
紅黑樹是一種自平衡的二叉查找樹。紅黑樹和平衡二叉樹的區(qū)別如下:
- AVL是嚴(yán)格平衡樹,因此在增加或者刪除節(jié)點(diǎn)的時(shí)候,根據(jù)不同情況,旋轉(zhuǎn)的次數(shù)比紅黑樹要多;
- 而紅黑是弱平衡的,用非嚴(yán)格的平衡來換取增刪節(jié)點(diǎn)時(shí)候旋轉(zhuǎn)次數(shù)的降低;
- 查找的次數(shù)遠(yuǎn)遠(yuǎn)大于插入和刪除,那么選擇AVL樹;如果搜索、插入刪除次數(shù)幾乎差不多,應(yīng)該選擇RB樹。
為什么使用B+樹作為索引
B+樹只需要遍歷葉子節(jié)點(diǎn)就可以實(shí)現(xiàn)整棵樹的遍歷,而不需要遍歷所有節(jié)點(diǎn)。B+樹非葉子節(jié)點(diǎn)存儲(chǔ)key而不存儲(chǔ)data數(shù)據(jù),相比于B-樹他高度更矮 io效率更少。
hash作為索引:雖然hash可以快速定位但是無序 ,對(duì)于一次索引獲取多個(gè)連續(xù)數(shù)據(jù)就會(huì)需要多次io
二叉樹索引:不能自平衡,io代價(jià)高
秒殺如何防止超賣
秒殺系統(tǒng)超賣產(chǎn)生的原因
秒殺系統(tǒng)賣貨是一個(gè)事務(wù)操作,涉及查詢秒殺庫存、更新購買后庫存。例如庫存是10個(gè) 在并發(fā)情況下,線程A查詢到庫存為10個(gè) 則生成訂單并扣減庫存8個(gè);線程B在同一時(shí)刻也查詢到庫存為10個(gè),也生成訂單并扣減庫存8個(gè);兩個(gè)線程執(zhí)行完成后庫存為-6 出現(xiàn)超賣問題。
超賣問題解決
| 序號(hào) | 方法 | 優(yōu)點(diǎn) | 缺點(diǎn) |
|---|---|---|---|
| 1 | 悲觀鎖 | 在更新庫存期間加鎖,不允許其它線程修改;select * for update | 高并發(fā)情況下會(huì)導(dǎo)致多個(gè)請(qǐng)求等待數(shù)據(jù)庫鏈接,數(shù)據(jù)庫成為性能瓶頸 |
| 2 | 樂觀鎖 | 在數(shù)據(jù)庫中添加版本號(hào)字段,修改數(shù)據(jù)時(shí)判斷版本號(hào) | ---------- |
| 3 | 分布式鎖 | 分布式鎖是在業(yè)務(wù)代碼中手動(dòng)獲取鎖,并在業(yè)務(wù)處理完成后釋放鎖,在這一過程中其他線程無法獲取鎖 | 對(duì)同一商品的秒殺會(huì)出現(xiàn)多個(gè)線程等待分布式鎖,系統(tǒng)吞吐量下降 |
| 4 | FIFO 隊(duì)列 | 引入串行化隊(duì)列將所有的寫數(shù)據(jù)庫的請(qǐng)求在隊(duì)列里邊穿行化執(zhí)行 | 性能受限于隊(duì)列處理機(jī)處理性能和DB的寫入性能中最短的那個(gè) |
| 5 | Redis原子操作 | 利用redis的事務(wù)特性,將庫存數(shù)據(jù)緩存中redis中。秒殺庫存直接操作redis,異步更新數(shù)據(jù)到db | 保證數(shù)據(jù)一致性 |
ThreadLocal原理以及oom
ThreadLocal是操作線程的局部變量入口,可以為每個(gè)線程提供一個(gè)獨(dú)立的變量副本。
ThreadLocal原理
ThreadLocal類在線程中聲明,要注意不同實(shí)例的ThreadLocal 存儲(chǔ)的變量副本不同。原理是ThreadLocal是一個(gè)操作線程本地變量ThreadLocalMap(一個(gè)Entity數(shù)組存儲(chǔ)數(shù)據(jù),可以理解為HashMap)的入口,并且以ThreadLocal 實(shí)例this作為key(弱引用);存儲(chǔ)的具體值value為強(qiáng)引用。
ThreadLocal產(chǎn)生oom原因
ThreadLocalMap的生命周期于線程的生命周期一致,當(dāng)應(yīng)用ThreadLocal的對(duì)象被回收時(shí),ThreadLocalMap還持有ThreadLocal的弱引用以及value的強(qiáng)引用;弱引用會(huì)在下次垃圾回收時(shí)回收,但強(qiáng)應(yīng)用value無法回收 造成泄漏。
HashMap實(shí)現(xiàn)原理
數(shù)組+鏈表的散列存儲(chǔ)結(jié)構(gòu),數(shù)組初始容量16,擴(kuò)容因子0.75;超過最大存儲(chǔ)容量則進(jìn)行2被擴(kuò)容處理;如果鏈表length>8 hash碰撞沖突太多,轉(zhuǎn)換為紅黑樹存儲(chǔ)(查詢效率高于鏈表)。