2021.03.01 餓了么一面
1.1 使用dubbo遇到過的問題
1)dubbo序列化的問題
(1)序列化和反序列化
任何一個對象從一個JVM傳輸到另一個JVM,都要經過序列化為二進制數據(或者字符串等其他格式,比如JSON),然后在反序列化為Java對象,這最后都是通過二進制的數據在不同的JVM之間傳輸(一般是通過Socket和二進制的數據傳輸),本文定義一個比較符合工作中。
dubbo是采用Hessian(比jdk自帶反序列化高效)進行反序列化的,該反序列化創建對象時,會取參數最少的構造方法來創建對象,構造方法參數設置默認值,基本類型設置為相應基本類型的默認值,不是基本類型設置為null(就是這點,才導致我上面的構造方法出現空指針,進而導致該對象無法實例化)
dubbo在進行反序列化時,如果找不到對象,會被反序列化成HashMap,給出類找不到的warn,具體的實現可研究com.alibaba.com.caucho.hessian.io.SerializerFactory類。
(2)無法獲取到父類名稱相同的屬性
最近工作中遇見了一個小問題,在此記錄一下,大致是這樣的,有一父類,有一個屬性traceId,主要是記錄日志號,這樣可以把所有日志串起來,利於排查問題,所有的pojo對象繼承於此,但是其中一同事在子類pojo中也增加了這一個屬性,在消費者端給traceId設置了值,但經過序列化解析后,提供者端這個traceId時,值為空,解決問題很簡單啊,把子類中的traceId屬性去掉搞定。
這個類的構造方法里調用了這樣的方法getFieldMap,把里面本類和父類的所有方法放到一個fieldMap里,因為是HashMap,為了保證方法名不覆蓋,這個方法里做了一個操作就是fieldMap.get(field.getName()) != null,有的話就繼續循環下去不覆蓋,這樣的話如果有同名的方法,那只有子類的方法在里面。還有這個類Hessian2Input要說下,其中的方法readObjectInstance,它會取到本類和父類的所有方法放到一個數組fieldNames下,這些說完了說到這里面反序列化的方法JavaSerializer的readObject,是按fieldNames數組循環取值,在流里面挨個取出來,一直賦給本類的set方法,先是有值的,到父類時,取到的為空,就把本類的值覆蓋了。到這里原因就清楚了。
(3)泛型的
對於泛型的ComplexModel,Hessian是可以正確的序列化和反序列化的,這讓我納悶了,既然泛型是編譯時的行為,為什么序列化和反序列化能夠成功?
我的理解:對於JVM而言,運行時沒有泛型信息,也就是說不管是否使用泛型,它的字節碼是完全一樣的,當把一個沒有泛型信息的對象序列化為二進制數據,然后再把它反序列回來,它的數據就是反序列化前的樣子。
因此ComplexModel的List如果是Point類型的元素,那么反序列化后也是Point類型,這屬於字節碼級別的序列化和反序列化。
反序化時為什么能夠知道List元素的類型呢?原因是在序列化時,List中的每個元素的類型都會作為序列化的數據的一部分,這部分類型信息就是反序列化到正確類型的依據
2)傳輸報文最大限制
1. dubbo接口限制, 針對的是單個參數, 還是整體參數的大小呢?
- 1. 經過測試,大小限制針對整體參數大小.
2. 如何解決?
- 1. dubbo默認參數大小限制為8388608(8M).
- 2. 可以通過配置修改
- 3. 配置payload屬性:dubbo.protocol.dubbo.payload=10485760
3. 另外一種方式:繞過dubbo的限制
- 大文件,都統一用第三方文件系統存儲,dubbo接口調用中,只傳遞url地址.
3)重試次數,2次
4)其他參數
背景:如果不設置dubbo解救超時時間,默認是1s,重試次數是2次,在調用dubbo接口時,會存在超過1s的接口響應時間,這時,就會重新發送請求,而在dubbo提供方邏輯還沒有走完,就會由於接口響應時間問題而造成bug,在這次事故中是對數據庫的操作幾乎同時操作造成了SqlMapClient operation; SQL []這個錯誤。
dubbo默認值:
變量名 描述 默認值 用途
DEFAULT_IO_THREADS 默認IO線程 Math.min(Runtime.getRuntime().availableProcessors() + 1, 32) 創建NettyServer和MinaServer時
DEFAULT_PROXY 默認代理, javassist 通過生成字節碼代替反射
DEFAULT_PAYLOAD 默認最大數據大小 8 * 1024 * 1024/8M 在從通道獲取數據進行編碼時判斷大小
DEFAULT_CLUSTER 默認集群容錯方案 failover
DEFAULT_DIRECTORY 默認集群目錄服務 dubbo
DEFAULT_LOADBALANCE 默認負載均衡方案 random(隨機)
DEFAULT_PROTOCOL 默認協議 dubbo
DEFAULT_EXCHANGER 默認信息交換方式 header
DEFAULT_TRANSPORTER 默認傳輸方式 netty(netty3)
DEFAULT_REMOTING_SERVER 默認遠程客戶端 netty(netty3)
DEFAULT_REMOTING_CODEC 默認協議編碼 dubbo
DEFAULT_REMOTING_SERIALIZATION 默認遠程調用序列化方案 hessian2
DEFAULT_HTTP_CLIENT protocol為hession時的默認客戶端類型 jdk
DEFAULT_HTTP_SERIALIZATION http類型默認序列化方案 json
DEFAULT_CHARSET 默認字符集 UTF-8
DEFAULT_WEIGHT 服務默認權重 1000
DEFAULT_FORKS 默認並行請求數 2
DEFAULT_THREAD_NAME 默認線程名 Dubbo
DEFAULT_CORE_THREADS 默認核心線程數 0
DEFAULT_THREADS 線程池默認線程數 200
DEFAULT_QUEUES 默認隊列數 0
DEFAULT_IDLE_TIMEOUT 默認空閑時間 600 * 1000(10分鍾)
DEFAULT_ALIVE 連接默認存活時間 60 * 1000(1分鍾)
DEFAULT_CONNECTIONS 默認連接 0
DEFAULT_ACCEPTS 默認接收 0
DEFAULT_HEARTBEAT 默認心跳時間 60 * 1000(1分鍾)
DEFAULT_TIMEOUT 請求執行默認超時時間 1s
DEFAULT_CONNECT_TIMEOUT 連接默認超時時間 3s
DEFAULT_RETRIES 默認重試次數 2
DEFAULT_BUFFER_SIZE 默認緩沖區大小 8 * 1024(8K)
1.2 redis 分布式鎖
A線程拿到分布式鎖,但是處理時間過長,然后B線程又來拿到分布式鎖,怎么處理這種情況
1.3 mysql的聯合索引,a,b,c
我用a,c查詢條件,可以走到a,b,c的索引嗎
1.4 classloader隔離
比如rocketmq引用了slf4j,其他包也引用了slf4j,但是版本不一致怎么處理
兩個不同的classloader加載相同的類,互相之間怎么通信?
不同分支加載同一個class文件會被認為是不同的class,不可直接互相訪問
比方說class A 分別被兩個分支上的classLoader 加載,分別生成a1,a2兩個實例,
如果兩個實例都持有對方的引用, 在a1 中調 a2.f();或在a2中調a1.f();都會提示class not found
但是通過接口訪問沒問題,比方說A implements IA ,不同classloader 加載的類可以通過IA的引用互訪
其原理是,classloader加載順序為從父類到子類順着繼承關系一級一級的加載,如果在加載的過程中沒有找到改class 則到父類里面尋找,平行的 classloader是不能夠互訪的。
所以,實現方法是要先用一個公共接口的jar包。這個jar包放到父類里面。也就是osgi框架級別加載。
使用自定義ClassLoader解決反序列化serialVesionUID不一致問題
就是rocketmq引用了一個jar包2.0版本的,調用了里面某個類,假設是com.xxx.classA里面的hello2方法,但是redis里面引用的是一個1.0版本的jar,里面的com.xxx.classA中沒有hello2方法,那如果類加載過程中,先由redis的classloader加載com.xxx.classA,那么rocketmq調用hello2的時候就找不到這個方法
1.5 分布式事務的原理
XA、2PC、3PC、TCC、SAGA
Seata
1.6 rocketmq消息隊列堆積問題
1.7 rocketmq的分片機制
2021.03.02 小鵝拼拼一面
對着簡歷的項目經驗問,我說項目經驗里用到了SpringBoot + Dubbo + Redis + MySQL,然后就一個個地開始問了。
1)SpringBoot
(1)SpringMVC和SpringBoot使用起來有什么區別
回答一個是少了很多配置,一個是SpringBoot把Tomcat容器集成進去了
(2)看過SpringBoot的源碼嗎?他和Dubbo的類加載區別是什么?
(3)SpringBoot是怎樣提前讀取配置給到Tomcat的?tomcat有配置過超時時間、請求協議之類的嗎?
(4)自己寫過SpringBoot starter嗎?
寫一個AutoApplication注解
(5)你說用過Apollo,那Apollo是怎么實現熱更新的?怎么熱更新Tomcat的配置?
(4)Bean的生命周期
2)Dubbo
(1)Dubbo有哪些負載均衡策略?
(2)給我講一講Dubbo的完整調用鏈。
(3)Dubbo的SPI是怎么實現的?
3)Redis
(1)Redis主要用來做什么?分布式緩存和分布式鎖。
(2)分布式緩存是先操作數據庫還是先操作緩存?分別有什么樣的問題,怎么解決?
(3)假設先操作緩存,然后服務宕機了,這個時候鎖就拿不到了怎么解決?
(4)用了哪些數據類型?String、list、set、zset主要用在什么場景?
我說zset用來做排行榜。那1億的用戶數據怎么用zset做排行榜?
(5)zset底層的實現原理是什么?
字典表+跳表。字典表用來做什么?插入一個數據,插在跳表的第幾層?
4)MySQL
事務隔離級別知道吧?
MySQL的MVCC在RC和RR上分別有什么樣的表現?你說下兩種隔離級別下的事務ID視圖?(后來問了說是活躍數和快照表)
MVCC讀取的快照數據在哪里?
undo log和redo log分別什么情形下寫入?bin log呢?
5)網絡了解過嗎?
說下TCP的四次揮手。
HTTP響應碼主要有哪些? 200,404,500
forward和redirect的響應碼是什么?302?
你用看過HTTP請求的時候當前連接狀態嗎?用什么看的。我說用過netstat,主要用來看端口是否被占用了。他說他想問的不是這個。
HTTPS的連接過程是怎樣的?證書是誰頒發的?怎么驗證證書的?
6)我們來寫一道算法題吧
剛開始是大數的一個題,我沒聽懂是什么。
他就說寫個簡單的兩個大數相加吧。
2021.03.05 永輝超市一面
1)Object里有哪些方法
2)Dubbo的一次完整調用鏈
3)有一張門店表、一張門店商品表,一張門店商品關聯表,門店商品關聯表的數據量特別大,怎么提高這張表的查詢速度?
4)HashMap 1.7和1.8的區別,什么時候鏈表轉紅黑樹,數據后來又刪除了,紅黑樹會變成鏈表嗎?
2021.03.06 微盟一面
1)項目經歷,這次主要講了信貸的項目分庫分表,引入到了這個項目
我說拆分成4庫16表,你為什么這樣分?
2)Spring是怎么解決循環依賴問題的(微盟必問,去年一面就是這個掛了)
3)數據庫的MVCC是怎么實現的
4)你們是怎樣解決redis和數據庫的數據一致性問題的?
我說先更新數據庫,再刪除redis。
那么如果這個時候並發量比較高,流量都打在redis上怎么辦?
5)你們分布式鏈路跟蹤用的什么?
6)我看你有帶團隊,你是怎樣保證團隊代碼質量的?
2021.03.06 百布一面
1)對象的HashCode是什么?兩個Person 年齡屬性值都是1,作為HashMap的key存入HashMap會保存幾條記錄?
2)Java里面是值傳遞還是引用傳遞?為什么你傳一個Integer,然后改了外面的方法感知不到?
3)ArrayList按照1.5倍擴容,如果ArrayList容量是100萬再插入時,擴容時速度會變慢嗎?
4)System開頭的方法代表什么?
5)MyBatis的Mapper接口沒有實現類,但是卻能自動注入,實現原理是什么?
6)MinoGC和FullGC的關聯關系是什么?
7)Histrix的熔斷策略是配置在客戶端還是服務端?
2021.03.08 Soul一面
1)Redis集群情況下,主從同步失敗,導致分布式鎖失效怎么處理?
redis的單點故障主從切換帶來的兩個客戶端同時執行(而不是叫同時獲取鎖的錯誤寫法)的問題
解決方案
(1)業務容忍
(2)RedLock
2)Redis的內存淘汰機制有哪幾種?
volatile lru ttl random lfu
allkey lru lfu
3)MySQL是先操作undolog還是redolog?
4)MySQL寫磁盤前會先寫到Cache里,這個原理叫什么?
checkpoint規則:checkpoint觸發后,將buffer中臟數據頁和臟日志頁都刷到磁盤。
臟數據刷盤:buffer-pool ====> redo log
臟日志刷盤:redo log buffer ====> redo log file
redo log buffer -> os buffer -> fsync函數 -> redo log file
5)你們的分布式事務一致性是怎么做的?用的什么框架?
6)給你一個100億的數據,你要怎樣分庫分表?
7)ES有用過嗎?主要用來做什么?
8)dubbo配置的連接池有哪幾種類型,區別是什么?
9)崗位描述,C端業務研發
技術棧:Dubbo、zookeeper、mysql、HBase、Mongo
2021.03.10 喜馬拉雅一面
第一面
1)Redis瘋狂地面,所有知識點
(1)怎么發現熱key?
Storm流式計算統計,判斷成熱點緩存。
zookeeper同步,放到本地緩存
(2)怎么解決熱key?
(3)redis的過期刪除策略是什么?我回答惰性+定時。
他問定期刪除是怎么實現的?定期刪除的時候拿所有的key?
2)JVM
(1)JVM怎么管理堆外內存
(2)強引用、軟引用、弱引用的實現原理是什么?分別什么時機回收?JVM是怎么知道要去回收的?
(3)你看了軟引用類的源碼里的參數,有什么啟發嗎?
(4)怎樣動態輸出GC的日志?
3)RocketMQ
(1)RocketMQ的存儲實現原理是什么?
(2)RocketMQ怎樣延時隊列的實現原理是什么?
(3)RocketMQ的事務消息實現原理是什么?
第二面
1)Redis
(1)zset的底層數據結構是什么?
HashMap + 跳表。跳表可以用紅黑樹代替嗎?
zset的range怎么實現?查詢的路徑是什么?
2)MySQL
(1)MVCC的實現原理是什么?在RC和RR的事務隔離級別下分別有什么?
(2)MySQL用B+樹,MongoDB用B樹,為什么?
(3)給我畫一下B+樹升級層級的過程
3)講一下Dubbo的client調用過程
4)Zookeeper
(1)看過Zookeeper的源碼嗎?
(2)Zookeeper的選舉過程是怎樣的?
(3)Zookeeper的ZAB算法實現原理是什么?看過ZAB的Paper嗎?
2021.03.10 叮咚一面
講了6個生產問題,問我可能的原因是什么,怎么解決?
1)A系統更新庫存,通過消息通知B系統庫存更新完成了,B系統過來反查但是發現庫存沒變化,可能原因是什么?
2)發完版本后,redis(騰訊雲上的單實例)帶寬占滿了怎么處理?
3)發現某個應用線程數占用幾萬個,怎么處理?
4)修改商品庫存,100個商品的庫存同時修改,在一個事務里做for 循環偶爾會發生死鎖,可能是什么原因?
解決方案,對商品ID排序后再操作。
5)說一下緩存和數據庫的先操作哪個,分別會有什么問題,怎么解決。
6)樂觀鎖和悲觀鎖的區別是什么,分別用在什么場景?
7)A系統一個接口會調用B、C、D三個系統的查詢接口,怎么提高A系統這個接口的查詢速度?
8)CQRS 更新和查詢分離,更新解決並發問題,查詢解決一致性問題
分布式系統就是解決並發和一致性問題
2021.03.11 比心一面
1. dubbo里的線程池是用來做什么的?什么階段用?你說有200個線程,是200個連接嗎?具體是指什么?業務線程和這200個線程是同一個線程嗎?如果不是,他們是怎么通信的呢?
2. 你剛剛說用了future,那future是怎么拿到線程的返回的?可以具體講講嗎?
3. 線程池是怎么管理線程的?怎么回收的?可以具體講講嗎?
4. 你可以手寫一個阻塞隊列嗎?
5. 數組123456右移2位變成561234,空間復雜度O(1)
用 Spring 的 @Transactional 注解控制事務有哪些不生效的場景?