面試就是這么簡(jiǎn)單,offer拿到手軟(一)—— 常見(jiàn)非技術(shù)問(wèn)題回答思路
面試就是這么簡(jiǎn)單,offer拿到手軟(二)—— 常見(jiàn)65道非技術(shù)面試問(wèn)題
面試就是這么簡(jiǎn)單,offer拿到手軟(三)—— 常見(jiàn)中間件框架面試題,es,redis,dubbo,zookeeper kafka 等
面試就是這么簡(jiǎn)單,offer拿到手軟(四)—— 常見(jiàn)java152道基礎(chǔ)面試題
一、消息隊(duì)列
1.1 常見(jiàn)消息隊(duì)列優(yōu)缺點(diǎn)
常見(jiàn)消息隊(duì)列:activemq、rabbitmq、rocketmq、kafka
消息隊(duì)列的優(yōu)點(diǎn): 解耦、異步、削峰
消息隊(duì)列的優(yōu)點(diǎn): 系統(tǒng)可用性降低、系統(tǒng)復(fù)雜性提高、一致性問(wèn)題
1.2如何保證消息隊(duì)列高可用?
1.2.1 使用kafka使用集群模式
1.2.2 確保不重復(fù)消費(fèi)
- 使用offset序號(hào)(zk實(shí)現(xiàn))
- 保證冪等性(使用數(shù)據(jù)庫(kù)表主鍵)
1.2.3 確保消息可靠性傳輸
-
如何解決消費(fèi)端弄丟問(wèn)題?
關(guān)閉自動(dòng)提交offset,改為手動(dòng)提交offset -
如何解決kafka本身弄丟的問(wèn)題?
leader宕掉
topic設(shè)置replication.factor值大于1,要求partition必須至少2個(gè)副本
kafka服務(wù)端設(shè)置min.insync.replicas值大于1,要求leader至少感知到有至少一個(gè)follower跟自己保持聯(lián)系
producer(生產(chǎn)者)端設(shè)置acks=all,每條數(shù)據(jù)必須是寫(xiě)入所有replica后,才認(rèn)為寫(xiě)入成功
producer端設(shè)置retries=MAX,一旦寫(xiě)入失敗,無(wú)限重試,卡在這里
1.2.4 如何保證保證消息順序性
- kafka保證寫(xiě)入一個(gè)partition中的數(shù)據(jù)是一定有順序的,生產(chǎn)者指定的一個(gè)key的數(shù)據(jù)一定會(huì)寫(xiě)入到一個(gè)partition中
- 消費(fèi)者從partition中取出數(shù)據(jù)也是一定有順序的
- 多線程處理時(shí)可能會(huì)順序出錯(cuò),設(shè)定內(nèi)存隊(duì)列,hash分發(fā)時(shí),同一key分到同一隊(duì)列
1.2.5 如何設(shè)計(jì)消息中間件
- 支持?jǐn)U容
- 數(shù)據(jù)落磁盤(pán)
- 可用性
- 數(shù)據(jù)可靠性
二、分布式搜索引擎
elasticsearch 即 es
2.1. es分布式架構(gòu)原理
es存儲(chǔ)數(shù)據(jù)的基本單位是索引index
index -> type -> mapping -> document -> field
1個(gè)index能被分成多個(gè)shard,分布在不同的機(jī)器上,shard類(lèi)比kafka,有主從性(備份)
寫(xiě)只能主,讀可以主從
2.2. es讀寫(xiě)流程原理
寫(xiě)入內(nèi)存buffer和translog文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-752636.html
- buffer快滿(mǎn)了或一定時(shí)間后,將buffer中數(shù)據(jù)refresh到一個(gè)新的segment file中(先進(jìn)入到os cache,一般1s執(zhí)行一次)
- refresh持續(xù)執(zhí)行后,當(dāng)translog達(dá)到一定體量時(shí),觸發(fā)commit操作(buffer中現(xiàn)有數(shù)據(jù)全部refresh到os cache中,清空buffer,將一個(gè)commit point寫(xiě)入磁盤(pán)文件,標(biāo)識(shí)對(duì)應(yīng)的segment file,將os cache中數(shù)據(jù)fsync到磁盤(pán))
- 可以調(diào)用api手動(dòng)執(zhí)行flush操作(整個(gè)commit過(guò)程即flush)
- translog也是先進(jìn)入到os cache中,默認(rèn)5s持久化操作一次
- 刪除操作,標(biāo)識(shí)del標(biāo)記,邏輯刪除,非物理刪除
- 更新操作,即先標(biāo)記原有數(shù)據(jù)del,重新寫(xiě)入一條數(shù)據(jù)
- 定期執(zhí)行merge操作,當(dāng)segment file多到一定程度的時(shí)候,es就會(huì)自動(dòng)觸發(fā)merge操作,將多個(gè)segment file給merge成一個(gè)segment file
2.3. es優(yōu)化
- 加大分配給es的內(nèi)存(數(shù)據(jù)量的體量最好小于或等于分配給es的內(nèi)存)
- 數(shù)據(jù)預(yù)熱,對(duì)于大量搜索的數(shù)據(jù),定時(shí)的查詢(xún)一次,將數(shù)據(jù)存入到es內(nèi)存中
- 優(yōu)化存入filesystem cache的數(shù)據(jù),只存入用于搜索的數(shù)據(jù)
- 冷熱分離,盡可能的將熱數(shù)據(jù)放到一個(gè)索引,冷數(shù)據(jù)放到另一個(gè)索引中去,防止熱數(shù)據(jù)被冷數(shù)據(jù)從cache中沖掉
三、分布式緩存redis
3.1 為什么要用分布式緩存?
為了高性能和高并發(fā)使用緩存(使用場(chǎng)景:數(shù)據(jù)字典)
3.2 常見(jiàn)問(wèn)題
1)緩存與數(shù)據(jù)庫(kù)雙寫(xiě)不一致
2)緩存雪崩
3)緩存穿透
4)緩存并發(fā)競(jìng)爭(zhēng)
3.3 redis介紹以及與memcached的區(qū)別
3.3.1. redis是單線程工作模型
3.3.2. redis和memcached 區(qū)別
1)Redis支持服務(wù)器端的數(shù)據(jù)操作:
Redis相比Memcached擁有更多的數(shù)據(jù)結(jié)構(gòu)和并支持更豐富的數(shù)據(jù)操作,通常在Memcached里,你需要將數(shù)據(jù)拿到客戶(hù)端來(lái)進(jìn)行類(lèi)似的修改再set回去。
這大大增加了網(wǎng)絡(luò)IO的次數(shù)和數(shù)據(jù)體積。在Redis中,這些復(fù)雜的操作通常和一般的GET/SET一樣高效。
2)集群模式:memcached沒(méi)有原生的集群模式,需要依靠客戶(hù)端來(lái)實(shí)現(xiàn)往集群中分片寫(xiě)入數(shù)據(jù);但是redis目前是原生支持cluster模式的
3.3.3. redis高可用原因
- 非阻塞IO多路復(fù)用模型
- 純內(nèi)存操作
- 避免了多線程的頻繁上下文切換問(wèn)題
3.3.4. redis數(shù)據(jù):
String、Hash、list、set、zset
3.3.5 .redis過(guò)期策略
- 定期刪除+惰性刪除
- 內(nèi)存淘汰
1)noeviction:當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí),新寫(xiě)入操作會(huì)報(bào)錯(cuò)
2)allkeys-lru:當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí),在鍵空間中,移除最近最少使用的key(這個(gè)是最常用的)
3)allkeys-random:當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí),在鍵空間中,隨機(jī)移除某個(gè)key
4)volatile-lru:當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí),在設(shè)置了過(guò)期時(shí)間的鍵空間中,移除最近最少使用的key(這個(gè)一般不太合適)
5)volatile-random:當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí),在設(shè)置了過(guò)期時(shí)間的鍵空間中,隨機(jī)移除某個(gè)key
6)volatile-ttl:當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí),在設(shè)置了過(guò)期時(shí)間的鍵空間中,有更早過(guò)期時(shí)間的key優(yōu)先移除
3.3.6. redis高并發(fā)高可用的保證
主從架構(gòu)、讀寫(xiě)分離、水平擴(kuò)容
哨兵sentinel機(jī)制
redis集群數(shù)據(jù)丟失問(wèn)題:
1)異步復(fù)制
2)集群腦裂
min-slaves-to-write 1
min-slaves-max-log 10
選舉:
slaves priority優(yōu)先級(jí) -> replica offset -> run id
3.3.7 .redis持久化
用于故障恢復(fù)
持久化方案:
AOF:每條數(shù)據(jù)寫(xiě)入一個(gè)AOF文件內(nèi),適合做熱備
當(dāng)AOF文件膨脹到一定體量時(shí),會(huì)觸發(fā)rewrite操作,基于現(xiàn)有redis數(shù)據(jù)生成一份新的AOF文件,并將原有AOF文件清除
一般AOF會(huì)每隔1秒,通過(guò)一個(gè)后臺(tái)線程執(zhí)行一次fsync操作,最多丟失1秒鐘的數(shù)據(jù)
AOF日志文件以append-only模式寫(xiě)入,所以沒(méi)有任何磁盤(pán)尋址的開(kāi)銷(xiāo),寫(xiě)入性能非常高,而且文件不容易破損,即使文件尾部破損,也很容易修復(fù)
但:
AOF日志文件通常比RDB數(shù)據(jù)快照文件更大
AOF開(kāi)啟后,支持的寫(xiě)QPS會(huì)比RDB支持的寫(xiě)QPS低
做數(shù)據(jù)恢復(fù)的時(shí)候,會(huì)比較慢
RDB:每隔一定時(shí)間,生成一個(gè)快照,適合做冷備
RDB對(duì)redis對(duì)外提供的讀寫(xiě)服務(wù),影響非常小,可以讓redis保持高性能,因?yàn)閞edis主進(jìn)程只需要fork一個(gè)子進(jìn)程,讓子進(jìn)程執(zhí)行磁盤(pán)IO操作來(lái)進(jìn)行RDB持久化即可
但:
時(shí)間間隔問(wèn)題,數(shù)據(jù)不全
3.3.8. redis橫向擴(kuò)容
redis cluster支撐N個(gè)redis master node,每個(gè)master都可掛載多個(gè)slave node
3.3.9 一致性hash算法(有虛擬節(jié)點(diǎn),為解決熱點(diǎn)數(shù)據(jù))
3.3.10 redis cluster,hash slot算法
cluster有固定的16384個(gè)hash slot,對(duì)每個(gè)key計(jì)算CRC16值,然后對(duì)16384取模,可以獲取key對(duì)應(yīng)的hash slot
redis cluster中每個(gè)master都會(huì)持有部分slot,增加一個(gè)master,就將其他master的hash slot移動(dòng)部分過(guò)去,減少一個(gè)master,就將它的hash slot移動(dòng)到其他master上去
移動(dòng)hash slot的成本是非常低的,客戶(hù)端的api,可以對(duì)指定的數(shù)據(jù),讓他們走同一個(gè)hash slot,通過(guò)hash tag來(lái)實(shí)現(xiàn)
3.3.11 緩存雪崩、穿透
3.3.12 數(shù)據(jù)庫(kù)雙寫(xiě)不一致
3.3.13 redis并發(fā)競(jìng)爭(zhēng)
分布式鎖+時(shí)間戳文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-752636.html
四、dubbo:
4.1 dubbo工作原理
第一層:service層,接口層,給服務(wù)提供者和消費(fèi)者來(lái)實(shí)現(xiàn)的
第二層:config層,配置層,主要是對(duì)dubbo進(jìn)行各種配置的
第三層:proxy層,服務(wù)代理層,透明生成客戶(hù)端的stub和服務(wù)單的skeleton
第四層:registry層,服務(wù)注冊(cè)層,負(fù)責(zé)服務(wù)的注冊(cè)與發(fā)現(xiàn)
第五層:cluster層,集群層,封裝多個(gè)服務(wù)提供者的路由以及負(fù)載均衡,將多個(gè)實(shí)例組合成一個(gè)服務(wù)
第六層:monitor層,監(jiān)控層,對(duì)rpc接口的調(diào)用次數(shù)和調(diào)用時(shí)間進(jìn)行監(jiān)控
第七層:protocol層,遠(yuǎn)程調(diào)用層,封裝rpc調(diào)用
第八層:exchange層,信息交換層,封裝請(qǐng)求響應(yīng)模式,同步轉(zhuǎn)異步
第九層:transport層,網(wǎng)絡(luò)傳輸層,抽象mina和netty為統(tǒng)一接口
第十層:serialize層,數(shù)據(jù)序列化層
工作流程:
1)第一步,provider向注冊(cè)中心去注冊(cè)
2)第二步,consumer從注冊(cè)中心訂閱服務(wù),注冊(cè)中心會(huì)通知consumer注冊(cè)好的服務(wù)
3)第三步,consumer調(diào)用provider
4)第四步,consumer和provider都異步的通知監(jiān)控中心
4.2. 支持協(xié)議
1)dubbo協(xié)議
單一長(zhǎng)連接,NIO異步通信,基于hessian作為序列化協(xié)議;適用的場(chǎng)景就是:傳輸數(shù)據(jù)量很?。看握?qǐng)求在100kb以?xún)?nèi)),但是并發(fā)量很高
2)rmi協(xié)議
走java二進(jìn)制序列化,多個(gè)短連接,適合消費(fèi)者和提供者數(shù)量差不多,適用于文件的傳輸
3)hessian協(xié)議
走h(yuǎn)essian序列化協(xié)議,多個(gè)短連接,適用于提供者數(shù)量比消費(fèi)者數(shù)量還多,適用于文件的傳輸
4)http協(xié)議
走json序列化
5)webservice
走SOAP文本序列化
4.3.dubbo負(fù)載均衡策略
1)random loadbalance 權(quán)重
2)roundrobin loadbalance 輪詢(xún)
3)leastactive loadbalance 自動(dòng)感知
4)consistanthash loadbalance 一致性hash算法
4.4.集群容錯(cuò)
1)failover cluster模式
失敗自動(dòng)切換,自動(dòng)重試其他機(jī)器,默認(rèn)就是這個(gè),常見(jiàn)于讀操作
2)failfast cluster模式
一次調(diào)用失敗就立即失敗,常見(jiàn)于寫(xiě)操作
3)failsafe cluster模式
出現(xiàn)異常時(shí)忽略掉,常用于不重要的接口調(diào)用,比如記錄日志
4)failbackc cluster模式
失敗了后臺(tái)自動(dòng)記錄請(qǐng)求,然后定時(shí)重發(fā),比較適合于寫(xiě)消息隊(duì)列這種
5)forking cluster
并行調(diào)用多個(gè)provider,只要一個(gè)成功就立即返回
6)broadcacst cluster
逐個(gè)調(diào)用所有的provider
4.5.動(dòng)態(tài)代理策略
默認(rèn)使用javassist動(dòng)態(tài)字節(jié)碼生成,創(chuàng)建代理類(lèi),但是可以通過(guò)spi擴(kuò)展機(jī)制配置自己的動(dòng)態(tài)代理策略
4.6 自設(shè)計(jì)rpc框架
注冊(cè)中心 -> 動(dòng)態(tài)代理 -> 負(fù)載均衡 -> 網(wǎng)絡(luò)通信
五、zookeeper
5.1. 適用場(chǎng)景
1)分布式協(xié)調(diào)
2)分布式鎖
3)元數(shù)據(jù)/配置信息管理
4)HA高可用性
5.2.分布式鎖
redis實(shí)現(xiàn) -> 叫做RedLock算法,是redis官方支持的分布式鎖算法
互斥(只能有一個(gè)客戶(hù)端獲取鎖),不能死鎖,容錯(cuò)(大部分redis節(jié)點(diǎn)存活這個(gè)鎖就可以加可以釋放)
1)第一個(gè)最普通的實(shí)現(xiàn)方式,如果就是在redis里創(chuàng)建一個(gè)key算加鎖
創(chuàng)建鎖 SET my:lock 隨機(jī)值 NX PX 30000
釋放鎖 一般可以用lua腳本刪除,判斷value一樣才刪除
2)RedLock算法
使用redis cluster集群,為避免上一方法redis宕機(jī)問(wèn)題
zookeeper實(shí)現(xiàn)
zookeeper保證只有一個(gè)人獲取到鎖(創(chuàng)建臨時(shí)節(jié)點(diǎn)),某一線程獲取到一個(gè)鎖后執(zhí)行一定的操作后釋放鎖,其他線程如果沒(méi)有獲取到這個(gè)
鎖就對(duì)這個(gè)鎖注冊(cè)一個(gè)監(jiān)聽(tīng)器,感知到鎖被釋放后再次重新嘗試取鎖
六、分布式session
1.tomcat + redis
在tomcat配置文件配RedisSessionManager屬性
2.spring session + redis
spring-session-data-redis.jar
jedis.jar
七、分布式事務(wù)
1.兩階段提交方案(XA方案)
有一個(gè)事務(wù)管理器,先詢(xún)問(wèn)后執(zhí)行
2.tcc方案(try、confirm、cancel)
1)Try階段:對(duì)各個(gè)服務(wù)的資源做檢測(cè)以及對(duì)資源進(jìn)行鎖定或者預(yù)留
2)Confirm階段:在各個(gè)服務(wù)中執(zhí)行實(shí)際的操作
3)Cancel階段:業(yè)務(wù)方法執(zhí)行出錯(cuò),那么這里就需要進(jìn)行補(bǔ)償,執(zhí)行已經(jīng)執(zhí)行成功的業(yè)務(wù)邏輯的回滾操作
3.本地消息表
通過(guò)zookeeper、mq和數(shù)據(jù)庫(kù)來(lái)做,數(shù)據(jù)庫(kù)中有個(gè)業(yè)務(wù)表和一個(gè)消息表
4.可靠消息最終一致性
基于mq實(shí)現(xiàn),阿里的rocketMQ
1)A系統(tǒng)先發(fā)送一個(gè)prepared消息到mq,如果這個(gè)prepared消息發(fā)送失敗那么就直接取消操作不執(zhí)行
2)如果這個(gè)消息發(fā)送成功,那么接著執(zhí)行本地事務(wù),如果成功,向mq發(fā)送確認(rèn)消息,如果失敗就告訴mq回滾消息
3)如果發(fā)送了確認(rèn)消息,那么此時(shí)B系統(tǒng)會(huì)接收到確認(rèn)消息,然后執(zhí)行本地的事務(wù)
4)mq會(huì)自動(dòng)定時(shí)輪詢(xún)所有prepared消息回調(diào)你的接口
5)如果系統(tǒng)B的事務(wù)失敗了,自動(dòng)不斷重試直到成功
5.最大努力通知
1)系統(tǒng)A本地事務(wù)執(zhí)行完之后,發(fā)送個(gè)消息到MQ
2)這里會(huì)有個(gè)專(zhuān)門(mén)消費(fèi)MQ的最大努力通知服務(wù),這個(gè)服務(wù)會(huì)消費(fèi)MQ然后寫(xiě)入數(shù)據(jù)庫(kù)中記錄下來(lái),或者是放入個(gè)內(nèi)存隊(duì)列也可以,接著調(diào)用系統(tǒng)B的接口
3)要是系統(tǒng)B執(zhí)行成功就ok了;要是系統(tǒng)B執(zhí)行失敗了,那么最大努力通知服務(wù)就定時(shí)嘗試重新調(diào)用系統(tǒng)B,反復(fù)N次,最后還是不行就放棄
八、設(shè)計(jì)一個(gè)高并發(fā)的系統(tǒng)架構(gòu)
1.系統(tǒng)拆分
2.使用緩存
3.使用mq
4.分庫(kù)分表
5.讀寫(xiě)分離
6.es
九、分庫(kù)分表
分庫(kù)分表中間件: cobar、TDDL、atlas、sharding-jdbc、mycat
range分法(按時(shí)間分) 擴(kuò)容快,但是大部分的請(qǐng)求,都是訪問(wèn)最新的數(shù)據(jù)
哈希分法(以某一字段取模分) 可以平均分配給庫(kù)的數(shù)據(jù)量和請(qǐng)求壓力,但擴(kuò)容麻煩
垂直拆分:把一個(gè)有很多字段的表給拆分成多個(gè)表,或者是多個(gè)庫(kù)上去
水平拆分:一個(gè)表的數(shù)據(jù)給弄到多個(gè)庫(kù)的多個(gè)表里去,但是每個(gè)庫(kù)的表結(jié)構(gòu)都一樣,只不過(guò)每個(gè)庫(kù)表放的數(shù)據(jù)是不同的,所有庫(kù)表的數(shù)據(jù)加起來(lái)就是全部數(shù)據(jù)
不停機(jī)遷移分庫(kù)分表:
雙寫(xiě)遷移方案
十、讀寫(xiě)分離、主從復(fù)制、同步延時(shí)問(wèn)題
10.1. 讀寫(xiě)分離
基于主從復(fù)制架構(gòu),簡(jiǎn)單來(lái)說(shuō),就搞一個(gè)主庫(kù),掛多個(gè)從庫(kù),然后我們就單單只是寫(xiě)主庫(kù),然后主庫(kù)會(huì)自動(dòng)把數(shù)據(jù)給同步到從庫(kù)上去。
10.2.主從復(fù)制
主庫(kù)將變更寫(xiě)binlog日志,然后從庫(kù)連接到主庫(kù)之后,從庫(kù)有一個(gè)IO線程,將主庫(kù)的binlog日志拷貝到自己本地,寫(xiě)入一個(gè)中繼日志中。
接著從庫(kù)中有一個(gè)SQL線程會(huì)從中繼日志讀取binlog,然后執(zhí)行binlog日志中的內(nèi)容,也就是在自己本地再次執(zhí)行一遍SQL。
10.3.主從同步機(jī)制
mysql實(shí)際上在這一塊有兩個(gè)機(jī)制,一個(gè)是半同步復(fù)制,用來(lái)解決主庫(kù)數(shù)據(jù)丟失問(wèn)題;一個(gè)是并行復(fù)制,用來(lái)解決主從同步延時(shí)問(wèn)題。
10.4.同步延時(shí)問(wèn)題
1)分庫(kù),將一個(gè)主庫(kù)拆分為4個(gè)主庫(kù),每個(gè)主庫(kù)的寫(xiě)并發(fā)就500/s,此時(shí)主從延遲可以忽略不計(jì)
2)打開(kāi)mysql支持的并行復(fù)制,多個(gè)庫(kù)并行復(fù)制,如果說(shuō)某個(gè)庫(kù)的寫(xiě)入并發(fā)就是特別高,單庫(kù)寫(xiě)并發(fā)達(dá)到了2000/s,并行復(fù)制還是沒(méi)意義
3)重寫(xiě)代碼,插入數(shù)據(jù)之后,直接就更新,不要查詢(xún)
4)如果確實(shí)是存在必須先插入,立馬要求就查詢(xún)到,然后立馬就要反過(guò)來(lái)執(zhí)行一些操作,對(duì)這個(gè)查詢(xún)?cè)O(shè)置直連主庫(kù)。不推薦這種方法,你這么搞導(dǎo)致讀寫(xiě)分離的意義就喪失了
到了這里,關(guān)于面試就是這么簡(jiǎn)單,offer拿到手軟(三)—— 常見(jiàn)中間件框架面試題,es,redis,dubbo,zookeeper kafka 等的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!