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