某大佬的20+公司面试题总结和自己的补充
附上原文鏈接(在此基礎上自己做了補充和修改。)
ZooKeeper
1. CAP定理
C:一致性(讀操作總能讀到以前的寫操作)
A:可用性(在單臺機器出錯時,仍然能正常工作,不用遷移到其他機器)
P:分區容錯性 (異常情況下仍然能滿足CA)
該理論指出一個分布式系統不可能同時滿足CAP,ZooKeeper保證了CP,A的話在Leader選舉時會丟失部分請求
2. ZAB協議
分為消息廣播(半數follower收到請求即commit)和崩潰恢復(leader崩潰后選舉leader的過程)
3. Leader選舉算法和流程
每個ZooKeeper都有兩個Id,一個是代表自己的Pid,一個是代表本身所存儲的數據的Zid,
一開始還沒有leader也沒有數據的時候會選舉最大的Pid當leader
當運行突然崩潰時,先每個都選舉自己,廣播自己的Pid和Zid,然后收到的機器廣播最大的那個Zid對應的Pid,當半數+1ZooKeeper同意的時候即成為Leader
Redis
1. Redis的應用場景
緩存、簡單消息隊列、分布式鎖、共享session。
2. Redis支持的數據類型(必考)
String(SDS字符串,簡單key-value,并發計數,簡單緩存),
List(zipList,LinkedList,雙向隊列,可以用作消息隊列,可以先進先出,也可以先進后出),
Set(intSet,HashTable,交并合集),
ZSet(ZipList,SkipList,熱搜榜一類,有排名的Set集合,事實上還用Hashtable存了key-分值),
Hash(ZipList,HashTable,rehash概念、提高負載因子,符合多重 key的情況,比如用戶的購物車?)
3. zset跳表的數據結構(必考)
首先實現一個單項鏈表,然后在此之上比如說每隔一個節點指向往后數數第二個節點。這樣的跳層有很多層
查詢方式為,先跳,如果大于了要查的分值,就往下一層查。
補充:跳表能用紅黑樹實現嗎,跳表的自平衡怎么實現?
紅黑樹沒法實現區間查詢,跳表可以查到一個之后再前后查,時間復雜度為O(nlogn)
跳表是通過隨機函數來維護索引與原始鏈表大小之間的平衡
4. Redis的數據過期策略(必考)
比如1.每隔100ms,查詢一部分數據,過期就刪除
2.查詢的key是過期的,刪除
當內存不夠使
對設置了過期時間的key:
隨機刪除、刪除快要過期的、刪除最不常用的、刪除一段時間最少使用的
對沒設置過期的key:
隨機刪除、刪除最不常用的,刪除最少使用的
或者直接報錯
5. Redis的LRU過期策略的具體實現
維護了一個大小固定的pool,每次隨機取值,將lru值最小的放到pool里來
6. 如何解決Redis緩存雪崩,緩存穿透問題
雪崩(隨機過期時間、永不過期)、
穿透(表示惡意請求,在系統端判斷是否符合規則,比如id<0,布隆過濾器)、
擊穿(查詢加for update,永不過期)
7. Redis的持久化機制(必考)
RDB(內存快照),比較快,存儲的是內容,可以BGSave,fork一個子進程存儲,對于Slave可以一開始用這個同步,之后再以aof的形式同步,開啟時會影響并發性能。進行BGSave時服務可能會暫停幾秒(需要注意)
AOF(AppendOnlyFile),比如每隔一秒將操作追加到log中,開啟aof會導致吞吐量降低,但是比RDB可以更完整的保護數據,可以將AOF文件轉成RDB,
8. Redis的管道pipeline
減少TCP連接次數,由客戶端緩存一部分命令后一次性發送。
9.Redis和memcached的區別
redis支持多種數據結構,支持系列化,key-value可存儲上限為1G,單核
memcached只支持String,不支持序列化,value大小最大為1MB,支持多核
10.Redis并發競爭key的解決方案
比如要set一個key,順序為234 ,沒加鎖變成了432
zookeeper的分布式鎖實現(監聽前面一個節點,當自己為第一個節點時,獲得鎖)
1.redis的分布式鎖實現(setnx+看門狗(比如當key過期快到的時候還沒有delete,自動續時))
2.消息隊列串行執行
11.Redis與Mysql雙寫一致性方案
先更新mysql再刪除reids,或者直接串行執行
Mysql
1. 事務的基本要素
原子性,隔離性,一致性,持久性
2. 事務隔離級別(必考)
Uncommited 臟讀
commitedread 不可重復度
repeatedtable 幻讀(mysql默認)
seriazable
3. 如何解決事務的并發問題(臟讀,幻讀)(必考)
直接上隔離級別就可解決
讀加共享鎖,寫加排它鎖
4. MVCC多版本并發控制(必考)
Inodb多 維護了兩個字段,一個是createversion,一個是deleteversion
update時會更新createversion
讀取到一行需要滿足該事務的version大于等于createversion,而小于deleteversion
5. binlog,redolog,undolog都是什么,起什么作用
binlog記錄的是sql語句,
redolog記錄是為了保證食物安全,當數據庫掛掉之后重啟仍能通過redolog執行未完成事務
undolog記錄的是上一個版本,用來回滾和快照讀,
6. InnoDB的行鎖/表鎖
不走索引會表鎖,走索引會行鎖,for update、update,insert都是行鎖
如果索引不為主鍵索引,且索引可重復,會有間隙鎖
7. myisam和innodb的區別,什么時候選擇myisam
innodb提供事務,可以崩潰恢復,最低行鎖
myisam不支持事務,不能崩潰恢復,表鎖,
讀寫分離,讀庫可以選擇myisam
8. 為什么選擇B+樹作為索引結構(必考)
B樹非葉子節點也會存,導致b樹高度變高,io次數變多,而且葉子節點沒有指向下一個葉子節點的指針
9. 索引B+樹的葉子節點都可以存哪些東西(必考)
索引值,下一個葉子節點的開頭(范圍查詢的實現)
主鍵索引可以不用再次查詢,因為主鍵索引與數據放在一起。
普通索引需要再次查詢主鍵索引之后再得到數據
10. 查詢在什么時候不走(預期中的)索引(必考)
查詢字段中雖然為索引,但是索引大量重復
用了or,但是后面的字段沒有用到索引
11. sql如何優化
創建索引,索引字段設置成notnull ,注意不走索引的情況:%打頭的like語句,!=用> union <實現,is
null的查詢,注意最左匹配原則;再有就是去優化limit,先查id再limit,查詢別用select*,防止表修改后報錯或者查詢冗余
SQL的執行順序:from---where--group by---having---select---order by
12. explain是如何解析sql的
explain ***之后會顯示sql走的類型,掃描的行數等等,可以根據這個判斷sql
13. order by原理
利用索引的有序性獲取有序數據
14.Mysql為什么不用紅黑樹?
紅黑樹每個節點下只有兩個子節點,而硬盤IO時是按簇讀取的,兩個節點中的值可能不夠填滿簇導致每次IO的浪費,此時紅黑樹的高度會大于B+樹,導致IO次數增加。
JVM
1. 運行時數據區域(內存模型)(必考)
堆、方法區、虛擬機棧,本地方法棧、程序計數器
2. 垃圾回收機制(必考)
強引用:會爆出OOM也不會被回收
軟引用:在內存不夠的時候被回收
弱引用:每次GC都會被回收(ThreadLocal中內部類Map的key就是)
虛引用:可以用來跟蹤GC,對象準備被回收時發現他還有虛引用,會把這個虛引用加入一個引用隊列,可以觀察這個隊列中虛引用是否存在來判斷對象是否被回收了。
3. 垃圾回收算法(必考)
引用計數(redis就是用的這個)
GCRoots(GCRoots可以簡單記憶為,如果被刪就一定會影響程序運行的對象,比如有虛擬機棧/本地方法棧中的引用對象,synchronized持有的對象,方法區中的靜態對象、常量)
分代收集
標記清除(內存泄漏)
標記整理
復制(一般不用在老年代,太耗時,且浪費空間)
補充:OOPMap和RememberSet
OOP是棧中所存儲的是引用的堆中的對象,可以快速枚舉GCRoots
RememberSet是為了加快新生代的GCRoots,他保存的是老年代中對象引用的新生代對象,
此時真正的新生代的GCRoots為 “新生代GCroot+rememberSet里的對象”
G1收集器將堆分為各個region,但是難免會有各個region互相引用的情況,所以G1也用到了RememberSet
4. Minor GC和Full GC觸發條件
MinorGC:Eden區滿
fullgc:大對象直接 到老年代,老年代空間不足,system.gc,minorgc后發現老年代大剩余空間大小小于平均每次從新生代進入老年代的值
5. GC中Stop the world(STW)
CMS會在找GCroot時和第二次查找時STW ,查找完畢就結束STW開始清理垃圾
G1會在找GCRoot時和第二次查找時STW,需要等垃圾清理完才結束
6. 各垃圾回收器的特點及區別
serial:單線程,復制算法,與其他的交互少的交互和上下文切換,快。
parnew:serial的多線程版本,只有這個能配合CMS
scanvage:吞吐量優先(用戶代碼執行時間/用戶代碼+垃圾回收執行的時間)
cms:老年代并發收集器,標記清除算法,停頓時間段,無法清理浮動垃圾,cpu敏感,線程數為(cpu數+3)/4,cpu少的用戶效率較低
G1 :強化分區,弱化分代的概念,本質上是復制算法,能預測時間停頓
7. 雙親委派模型
類先由父加載器加載,如果不能加載再由子類加載。
通過類本身與加載器來確定類的唯一性,防止 類被重復加載或者被修改核心的api
8. JDBC和雙親委派模型關系
簡單來說就是JDK的庫里有數據庫連接的接口,而具體實現是在各個數據庫的jar包中,又因為最高級的那個加載器默認只加載最基礎的jar包,所以只能用其他加載器去加載數據庫的jar包,此時雙親委派模型已經被破壞(可能說的比較亂,這塊我也不太理解,tomcat比較好懂一點)
補充:tomcat與雙親委派模型
tomcat中能加載多個項目,為了防止多個項目不同jar包沖突,就不可能讓父加載器都去加載這些,只能用子加載器加載各個項目的jar包。而父級加載器加載tomcat本身所需的jar包來確保安全。
tomcat還實現了jsp的熱部署,這個也是通過類加載器實現的
我們都知道jsp本質上是servlet,他被類加載器加載后,如果被修改了,此時類名還是一樣,類加載器還是會從方法區直接讀取已經存在的“緩存”來加載,這樣我們就無法實現熱部署了。那么怎么讓這個“緩存“失效呢?就是用自己的一個jsp類加載器,每個加載完成之后就卸載掉,每次加載都會去讀取最新的。如果此時使用雙親委派的話,需要把父類加載器卸載,tomcat直接掛啦。
9. JVM鎖優化和鎖膨脹過程
鎖消除 不會發生競爭的情況下JVM會把鎖消除
鎖粗化 比如簡單for循環內的synchronized會放到for循環外
偏向鎖 對象頭MarkWord01,還保存有持有的線程ID,這個MarKWord與無鎖狀態是一樣的,每次線程進來只要比較每次進來用CAS的方式把線程id設置成自己的,然后直接運行即可。
輕量級鎖 對象頭MarkWord00,由偏向鎖膨脹而來,先通過cas設置線程id,設置失敗,說明已經有其他線程拿到偏向鎖了,開始膨脹,剛才那個拿到那個偏向鎖的線程會在自己棧幀中創建一塊區域保存對象的MarkWord信息,然后用CAS指向對象的MarkWord區域。設置成功就相當于獲得了輕量級鎖
重量級鎖 在輕量級鎖CAS多次失敗后會膨脹成重量級鎖,此時其他線程過來的時候會直接掛起。喚醒需要由內核態轉換到用戶態,比較耗時。
自旋鎖,就是一直嘗試獲取鎖,建立在別的線程獲取鎖占用時間比較短的認知上。
Java基礎
1. HashMap和ConcurrentHashMap區別(必考)
線程不安全/安全
允許key-value為null/不允許
2. ConcurrentHashMap的數據結構(必考)
1.7 segement+hashtable,put時lock自帶的自旋,一定次數后阻塞。獲得size的方法比較有意思,先遍歷各個segement獲取下面的長度和修改次數,加起來后再獲取一次,相同就返回,不相同就常識多次,一定次數后加鎖
1.8 node數組+hashtable+紅黑樹,put時cas自旋,多次后synchronized,多線程會幫助擴容
兩者的get都是不用加鎖的,都用volatile修飾了
3. 高并發HashMap的環是如何產生的
1.7以前頭插法
4. volatile作用(必考)
保證可見性(這里指主內存與工作內存間的可見性),防止指令重排(指令重排也會導致可見性問題)
5. Atomic類如何保證原子性(CAS操作)(必考)
unsafe類的CAS和volatile,注意ABA問題
6. synchronized和Lock的區別(必考)
Lock底層就是AQS,是CLH隊列的增強,CLH是一個先進先出隊列,lock中把每個線程映射成CLH隊列的節點,CLH本身是自旋的,AQS在此基礎上增加了可中斷,可重入,阻塞等待而不是一直自旋,和非公平鎖,還包括資源的獨占和共享兩個功能
怎么實現非共平鎖,有什么好處?
非公平鎖簡單來說就是當線程即將進入隊列時,先cas爭取資源,若得到則運行,一定次數后仍然失敗則加入隊列,此時已失去非公平的手段,只能等前面節點來喚醒他。
公平鎖可能會導致,前一個節點釋放后,喚醒下一個節點,此時線程還在由內核向用戶態轉變,需要較多的時間,而非公平鎖可以減少這種情況的發生。
7. 為什么要使用線程池(必考)
減少開銷,方便管理
8. 核心線程池ThreadPoolExecutor的參數(必考)
核心線程、最大線程、消息隊列、存活時間、拒絕策略
9. ThreadPoolExecutor的工作流程(必考)
來一個先到核心線程,核心線程滿了到消息隊列,消息隊列滿了最大線程還沒滿,就建非核心線程工作
10. 如何控制線程池線程的優先級
image.png
11. 線程之間如何通信
鎖、信號
12. Boolean占幾個字節
百度到的 1或4
13. jdk1.8/jdk1.7都分別新增了哪些特性
1.8:lanmbd表達式,default關鍵字,紅黑樹,尾插法,concurrenthashmap的node數組
1.7:不太了解,只知道1.7將String常量池(我更喜歡把它叫做String的對象池)放到堆中
14. Exception和Error
Exception可以catch后處理,比如IOexception,出錯后程序仍能運行
error是非檢查性異常,比如OOM,
補充:
簡單說說怎么讓三個線程循環打印
1.new 三個 semaphere ,一個為1,其他為0.當A線程執行時對自己的semaphere執行acquire方法,執行完畢后對下一個線程的semaphere執行release。
不多比比,上鏈接
如果讓你用三個線程循環打印ABC,你有幾種寫法?
Spring
1. Spring的IOC/AOP的實現(必考)
ioc:beanfactory,在用到的時候加載到concurrenthashmap中,如果對象需要其他依賴,會遞歸實現里面的依賴。applicationcontext就是在容器加載的時候就把全部的bean放到concurrenthashmap中啦
aop:切面編程,一般是將可復用的方法在切點前后執行,實現方式有aspectj(靜態織入),cglib和jdk動態代理
順帶一提,dubbo中用了裝飾器把invoker包裝成wrapper
2. 動態代理的實現方式(必考)
cglib:利用asm框架,把代理對象的class文件加載進來之后修改其字節碼生成子類。
JDK:利用反射機制生成一個實現代理接口的匿名類
image.png
?image.png
補充:2.9bean的創建流程
1.獲取bean的名字
2.從緩存中查詢是否有這個bean
3.沒有的話就需要通過反射創建bean的實例(注意此時bean為空,里面東西都沒注入)
4.標記這個bean已經被創建了(此時可能會有循環依賴的問題,Spring用三級緩存來解決,提前將bean曝光)
5.遞歸獲取依賴的其他的bean
6.給當前bean綁定屬性
3. Spring如何解決循環依賴(三級緩存)(必考)
構造器(初始化與賦值沒法分開)與prototype(沒有實現三級緩存)會報錯
三級緩存分別為1.初始化完成的bean(singletonObjects)2.實例化的bean(尚未綁定屬性,earlySingletonObjects)3.beanfactory(singletonFactories)
比如有兩個beanA和B循環依賴
在A的實例化階段標記,將自己曝光到第三級緩存中,發現自己依賴B,去初始化B,B初始化過程中發現自己依賴A,從第三級緩存中getObject拿到A(注意此時A只是實例化完成,并沒有初始化),此時B順利進行初始化,將自己放到一級緩存中,此時返回A中,A順利拿到B,完成了初始化階段,放到了一級緩存。
4. Spring的后置處理器
image.png
5. Spring的@Transactional如何實現的(必考)
也是通過AOP實現的,順帶一提,如果方法B由@Transactional修飾,而A方法沒有此注解,此時A去調用方法B,@Transactional失效
6. Spring的事務傳播級別
image.png
7. BeanFactory和ApplicationContext的聯系和區別
beanfactory:懶加載,
applicationcontext:繼承了beanfactory接口,比beanfactory功能更多,加載時全部加載
其他
1. 高并發系統的限流如何實現
2. 高并發秒殺系統的設計
3. 負載均衡如何設計
某37互娛一面節選(Lucene篇)
1.Lucene為什么比數據庫快?
mysql的索引只是存儲field的內容(如果過長,只是存前多少位的內容為索引)并沒用分詞
es存儲的是分詞以后的索引,每個詞都在哪些文檔中出現過。
如果是搜索 keyword這種基本沒啥影響
但是如果是mysql的like "%word%" mysql全表查,es只需要查"word"這個詞包含的文檔id 速度明顯不是一個級別。
2.什么是倒排索引?
簡單理解就是將文章分詞后,用分出來的詞連接一個表,這個表里面是出現過這個詞的文章列表,可以根據這種方法快速查詢一個詞之后定位到文章,而不用去每個文章查這個詞。
3.倒排索引有哪幾部分?分詞屬于那一部分(不確定)
暫時理解為三部分,單詞id,單詞,倒排列表
?image.png
其他補充:
網絡:
TCP和UDP的區別?
TCP保證數據安全,以流的形式傳輸,一對一雙全工,能保證數據順序
UDP不保證數據安全,以數據報的形式傳輸,一對多,不保證數據順序
TCP是怎么保證安全的?
校驗和
應答機制
超時重傳
擁塞控制
流量控制
https和http的區別?
https:443端口,在TCP/IP協議上封裝了一層TCL/SSL,以數字證書的形式來保證數據安全
(將用戶數據hash后由公鑰加密成密文,拿到報文后解密密文,并在次將數據hash,比較數據是否相同,第一次傳輸用RSA得到對稱加密的秘鑰,之后都用對稱加密)
http:80端口,明文傳輸,無狀態
get/post區別?
本質上是無區別的,
在瀏覽器端,get一般由url調用,順帶一提url的限制也是瀏覽器的原因,事實上http標準協議對url的長度沒有限制,而post一般由表單調用
在restful規范中,get被認為是冪等的,用來請求數據,而post不冪等,用來實現資源的創建
Http請求的完整過程
1.DNS解析,先從瀏覽器緩存、內存緩存、host文件、DNS服務器一步步把url解析成ip地址
2.拿到ip地址之后如果是自己網段的,一般路由器里都有對應的mac地址,可以直接獲得然后三次握手建立TCP連接,如果不是自己網段的,還需要發到網關,由arp協議得到mac地址。因為七層模型都是上層依賴下層,你想傳輸肯定得把網絡和數據鏈路層搞定。
3.建立起TCP連接后就可以發送HTTP請求了,這個請求到了服務端可能會有負載均衡、重定向,
4.處理完請求后把請求返回,由瀏覽器解析數據時發現還有一些靜態資源比如CSS JS或圖片,又會發起另外的請求,這就是后話了。
5.處理完成后B/S架構不像C/S,一般都是短連接,四次揮手就關閉了。
為什么連接的時候是三次握手,關閉的時候卻是四次握手
四次握手是因為對比與握手的被動接收方,他還需要一次握手傳輸未傳輸完的信息來保證信息的完整性。
cookie和session的區別
cookie保存在瀏覽器端,一般有4BK的大小限制,cookie會有cros的安全問題,簡單來說就是別的惡心請求拿到了cookie之后每次請求都帶上,解決方法是用token或者直接禁用cookie,使用token可以讓特定的請求帶上而不是每次請求都帶上。
session保存在服務器端,需要用url或者cookie請求sessionid拿到,
xss攻擊和ddos?
xss其原理是攻擊者向有XSS漏洞的網站中輸入惡意的 HTML 代碼,當用戶瀏覽該網站時,這段 HTML 代碼會自動執行
ddos 簡單來說就是大量請求去攻擊一個公用接口,使服務器負載上升
什么是 DDoS 攻擊?
你知道的協議有哪些,在哪個層,有什么用?
簡單挑幾個記吧。。 TCP IP ARP RAPR PPPOE SSL HTTP FTP SMTP
?image.png
常見狀態碼及原因短語
1XX請求成功,正在處理
2XX請求成功,已經處理
3XX 重定向
301永久重定向
302臨時重定向
4XX
400 請求語法錯誤
403 服務被拒絕
404頁面不存在
5XX
500服務器內部錯誤(報錯了)
502 服務不可用
計算機系統
進程和線程的區別
進程是資源分配的最小單位,進程間不共享資源,通信困難
線程是cpu執行的最小單位,線程共享本進程的資源如內存、I/O、cpu。同一時間內同一個cpu只能執行一個線程。
進程的調度算法
時間片、先來先服務、最短時間、優先級
什么是虛擬內存
虛擬內存是為了解決如今在有限的內存空間加載較大的應用程序,根據需要在磁盤和主存之間來回傳送數據,通過段頁表的形式,先在虛擬內存中取一段連續的內存空間,再將這段內存空間映射到主內存中,此時主內存空間的程序段可以不連續,我們可以用頁表的形式找到他。
進程間的通信方式
匿名管道(fork,只能父子進程通信)
有名管道(在內核申請一塊區域,任何進程都可同信)
信號(信號是進程間通信機制中唯一的異步通信機制,內核進程可以利用他通知用戶空間進程發生了哪些系統事件)
信號量(本質是個計數器,用來同步)
socket(首先創建套接字,然后綁定一個端口再監聽套接字,可以通過網絡連接不同計算機上的進程進行通信)
共享內存區(快,需要考慮并發情況)
死鎖怎么形成的,怎么解決死鎖
請求保持,互斥,循環等待,不可剝奪
解決方案:設置優先級、請求一段時間后阻塞,
死鎖預防(用戶需要一次性請求全部資源,),檢測到死鎖后強行剝奪進程資源
Dubbo
什么是spi?dubbo對其做了什么改動?
spi全名叫server provider interface,是一種服務發現機制,可以在運行時,通過全限定路徑名,動態的加載接口的實現類。
dubbo在這個基礎上做了擴展,比如說jdk的spi,他會不管你需不需要用到這些類,只要你啟動就加載進來,而我們一些方法就想用到他的時候再用反射來加載,就像spring的beanfactory一樣。
此外,在如果一個類需要擴展的話,dubbo用裝飾者模式來實現了對類的擴展,相當于aop的實現。
服務暴露流程和引用流程?
首先dubbo有幾個角色,provider,consumer,注冊中心和監控中心
簡單來說就是provider將接口暴露,把服務注冊到注冊中心,由consumer訂閱注冊中心,在啟動的時候在注冊中心找到發布的接入入口,注冊到consumer服務里面,相當于創建了一個代理對象把服務間的通信封裝成了一個對象的調用。底下涉及到了網絡通信、協議的轉換等。
具體一點:
服務暴露:一開時就是解析一些配置文件,然后有一個serviceBean來執行暴露邏輯,里面主要涉及到protocal協議類,這個servicebean在初始化完成的時候會把那些參數注入進來,然后到ioc容器初始化完成的時候,開始來暴露方法,把要注冊的方法封裝成一個服務的執行對象invoker,先把這個放到自己的緩存中,通過protocal協議類去把invoker通過協議暴露給外部。
服務引用:
引用與服務暴露類似,一開始也是初始化配置,然后有一個ReferenceBean來執行引用邏輯,主要利用RegistryProtocol完成provider的訂閱、自己本身consumer的注冊、和執行對象invoker的創建(這里訂閱完成后如果有變動會調用notify方法去注冊和修改緩存里的invoker),把url和invoker的映射關系加到緩存之后還沒完,根據負載均衡算法拿到要執行的invoker后,動態代理生成代理類,通過代理類來完成請求遠程dubbo服務并獲取響應結果的功能。
dubbo的負載均衡機制?
輪詢、加權輪詢、一致性哈希、隨機、最少活躍數
dubbo的容錯機制?
廣播 (一個報錯就失敗,用于更新各個provider的本地資源信息)
多次發送(有一個成功就行,高時效性的讀)
失敗后重試(冪等)
失敗后報錯(不冪等)
失敗后不報錯記錄日志(審計日志)
失敗后按照配置策略一段時間后重試(消息通知)
dubbo支持的協議?
灰度發布了解嗎?
version標簽為*,按照負載均衡的機制來找機器調方法,一部分機器更新為最新版
消息隊列
消息隊列的作用?
異步:比如訂單服務與下單后送的優惠券服務,兩者異步執行。
削峰:大量寫操作,可以用消息隊列削峰。
解耦:仍然是訂單服務和優惠券服務,減少各個系統間的耦合,本系統只保證本系統的實現和消息隊列的落地,別的系統的落地由消息隊列來保證。
image.png
kafka的角色組成?
image.png
?Producer:服務生產者
Consumer:服務消費者(注意下文與partition的關系)
Broker:代理,可以看作是一個kafka的實例,由多個Broker可以組成一個集群Cluster。一個Broker中還包含Topic(主題)和Partition(分區)的概念
Topic:Producer 將消息發送到特定的主題,Consumer 通過訂閱特定的 Topic(主題) 來消費消息。
Partition:分區屬于Topic的一部分,一個 Topic 可以有多個 Partion,在每個Broker中都有他的全部信息(高可用),而各個Consumer也可以去不同的partition去讀取。
重要:如果有三個partition,四個consumer,其中一個consumer會空閑。
kafka怎么保證高可用?
簡單來說,就是備份分區僅僅用作備份,不做讀寫。如果某個Broker掛了,會選舉其他的partition來作為主分區。
如果重復消費/消息消費失敗怎么辦?怎么保證冪等?
此時就需要操作保證請求的冪等。 消息消費失敗會有重試機制去保證他成功。
冪等的實現可以說多種多樣。
1.全局唯一id
比如用戶付費成功(流水表里面有唯一id),然后用消息隊列調用其他業務(其他業務中會有流水表唯一id字段),可以先去查這個id存不存在,不存在就執行。
2.表中狀態字段
比如訂單表中有一個是否已支付的字段,去查的時候可以通過這個字段來決定是否執行。
3.唯一索引實現insert的冪等
比如已經創建流水id,可以把這個設置成唯一索引,其他再次insert時就會報錯。
再比如通過全局唯一id和用戶id設置成聯合唯一索引,可以實現秒殺場景下,一個用戶只能購買一件的需求。
3.redis實現冪等
比如發驗證短信的場景,先獲取一個token,保存在redis中,操作加入到消息隊列,然后判斷下redis中是否有這個token,有的話就消費并且把reids中的token刪除,沒有的話就不執行。
怎么保證消息的有序執行?
1、當消息加入到一個partition的時候,都是增量添加,所以都是有序的,所以可以設定只有一個partition。(不推薦這種方法,失去了kafka的高可用)
2、指定partition發送,Kafka 中發送 1 條消息的時候,可以指定topic, partition, key,data(數據) 4 個參數。如果你發送消息的時候指定了 partion 的話,所有消息都會被發送到指定的 partion。并且,同一個 key 的消息可以保證只發送到同一個 partition,比如我們可以把唯一訂單號作為key,這樣一個訂單的操作就能保證順序消費了。
消息如何保證不丟失?
kafka在partition有數據進來的時候會先緩存一部分,等數據量足夠多或者等待一定時間再批量寫到磁盤的消息日志上。
消息積壓怎么辦?
擴展機器數量,創建新的topicB ,設定10個partition,之前A的消費者邏輯改為獲取到topicA的消息之后,發topicB的消息,然后新的10臺機器來處理topicB的數據,這樣效率是以前的3倍。
轉載自:https://www.jianshu.com/p/a61f012e84d5
總結
以上是生活随笔為你收集整理的某大佬的20+公司面试题总结和自己的补充的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 看完这篇文章,我奶奶都懂了https的原
- 下一篇: IDEA中常用快捷键整理及重置快捷键