<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          oppo后端16連問(wèn)

          共 5393字,需瀏覽 11分鐘

           ·

          2022-04-28 19:47

          前言

          大家好,我是磊哥。最近有位讀者去面試了oppo,給大家整理了面試真題的答案。希望對(duì)大家有幫助哈,一起學(xué)習(xí),一起進(jìn)步。

          1. 聊聊你印象最深刻的項(xiàng)目,或者做了什么優(yōu)化。
          2. 你項(xiàng)目提到分布式鎖,你們是怎么使用分布式鎖的?
          3. 常見(jiàn)分布式事務(wù)解決方案
          4. 你們的接口冪等是如何保證的?
          5. 你們的MySQL架構(gòu)是怎樣的?
          6. 常見(jiàn)的索引結(jié)構(gòu)有?哈希表結(jié)構(gòu)屬于哪種場(chǎng)景?
          7. 給你ab,ac,abc字段,你是如何加索引的?
          8. 數(shù)據(jù)庫(kù)隔離級(jí)別是否了解?你們的數(shù)據(jù)庫(kù)默認(rèn)隔離級(jí)別是?為什么選它?
          9. RR隔離級(jí)別實(shí)現(xiàn)原理,它是如何解決不可重復(fù)讀的?
          10. 你們項(xiàng)目使用了RocketMQ對(duì)吧?那你知道如何保證消息不丟失嗎?
          11. 事務(wù)消息是否了解?場(chǎng)景題:比如下單清空購(gòu)物車,你是如何設(shè)計(jì)的?
          12. 如何快速判斷一個(gè)數(shù)是奇數(shù)還是偶數(shù),除開(kāi)對(duì)2取余呢。
          13. Spring聲明式事務(wù)原理?哪些場(chǎng)景事務(wù)會(huì)失效?
          14. 你們是微服務(wù)架構(gòu)嘛?如果你來(lái)設(shè)計(jì)一個(gè)類似淘寶的系統(tǒng),你怎么劃分微服務(wù)?
          15. 你們是怎么分庫(kù)分表的?分布式ID如何生成?
          16. 所有異常的共同祖先是?運(yùn)行時(shí)異常有哪幾個(gè)?

          1. 聊聊你印象最深刻的項(xiàng)目,或者做了什么優(yōu)化。

          大家平時(shí)做的項(xiàng)目,如果很多知識(shí)點(diǎn)跟面試八股文相關(guān)的話,就可以相對(duì)條理清晰地寫到簡(jiǎn)歷去。

          • 比如緩存數(shù)據(jù)庫(kù)相關(guān)的,查詢?yōu)榭眨阍O(shè)置了一個(gè)-1到緩存,代表數(shù)據(jù)庫(kù)沒(méi)記錄。下次判斷-1,就不查庫(kù)了,以解決緩存穿透問(wèn)題。

          • 又比如你設(shè)置緩存過(guò)期時(shí)間比較分散,解決緩存擊穿問(wèn)題,都可以條理清晰寫到簡(jiǎn)歷去,這樣面試官很可能會(huì)問(wèn)你相關(guān)的問(wèn)題,這時(shí)候就對(duì)答如流啦。

          還有平時(shí)你做的項(xiàng)目,有一些比較好的設(shè)計(jì),都可以說(shuō)一下哈,比如你是如何保證數(shù)據(jù)一致性的,怎么優(yōu)化接口性能的。

          • 如果是講優(yōu)化接口這一塊的話,其實(shí)就是緩存、分批、并發(fā)調(diào)用、異步等那幾個(gè)關(guān)鍵知識(shí)點(diǎn)。

          • 如果是代碼優(yōu)化細(xì)節(jié),你可以挑個(gè)簡(jiǎn)單的來(lái)講,比如復(fù)雜的if邏輯條件,可以調(diào)整順序,讓程序更高效,這樣會(huì)讓面試官眼前一亮哦。

          2. 你項(xiàng)目提到分布式鎖,你們是怎么使用分布式鎖的?

          一般你講述你做的項(xiàng)目時(shí),面試官會(huì)根據(jù)你項(xiàng)目涉及的一些面試點(diǎn),然后抽他感興趣的一兩個(gè)來(lái)問(wèn)。所以大家對(duì)哪些知識(shí)點(diǎn)熟悉,講述項(xiàng)目時(shí),就說(shuō)你用該知識(shí)點(diǎn),解決了什么問(wèn)題。

          • 比如,分布式鎖解決了超賣問(wèn)題。
          • 可以說(shuō)你是用什么方案保證緩存和數(shù)據(jù)庫(kù)一致性的。

          3. 常見(jiàn)分布式事務(wù)解決方案

          分布式事務(wù):就是指事務(wù)的參與者、支持事務(wù)的服務(wù)器、資源服務(wù)器以及事務(wù)管理器分別位于不同的分布式系統(tǒng)的不同節(jié)點(diǎn)之上。簡(jiǎn)單來(lái)說(shuō),分布式事務(wù)指的就是分布式系統(tǒng)中的事務(wù),它的存在就是為了保證不同數(shù)據(jù)庫(kù)節(jié)點(diǎn)的數(shù)據(jù)一致性。

          聊到分布式事務(wù),大家記得這兩個(gè)理論哈:CAP理論 和 BASE 理論

          分布式事務(wù)的幾種解決方案:

          • 2PC(二階段提交)方案、3PC
          • TCC(Try、Confirm、Cancel)
          • 本地消息表
          • 最大努力通知
          • seata

          2PC(二階段提交)方案

          2PC,即兩階段提交,它將分布式事務(wù)的提交拆分為2個(gè)階段:prepare和commit/rollback,即準(zhǔn)備階段和提交執(zhí)行階段。在prepare準(zhǔn)備階段需要等待所有參與子事務(wù)的反饋,因此可能造成數(shù)據(jù)庫(kù)資源鎖定時(shí)間過(guò)長(zhǎng),不適合并發(fā)高以及子事務(wù)生命周長(zhǎng)較長(zhǎng)的業(yè)務(wù)場(chǎng)景。并且協(xié)調(diào)者宕機(jī)的話,所有的參與者都收不到提交或回滾指令。

          3PC

          兩階段提交分別是:CanCommit,PreCommit 和 doCommit,這里不再詳述。3PC 利用超時(shí)機(jī)制解決了 2PC 的同步阻塞問(wèn)題,避免資源被永久鎖定,進(jìn)一步加強(qiáng)了整個(gè)事務(wù)過(guò)程的可靠性。但是 3PC 同樣無(wú)法應(yīng)對(duì)類似的宕機(jī)問(wèn)題,只不過(guò)出現(xiàn)多數(shù)據(jù)源中數(shù)據(jù)不一致問(wèn)題的概率更小。

          TCC

          TCC 采用了補(bǔ)償機(jī)制,其核心思想是:針對(duì)每個(gè)操作,都要注冊(cè)一個(gè)與其對(duì)應(yīng)的確認(rèn)和補(bǔ)償(撤銷)操作。它分為三個(gè)階段:Try-Confirm-Cancel

          • try階段:嘗試去執(zhí)行,完成所有業(yè)務(wù)的一致性檢查,預(yù)留必須的業(yè)務(wù)資源。
          • Confirm階段:該階段對(duì)業(yè)務(wù)進(jìn)行確認(rèn)提交,不做任何檢查,因?yàn)閠ry階段已經(jīng)檢查過(guò)了,默認(rèn)Confirm階段是不會(huì)出錯(cuò)的。
          • Cancel 階段:若業(yè)務(wù)執(zhí)行失敗,則進(jìn)入該階段,它會(huì)釋放try階段占用的所有業(yè)務(wù)資源,并回滾Confirm階段執(zhí)行的所有操作。

          TCC方案讓應(yīng)用可以自定義數(shù)據(jù)庫(kù)操作的粒度,降低了鎖沖突,可以提升性能。但是應(yīng)用侵入性強(qiáng),try、confirm、cancel三個(gè)階段都需要業(yè)務(wù)邏輯實(shí)現(xiàn)。

          本地消息表

          ebay最初提出本地消息表這個(gè)方案,來(lái)解決分布式事務(wù)問(wèn)題。業(yè)界目前使用這種方案是比較多的,它的核心思想就是將分布式事務(wù)拆分成本地事務(wù)進(jìn)行處理。可以看一下基本的實(shí)現(xiàn)流程圖:

          最大努力通知

          最大努力通知方案的目標(biāo),就是發(fā)起通知方通過(guò)一定的機(jī)制,最大努力將業(yè)務(wù)處理結(jié)果通知到接收方。

          seata

          Saga 模式是 Seata 提供的長(zhǎng)事務(wù)解決方案。核心思想是將長(zhǎng)事務(wù)拆分為多個(gè)本地短事務(wù),由Saga事務(wù)協(xié)調(diào)器協(xié)調(diào),如果正常結(jié)束那就正常完成,如果某個(gè)步驟失敗,則根據(jù)相反順序一次調(diào)用補(bǔ)償操作。

          Saga的并發(fā)度高,但是一致性弱,對(duì)于轉(zhuǎn)賬,可能發(fā)生用戶已扣款,最后轉(zhuǎn)賬又失敗的情況。

          4. 你們的接口冪等是如何保證的?

          如果你調(diào)用下游接口超時(shí)了,是不是考慮重試?如果重試,下游接口就需要支持冪等啦。

          實(shí)現(xiàn)冪等一般有這8種方案:

          • select+insert+主鍵/唯一索引沖突
          • 直接insert + 主鍵/唯一索引沖突
          • 狀態(tài)機(jī)冪等
          • 抽取防重表
          • token令牌
          • 悲觀鎖(如select for update,很少用)
          • 樂(lè)觀鎖
          • 分布式鎖

          5. 你們的mySQL架構(gòu)是怎樣的?

          大家可以結(jié)合自己公司的MySQL架構(gòu)聊聊。

          數(shù)據(jù)的庫(kù)高可用方案

          • 雙機(jī)主備
          • 一主一從
          • 一主多從
          • MariaDB同步多主機(jī)
          • 數(shù)據(jù)庫(kù)中間件

          5.1 雙機(jī)主備

          • 優(yōu)點(diǎn):一個(gè)機(jī)器故障了可以自動(dòng)切換,操作比較簡(jiǎn)單。
          • 缺點(diǎn):只有一個(gè)庫(kù)在工作,讀寫壓力大,未能實(shí)現(xiàn)讀寫分離,并發(fā)也有一定限制

          5.2 一主一從

          • 優(yōu)點(diǎn):從庫(kù)支持讀,分擔(dān)了主庫(kù)的壓力,提升了并發(fā)度。一個(gè)機(jī)器故障了可以自動(dòng)切換,操作比較簡(jiǎn)單。
          • 缺點(diǎn):一臺(tái)從庫(kù),并發(fā)支持還是不夠,并且一共兩臺(tái)機(jī)器,還是存在同時(shí)故障的機(jī)率,不夠高可用。

          5.3 一主多從

          • 優(yōu)點(diǎn):多個(gè)從庫(kù)支持讀,分擔(dān)了主庫(kù)的壓力,明顯提升了讀的并發(fā)度。
          • 缺點(diǎn):只有一臺(tái)主機(jī)寫,因此寫的并發(fā)度不高

          5.4 MariaDB同步多主機(jī)集群

          • 有代理層實(shí)現(xiàn)負(fù)載均衡,多個(gè)數(shù)據(jù)庫(kù)可以同時(shí)進(jìn)行讀寫操作;各個(gè)數(shù)據(jù)庫(kù)之間可以通過(guò)Galera Replication方法進(jìn)行數(shù)據(jù)同步,每個(gè)庫(kù)理論上數(shù)據(jù)是完全一致的。
          • 優(yōu)點(diǎn):讀寫的并發(fā)度都明顯提升,可以任意節(jié)點(diǎn)讀寫,可以自動(dòng)剔除故障節(jié)點(diǎn),具有較高的可靠性。
          • 缺點(diǎn):數(shù)據(jù)量不支持特別大。要避免大事務(wù)卡死,如果集群節(jié)點(diǎn)一個(gè)變慢,其他節(jié)點(diǎn)也會(huì)跟著變慢。

          5.5 數(shù)據(jù)庫(kù)中間件

          • mycat分片存儲(chǔ),每個(gè)分片配置一主多從的集群。
          • 優(yōu)點(diǎn):解決高并發(fā)高數(shù)據(jù)量的高可用方案
          • 缺點(diǎn):維護(hù)成本比較大。

          6. 常見(jiàn)的索引結(jié)構(gòu)有?哈希表結(jié)構(gòu)屬于哪種場(chǎng)景?

          哈希表、有序數(shù)組和搜索樹(shù)。

          • 哈希表這種結(jié)構(gòu)適用于只有等值查詢的場(chǎng)景
          • 有序數(shù)組適合范圍查詢,用二分法快速得到,時(shí)間復(fù)雜度為 O(log(N))。查詢還好,如果是插入,就得挪動(dòng)后面所有的記錄,成本太高。因此它一般只適用靜態(tài)存儲(chǔ)引擎,比如保存2018年某個(gè)城市的所有人口信息。
          • B+樹(shù)適合范圍查詢,我們一般建的索引結(jié)構(gòu)都是B+樹(shù)。

          7.給你ab,ac,abc字段,你是如何加索引的?

          這主要考察聯(lián)合索引的最左前綴原則知識(shí)點(diǎn)。

          • 這個(gè)最左前綴可以是聯(lián)合索引的最左N個(gè)字段。比如組合索引(a,b,c)可以相當(dāng)于建了(a),(a,b),(a,b,c)三個(gè)索引,大大提高了索引復(fù)用能力。
          • 最左前綴也可以是字符串索引的最左M個(gè)字符。

          因此給你ab,ac,abc字段,你可以直接加abc聯(lián)合索引和ac聯(lián)合索引即可。

          8. 數(shù)據(jù)庫(kù)隔離級(jí)別是否了解?你們的數(shù)據(jù)庫(kù)默認(rèn)隔離級(jí)別是?為什么選它?

          四大數(shù)據(jù)庫(kù)隔離級(jí)別,分別是讀未提交,讀已提交,可重復(fù)讀,串行化(Serializable)

          • 讀未提交:事務(wù)即使未提交,卻可以被別的事務(wù)讀取到的,這級(jí)別的事務(wù)隔離有臟讀、重復(fù)讀、幻讀的問(wèn)題。
          • 讀已提交:當(dāng)前事務(wù)只能讀取到其他事務(wù)提交的數(shù)據(jù),這種事務(wù)的隔離級(jí)別解決了臟讀問(wèn)題,但還是會(huì)存在不可重復(fù)讀、幻讀問(wèn)題;
          • 可重復(fù)讀:限制了讀取數(shù)據(jù)的時(shí)候,不可以進(jìn)行修改,所以解決了不可重復(fù)讀的問(wèn)題,但是讀取范圍數(shù)據(jù)的時(shí)候,是可以插入數(shù)據(jù),所以還會(huì)存在幻讀問(wèn)題。
          • 串行化:事務(wù)最高的隔離級(jí)別,在該級(jí)別下,所有事務(wù)都是進(jìn)行串行化順序執(zhí)行的。可以避免臟讀、不可重復(fù)讀與幻讀所有并發(fā)問(wèn)題。但是這種事務(wù)隔離級(jí)別下,事務(wù)執(zhí)行很耗性能。

          MySQL選擇Repeatable Read(可重復(fù)讀)作為默認(rèn)隔離級(jí)別,我們的數(shù)據(jù)庫(kù)隔離級(jí)別選的是讀已提交

          8.1 為什么MySQL的默認(rèn)隔離離別是RR?

          binlog的格式也有三種:statement,row,mixed。設(shè)置為statement格式,binlog記錄的是SQL的原文。又因?yàn)镸ySQL在主從復(fù)制的過(guò)程是通過(guò)binlog進(jìn)行數(shù)據(jù)同步,如果設(shè)置為讀已提交(RC)隔離級(jí)別,當(dāng)出現(xiàn)事務(wù)亂序的時(shí)候,就會(huì)導(dǎo)致備庫(kù)在 SQL 回放之后,結(jié)果和主庫(kù)內(nèi)容不一致。

          比如一個(gè)表t,表中有兩條記錄:


          CREATE?TABLE?t?(??
          ?????a?int(11)?DEFAULT?NULL,??
          ?????b?int(11)?DEFAULT?NULL,??
          ?????PRIMARY?KEY?a?(a),
          ?????KEY?b(b)
          ???)?ENGINE=InnoDB?DEFAULT?CHARSET=latin1;??
          ???insert?into?t1?values(10,666),(20,233);?

          兩個(gè)事務(wù)并發(fā)寫操作,如下:

          讀已提交(RC)隔離級(jí)別下,兩個(gè)事務(wù)執(zhí)行完后,數(shù)據(jù)庫(kù)的兩條記錄就變成了(30,666)、(20,666)。這兩個(gè)事務(wù)執(zhí)行完后,binlog也就有兩條記錄,因?yàn)槭聞?wù)binlog用的是statement格式,事務(wù)2先提交,因此update t set b=666 where b=233優(yōu)先記錄,而update t set a=30 where b=666記錄在后面。

          當(dāng)bin log同步到從庫(kù)后,執(zhí)行update t set b=666 where b=233update t set a=30 where b=666記錄,數(shù)據(jù)庫(kù)的記錄就變成(30,666)、(30,666),這時(shí)候主從數(shù)據(jù)不一致啦。

          因此MySQL的默認(rèn)隔離離別選擇了RR而不是RCRR隔離級(jí)別下,更新數(shù)據(jù)的時(shí)候不僅對(duì)更新的行加行級(jí)鎖,還會(huì)加間隙鎖(gap lock)。事務(wù)2要執(zhí)行時(shí),因?yàn)槭聞?wù)1增加了間隙鎖,就會(huì)導(dǎo)致事務(wù)2執(zhí)行被卡住,只有等事務(wù)1提交或者回滾后才能繼續(xù)執(zhí)行。

          并且,MySQL還禁止在使用statement格式的binlog的情況下,使用READ COMMITTED作為事務(wù)隔離級(jí)別。

          我們的數(shù)據(jù)庫(kù)隔離級(jí)別最后選的是讀已提交(RC)。

          那為什么MySQL官方默認(rèn)隔離級(jí)別是RR,而有些大廠選擇了RC作為默認(rèn)的隔離級(jí)別呢?

          • 提升并發(fā)

          RC 在加鎖的過(guò)程中,不需要添加Gap LockNext-Key Lock 的,只對(duì)要修改的記錄添加行級(jí)鎖就行了。因此RC的支持的并發(fā)度比RR高得多,

          • 減少死鎖

          正是因?yàn)镽R隔離級(jí)別增加了Gap LockNext-Key Lock 鎖,因此它相對(duì)于RC,更容易產(chǎn)生死鎖。

          9. RR隔離級(jí)別實(shí)現(xiàn)原理,它是如何解決不可重復(fù)讀的?

          9.1 什么是不可重復(fù)讀

          先回憶下什么是不可重復(fù)讀。假設(shè)現(xiàn)在有兩個(gè)事務(wù)A和B:

          • 事務(wù)A先查詢Jay的余額,查到結(jié)果是100
          • 這時(shí)候事務(wù)B 對(duì)Jay的賬戶余額進(jìn)行扣減,扣去10后,提交事務(wù)
          • 事務(wù)A再去查詢Jay的賬戶余額發(fā)現(xiàn)變成了90

          事務(wù)A被事務(wù)B干擾到了!在事務(wù)A范圍內(nèi),兩個(gè)相同的查詢,讀取同一條記錄,卻返回了不同的數(shù)據(jù),這就是不可重復(fù)讀

          9.2 undo log版本鏈 + Read View可見(jiàn)性規(guī)則

          RR隔離級(jí)別實(shí)現(xiàn)原理,就是MVCC多版本并發(fā)控制,而MVCC是是通過(guò)Read View+ Undo Log實(shí)現(xiàn)的,Undo Log 保存了歷史快照,Read View可見(jiàn)性規(guī)則幫助判斷當(dāng)前版本的數(shù)據(jù)是否可見(jiàn)。

          Undo Log版本鏈長(zhǎng)這樣:

          Read view 的幾個(gè)重要屬性

          • m_ids:當(dāng)前系統(tǒng)中那些活躍(未提交)的讀寫事務(wù)ID, 它數(shù)據(jù)結(jié)構(gòu)為一個(gè)List。
          • min_limit_id:表示在生成Read View時(shí),當(dāng)前系統(tǒng)中活躍的讀寫事務(wù)中最小的事務(wù)id,即m_ids中的最小值。
          • max_limit_id:表示生成Read View時(shí),系統(tǒng)中應(yīng)該分配給下一個(gè)事務(wù)的id值。
          • creator_trx_id: 創(chuàng)建當(dāng)前Read View的事務(wù)ID

          Read view 可見(jiàn)性規(guī)則如下:

          1. 如果數(shù)據(jù)事務(wù)IDtrx_id < min_limit_id,表明生成該版本的事務(wù)在生成Read View前,已經(jīng)提交(因?yàn)槭聞?wù)ID是遞增的),所以該版本可以被當(dāng)前事務(wù)訪問(wèn)。
          2. 如果trx_id>= max_limit_id,表明生成該版本的事務(wù)在生成Read View后才生成,所以該版本不可以被當(dāng)前事務(wù)訪問(wèn)。
          3. 如果min_limit_id =,需要分3種情況討論
          • 3.1 如果m_ids包含trx_id,則代表Read View生成時(shí)刻,這個(gè)事務(wù)還未提交,但是如果數(shù)據(jù)的trx_id等于creator_trx_id的話,表明數(shù)據(jù)是自己生成的,因此是可見(jiàn)的。
          • 3.2 如果m_ids包含trx_id,并且trx_id不等于creator_trx_id,則Read View生成時(shí),事務(wù)未提交,并且不是自己生產(chǎn)的,所以當(dāng)前事務(wù)也是看不見(jiàn)的;
          • 3.3 如果m_ids不包含trx_id,則說(shuō)明你這個(gè)事務(wù)在Read View生成之前就已經(jīng)提交了,修改的結(jié)果,當(dāng)前事務(wù)是能看見(jiàn)的。

          9.3 RR 如何解決不可重復(fù)讀

          查詢一條記錄,基于MVCC,是怎樣的流程

          1. 獲取事務(wù)自己的版本號(hào),即事務(wù)ID
          2. 獲取Read View
          3. 查詢得到的數(shù)據(jù),然后Read View中的事務(wù)版本號(hào)進(jìn)行比較。
          4. 如果不符合Read View的可見(jiàn)性規(guī)則, 即就需要Undo log中歷史快照;
          5. 最后返回符合規(guī)則的數(shù)據(jù)

          假設(shè)存在事務(wù)A和B,SQL執(zhí)行流程如下

          在可重復(fù)讀(RR)隔離級(jí)別下,一個(gè)事務(wù)里只會(huì)獲取一次Read View,都是副本共用的,從而保證每次查詢的數(shù)據(jù)都是一樣的。

          假設(shè)當(dāng)前有一張core_user表,插入一條初始化數(shù)據(jù),如下:

          基于MVCC,我們來(lái)看看執(zhí)行流程

          1. A開(kāi)啟事務(wù),首先得到一個(gè)事務(wù)ID為100
          2. B開(kāi)啟事務(wù),得到事務(wù)ID為101
          3. 事務(wù)A生成一個(gè)Read View,read view對(duì)應(yīng)的值如下
          變量
          m_ids100,101
          max_limit_id102
          min_limit_id100
          creator_trx_id100

          然后回到版本鏈:開(kāi)始從版本鏈中挑選可見(jiàn)的記錄:

          由圖可以看出,最新版本的列name的內(nèi)容是孫權(quán),該版本的trx_id值為100。開(kāi)始執(zhí)行read view可見(jiàn)性規(guī)則校驗(yàn):

          min_limit_id(100)=creator_trx_id?=?trx_id?=100;

          由此可得,trx_id=100的這個(gè)記錄,當(dāng)前事務(wù)是可見(jiàn)的。所以查到是name為孫權(quán)的記錄。

          1. 事務(wù)B進(jìn)行修改操作,把名字改為曹操。把原數(shù)據(jù)拷貝到undo log,然后對(duì)數(shù)據(jù)進(jìn)行修改,標(biāo)記事務(wù)ID和上一個(gè)數(shù)據(jù)版本在undo log的地址。
          1. 事務(wù)B提交事務(wù)

          2. 事務(wù)A再次執(zhí)行查詢操作,因?yàn)槭荝R(可重復(fù)讀)隔離級(jí)別,因此會(huì)復(fù)用老的Read View副本,Read View對(duì)應(yīng)的值如下

          變量
          m_ids100,101
          max_limit_id102
          min_limit_id100
          creator_trx_id100

          然后再次回到版本鏈:從版本鏈中挑選可見(jiàn)的記錄:

          從圖可得,最新版本的列name的內(nèi)容是曹操,該版本的trx_id值為101。開(kāi)始執(zhí)行read view可見(jiàn)性規(guī)則校驗(yàn):

          min_limit_id(100)=因?yàn)閙_ids{100,101}包含trx_id(101),
          并且creator_trx_id?(100)?不等于trx_id(101)

          所以,trx_id=101這個(gè)記錄,對(duì)于當(dāng)前事務(wù)是不可見(jiàn)的。這時(shí)候呢,版本鏈roll_pointer跳到下一個(gè)版本,trx_id=100這個(gè)記錄,再次校驗(yàn)是否可見(jiàn):

          min_limit_id(100)=因?yàn)閙_ids{100,101}包含trx_id(100),
          并且creator_trx_id?(100)?等于trx_id(100)

          所以,trx_id=100這個(gè)記錄,對(duì)于當(dāng)前事務(wù)是可見(jiàn)的,所以兩次查詢結(jié)果,都是name=孫權(quán)的那個(gè)記錄。即在可重復(fù)讀(RR)隔離級(jí)別下,復(fù)用老的Read View副本,解決了不可重復(fù)讀的問(wèn)題。

          10. 你們項(xiàng)目使用了RocketMQ對(duì)吧?那你知道如何保證消息不丟失嗎?

          一個(gè)消息從生產(chǎn)者產(chǎn)生,到被消費(fèi)者消費(fèi),主要經(jīng)過(guò)這3個(gè)過(guò)程:

          1. 生產(chǎn)者產(chǎn)生消息
          2. 消息發(fā)送到存儲(chǔ)端,保存下來(lái)
          3. 消息推送到消費(fèi)者,消費(fèi)者消費(fèi)完,ack應(yīng)答。

          因此如何保證MQ不丟失消息,可以從這三個(gè)階段闡述:

          • 生產(chǎn)者保證不丟消息
          • 存儲(chǔ)端不丟消息
          • 消費(fèi)者不丟消息

          10.1 生產(chǎn)者保證不丟消息

          生產(chǎn)端如何保證不丟消息呢?確保生產(chǎn)的消息能順利到達(dá)存儲(chǔ)端。

          如果是RocketMQ消息中間件的話,Producer生產(chǎn)者提供了三種發(fā)送消息的方式,分別是:

          • 同步發(fā)送
          • 異步發(fā)送
          • 單向發(fā)送

          生產(chǎn)者要想發(fā)消息時(shí)保證消息不丟失,可以:

          • 采用同步方式發(fā)送,send消息方法返回成功狀態(tài),即消息正常到達(dá)了存儲(chǔ)端Broker
          • 如果send消息異常或者返回非成功狀態(tài),可以發(fā)起重試。
          • 可以使用事務(wù)消息,RocketMQ的事務(wù)消息機(jī)制就是為了保證零丟失來(lái)設(shè)計(jì)的

          10.2 存儲(chǔ)端不丟消息

          如何保證存儲(chǔ)端的消息不丟失呢?確保消息持久化到磁盤,那就是刷盤機(jī)制嘛。

          刷盤機(jī)制分同步刷盤和異步刷盤

          • 同步刷盤:生產(chǎn)者消息發(fā)過(guò)來(lái)時(shí),只有持久化到磁盤,RocketMQ的存儲(chǔ)端Broker才返回一個(gè)成功的ACK響應(yīng)。它保證消息不丟失,但是影響了性能。
          • 異步刷盤:只要消息寫入PageCache緩存,就返回一個(gè)成功的ACK響應(yīng)。這樣提高了MQ的性能,但是如果這時(shí)候機(jī)器斷電了,就會(huì)丟失消息。

          除了同步刷盤機(jī)制,還有一個(gè)維度需要考慮。Broker一般是集群部署的,有主節(jié)點(diǎn)和從節(jié)點(diǎn)。消息到Broker存儲(chǔ)端,只有主節(jié)點(diǎn)和從節(jié)點(diǎn)都寫入成功,才反饋成功的ack給生產(chǎn)者。這就是同步復(fù)制,它保證了消息不丟失,但是降低了系統(tǒng)的吞吐量。與之對(duì)應(yīng)即是異步復(fù)制,只要消息寫入主節(jié)點(diǎn)成功,就返回成功的ack,它速度快,但是會(huì)有性能問(wèn)題。

          10.3 消費(fèi)階段不丟消息

          消費(fèi)者執(zhí)行完業(yè)務(wù)邏輯,再反饋會(huì)Broker說(shuō)消費(fèi)成功,這樣才可以保證消費(fèi)階段不丟消息。

          11. 事務(wù)消息是否了解?場(chǎng)景題:比如下單清空購(gòu)物車,你是如何設(shè)計(jì)的?

          事務(wù)消息主要用來(lái)解決消息生產(chǎn)者和消息消費(fèi)者的數(shù)據(jù)一致性問(wèn)題。我們先來(lái)回憶一下:一條普通的消息隊(duì)列消息,從產(chǎn)生到被消費(fèi),經(jīng)歷的流程:

          1. 生產(chǎn)者產(chǎn)生消息,發(fā)送到MQ服務(wù)器
          2. MQ收到消息后,將消息持久化到存儲(chǔ)系統(tǒng)。
          3. MQ服務(wù)器返回ACk到生產(chǎn)者。
          4. MQ服務(wù)器把消息push給消費(fèi)者
          5. 消費(fèi)者消費(fèi)完消息,響應(yīng)ACK
          6. MQ服務(wù)器收到ACK,認(rèn)為消息消費(fèi)成功,即在存儲(chǔ)中刪除消息。

          消息隊(duì)列的事務(wù)消息流程是怎樣的呢?

          1. 生產(chǎn)者產(chǎn)生消息,發(fā)送一條半事務(wù)消息到MQ服務(wù)器
          2. MQ收到消息后,將消息持久化到存儲(chǔ)系統(tǒng),這條消息的狀態(tài)是待發(fā)送狀態(tài)。
          3. MQ服務(wù)器返回ACK確認(rèn)到生產(chǎn)者,此時(shí)MQ不會(huì)觸發(fā)消息推送事件
          4. 生產(chǎn)者執(zhí)行本地事務(wù)
          5. 如果本地事務(wù)執(zhí)行成功,即commit執(zhí)行結(jié)果到MQ服務(wù)器;如果執(zhí)行失敗,發(fā)送rollback。
          6. 如果是正常的commit,MQ服務(wù)器更新消息狀態(tài)為可發(fā)送;如果是rollback,即刪除消息。
          7. 如果消息狀態(tài)更新為可發(fā)送,則MQ服務(wù)器會(huì)push消息給消費(fèi)者。消費(fèi)者消費(fèi)完就回ACK。
          8. 如果MQ服務(wù)器長(zhǎng)時(shí)間沒(méi)有收到生產(chǎn)者的commit或者rollback,它會(huì)反查生產(chǎn)者,然后根據(jù)查詢到的結(jié)果執(zhí)行最終狀態(tài)。

          我們舉個(gè)下訂單清空購(gòu)物車的例子吧。訂單系統(tǒng)創(chuàng)建完訂單后,然后發(fā)消息給下游系統(tǒng)購(gòu)物車系統(tǒng),清空購(gòu)物車。

          1. 生產(chǎn)者(訂單系統(tǒng))產(chǎn)生消息,發(fā)送一條半事務(wù)消息到MQ服務(wù)器
          2. MQ收到消息后,將消息持久化到存儲(chǔ)系統(tǒng),這條消息的狀態(tài)是待發(fā)送狀態(tài)。
          3. MQ服務(wù)器返回ACK確認(rèn)到生產(chǎn)者,此時(shí)MQ不會(huì)觸發(fā)消息推送事件
          4. 生產(chǎn)者執(zhí)行本地事務(wù)(訂單創(chuàng)建成功,提交事務(wù)消息)
          5. 如果本地事務(wù)執(zhí)行成功,即commit執(zhí)行結(jié)果到MQ服務(wù)器;如果執(zhí)行失敗,發(fā)送rollback。
          6. 如果是commit正常提交,MQ服務(wù)器更新消息狀態(tài)為可發(fā)送;如果是rollback,即刪除消息
          7. 如果消息狀態(tài)更新為可發(fā)送,則MQ服務(wù)器會(huì)push消息給消費(fèi)者(購(gòu)物車系統(tǒng))。消費(fèi)者消費(fèi)完(即拿到訂單消息,清空購(gòu)物車成功)就應(yīng)答ACK。
          8. 如果MQ服務(wù)器長(zhǎng)時(shí)間沒(méi)有收到生產(chǎn)者的commit或者rollback,它會(huì)反查生產(chǎn)者,然后根據(jù)查詢到的結(jié)果(回滾操作或者重新發(fā)送消息)執(zhí)行最終狀態(tài)。

          有些伙伴可能有疑惑,如果消費(fèi)者消費(fèi)失敗怎么辦呢?那數(shù)據(jù)是不是不一致啦?所以就需要消費(fèi)者消費(fèi)成功,執(zhí)行業(yè)務(wù)邏輯成功,再反饋ack嘛。如果消費(fèi)者消費(fèi)失敗,那就自動(dòng)重試嘛,接口支持冪等即可。

          12. 如何快速判斷一個(gè)數(shù)是奇數(shù)還是偶數(shù),除開(kāi)對(duì)2取余呢。

          判斷一個(gè)數(shù)是奇數(shù)還是偶數(shù),我們最容易想到的就是對(duì)2取余。

          if(?x?%?2?)
          //?奇數(shù)
          else
          //?偶數(shù)

          還有一種方法,就是與1相與( &1),具體實(shí)現(xiàn)如下:

          if(?x?&?1?)
          //?奇數(shù)
          else
          //?偶數(shù)

          13. Spring聲明式事務(wù)原理?哪些場(chǎng)景事務(wù)會(huì)失效?

          13.1 聲明式事務(wù)原理

          spring聲明式事務(wù),即@Transactional,它可以幫助我們把事務(wù)開(kāi)啟、提交或者回滾的操作,通過(guò)Aop的方式進(jìn)行管理。

          在spring的bean的初始化過(guò)程中,就需要對(duì)實(shí)例化的bean進(jìn)行代理,并且生成代理對(duì)象。生成代理對(duì)象的代理邏輯中,進(jìn)行方法調(diào)用時(shí),需要先獲取切面邏輯,@Transactional注解的切面邏輯類似于@Around,在spring中是實(shí)現(xiàn)一種類似代理邏輯。


          13.2 spring聲明式事務(wù)哪些場(chǎng)景會(huì)失效

          • 方法的訪問(wèn)權(quán)限必須是public,其他private等權(quán)限,事務(wù)失效
          • 方法被定義成了final的,這樣會(huì)導(dǎo)致事務(wù)失效。
          • 在同一個(gè)類中的方法直接內(nèi)部調(diào)用,會(huì)導(dǎo)致事務(wù)失效。
          • 一個(gè)方法如果沒(méi)交給spring管理,就不會(huì)生成spring事務(wù)。
          • 多線程調(diào)用,兩個(gè)方法不在同一個(gè)線程中,獲取到的數(shù)據(jù)庫(kù)連接不一樣的。
          • 表的存儲(chǔ)引擎不支持事務(wù)
          • 如果自己try...catch誤吞了異常,事務(wù)失效。
          • 錯(cuò)誤的傳播

          14. 你們是微服務(wù)架構(gòu)嘛?如果你來(lái)設(shè)計(jì)一個(gè)類似淘寶的系統(tǒng),你怎么劃分微服務(wù)?

          可以按業(yè)務(wù)領(lǐng)域、功能、重要程度進(jìn)行劃分。

          • 可以按業(yè)務(wù)領(lǐng)域,把用戶、社區(qū)、商品信息、消息等模塊等劃分。
          • 單一功能職責(zé),按功能拆分,比如訂單、支付、物流、權(quán)限。
          • 按重要程度劃分,區(qū)分核心和非核心功能,比如支付、訂單就是核心功能。

          15. 你們是怎么分庫(kù)分表的?分布式ID如何生成?

          如果是我們公司的話,使用了水平分庫(kù)的方式,就是一個(gè)用戶注冊(cè)時(shí),就劃分了屬于哪個(gè)數(shù)據(jù)庫(kù),然后具體的表結(jié)構(gòu)是一樣的。

          業(yè)界還有垂直分庫(kù),就是按照不同的系統(tǒng)中的不同業(yè)務(wù)進(jìn)行拆分,比如拆分成用戶庫(kù)、訂單庫(kù)、積分庫(kù)、商品庫(kù),把它們部署在不同的數(shù)據(jù)庫(kù)服務(wù)器。

          分表的話也有水平分表和垂直分表,垂直分表就是將一些不常用的、數(shù)據(jù)較大或者長(zhǎng)度較長(zhǎng)的列拆分到另外一張表,水平分表就是可以按照某種規(guī)則(如hash取模、range),把數(shù)據(jù)切分到多張表去。一張訂單表,按時(shí)間range拆分如下:

          range劃分利于數(shù)據(jù)遷移,但是存在數(shù)據(jù)熱點(diǎn)問(wèn)題。hash取模劃分,不會(huì)存在明顯的熱點(diǎn)問(wèn)題,但是不利于擴(kuò)容。可以range+hash取模結(jié)合使用。

          分布式ID可以使用雪花算法生成

          雪花算法是一種生成分布式全局唯一ID的算法,生成的ID稱為Snowflake IDs。這種算法由Twitter創(chuàng)建,并用于推文的ID。

          一個(gè)Snowflake ID有64位。

          • 第1位:Java中l(wèi)ong的最高位是符號(hào)位代表正負(fù),正數(shù)是0,負(fù)數(shù)是1,一般生成ID都為正數(shù),所以默認(rèn)為0。
          • 接下來(lái)前41位是時(shí)間戳,表示了自選定的時(shí)期以來(lái)的毫秒數(shù)。
          • 接下來(lái)的10位代表計(jì)算機(jī)ID,防止沖突。
          • 其余12位代表每臺(tái)機(jī)器上生成ID的序列號(hào),這允許在同一毫秒內(nèi)創(chuàng)建多個(gè)Snowflake ID。

          16. 所有異常的共同的祖先是?運(yùn)行時(shí)異常有哪幾個(gè)?

          Java 異常的頂層父類是Throwable,它生了兩個(gè)兒子,大兒子叫Error,二兒子叫Exception

          • Error:是程序?法處理的錯(cuò)誤,一般表示系統(tǒng)錯(cuò)誤,例如虛擬機(jī)相關(guān)的錯(cuò)誤OutOfMemoryError
          • Exception:程序本身可以處理的異常。它可以分為RuntimeException(運(yùn)行時(shí)異常)和CheckedException(可檢查的異常)。

          什么是RuntimeException(運(yùn)行時(shí)異常)

          運(yùn)行時(shí)異常是不檢查異常,程序中可以選擇捕獲處理,也可以不處理。這些異常一般是由程序邏輯錯(cuò)誤引起的,程序應(yīng)該從邏輯角度盡可能避免這類異常的發(fā)生。

          常見(jiàn)的RuntimeException異常

          • NullPointerException:空指針異常

          • ArithmeticException:出現(xiàn)異常的運(yùn)算條件時(shí),拋出此異常

          • IndexOutOfBoundsException:數(shù)組索引越界異常

          • ClassNotFoundException:找不到類異常

          • IllegalArgumentException(非法參數(shù)異常)

          什么是CheckedException(可檢查的異常)

          從程序語(yǔ)法角度講是必須進(jìn)行處理的異常,如果不處理,程序就不能編譯通過(guò)。如IOException、SQLException等。

          常見(jiàn)的 Checked Exception 異常:

          • IOException:(操作輸入流和輸出流時(shí)可能出現(xiàn)的異常)
          • SQLException

          最后(求關(guān)注,別白嫖我)

          如果這篇文章對(duì)您有所幫助,或者有所啟發(fā)的話,求一鍵三連:點(diǎn)贊、轉(zhuǎn)發(fā)、在看,您的支持是我堅(jiān)持寫作最大的動(dòng)力。

          參考感謝

          瀏覽 46
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费日皮视频网站 | 国产福利网站 | 激情动态图在线观看 | 免费看A片秘 免费 | 天天日天天肏 |