1.kafka的讀寫效率快的原因(詳細解釋傳送門;https://blog.csdn.net/lianggzone/article/details/112386378)
(1) 利用 Partition 實作并行處理
Kafka 是一個 Pub-Sub 的訊息系統,無論是發布還是訂閱,都要指定 Topic;
Topic 只是一個邏輯的概念,每個 Topic 都包含一個或多個 Partition,不同 Partition 可位于不同節點,
一方面,由于不同 Partition 可位于不同機器,因此可以充分利用集群優勢,實作機器間的并行處理,
另一方面,由于 Partition 在物理上對應一個檔案夾,即使多個 Partition 位于同一個節點,也可通過配置讓同一節點上的不同 Partition 置于不同的磁盤上,從而實作磁盤間的并行處理,充分發揮多磁盤的優勢,
(2) 順序寫磁盤
Kafka 中每個磁區是一個有序的,不可變的訊息序列,新的訊息不斷追加到 partition 的末尾,這個就是順序寫,
Kafka的洗掉并不是"讀-寫"這種形式,而是將Partition分為多個Segment,每個Segment對應一個物理檔案,通過洗掉整個檔案的方式去洗掉Partition 內的資料,這種方式清除舊資料的方式,也避免了對檔案的隨機寫操作,
(3) 充分利用 Page Cache
[1] I/O Scheduler 會將連續的小塊寫組裝成大塊的物理寫從而提高性能,
[2] I/O Scheduler 會嘗試將一些寫操作重新按順序排好,從而減少磁盤頭的移動時間,
[3] 充分利用所有空閑記憶體(非 JVM 記憶體),如果使用應用層 Cache(即 JVM 堆記憶體),會增加 GC 負擔,
[4] 讀操作可直接在 Page Cache 內進行,如果消費和生產速度相當,甚至不需要通過物理磁盤(直接通過 Page Cache)交換資料,
[5] 如果行程重啟,JVM 內的 Cache 會失效,但 Page Cache 仍然可用,
(4) 零拷貝技術
技術指在計算機執行操作時,CPU 不需要先將資料從一個記憶體區域復制到另一個記憶體區域,從而可以減少背景關系切換以及 CPU 的拷貝時間,
[1] 網路資料持久化到磁盤 (Producer 到 Broker)
傳統模式下:資料從網路傳輸到檔案需要 4 次資料拷貝、4 次背景關系切換和兩次系統呼叫,
① 首先通過 DMA copy 將網路資料拷貝到內核態 Socket Buffer,
② 然后應用程式將內核態 Buffer 資料讀入用戶態(CPU copy)
③ 接著用戶程式將用戶態 Buffer 再拷貝到內核態(CPU copy)
④ 最后通過 DMA copy 將資料拷貝到磁盤檔案
kafka MMap:
使用 mmap 的目的是將內核中讀緩沖區(read buffer)的地址與用戶空間的緩沖區(user buffer)進行映射,從而實作內核緩沖區與應用程式記憶體的共享,省去了將資料從內核讀緩沖區(read buffer)拷貝到用戶緩沖區(user buffer)的程序,它的作業原理是直接利用作業系統的 Page 來實作檔案到物理記憶體的直接映射,完成映射之后你對物理記憶體的操作會被同步到硬碟上,
使用這種方式可以獲取很大的 I/O 提升,省去了用戶空間到內核空間復制的開銷,
[2] 磁盤檔案通過網路發送(Broker 到 Consumer)
傳統模式:
① 首先通過系統呼叫將檔案資料讀入到內核態 Buffer(DMA 拷貝)
② 然后應用程式將內 存態 Buffer 資料讀入到用戶態 Buffer(CPU 拷貝)
③ 接著用戶程式通過 Socket 發送資料時將用戶態 Buffer 資料拷貝到內核態 Buffer(CPU 拷貝)
④ 最后通過 DMA 拷貝將資料拷貝到 NIC Buffer
kafka:
Kafka 在這里采用的方案是通過 NIO 的 transferTo/transferFrom 呼叫作業系統的 sendfile 實作零拷貝,總共發生 2 次內核資料拷貝、2 次背景關系切換和一次系統呼叫,消除了 CPU 資料拷貝
(5) 批處理
在很多情況下,系統的瓶頸不是 CPU 或磁盤,而是網路IO,
因此,除了作業系統提供的低級批處理之外,Kafka 的客戶端和 broker 還會在通過網路發送資料之前,在一個批處理中累積多條記錄 (包括讀和寫),記錄的批處理分攤了網路往返的開銷,使用了更大的資料包從而提高了帶寬利用率,
(6) 資料壓縮
Producer 可將資料壓縮后發送給 broker,從而減少網路傳輸代價,目前支持的壓縮演算法有:Snappy、Gzip、LZ4,資料壓縮一般都是和批處理配套使用來作為優化手段的,
2.redis資料主從同步
(1)全量同步:
需要在主庫上進行一次bgsave將當前記憶體的資料全部快照到磁盤檔案中,然后在將快照檔案的內容全部傳送到從節點,從節點將快照檔案接收完畢后,立即執行一次全量加載,加載之前先要將當前記憶體的資料清空,
(2)部分同步:
只同步從服務器中沒有的資料,涉及到賦值偏移量和賦值積壓緩沖區,
(3)命令傳播:
用于在master的資料庫狀態被修改時,將導致變更的命令傳播給slave,從而讓slave的資料庫狀態與master保持一致,
(4)復制擠壓緩沖區
[1] 它是master維護的一個固定長度的先進先出的記憶體佇列(FIFO),默認為1MB,當佇列長度超過時,最先進入的元素被彈出,佇列的生存時間默認為3600秒,如果master不在有與之相連接的slave,并且該狀態持續時間超過了佇列生成時間,master就會釋放該佇列,等到有需要的時候在創建,
[2] 如果從服務器與master失聯后重連成功,從服務器通過PSYNC命令將自己的賦值偏移量發送給master,master通過偏移量來決定采用全量同步還是增量同步,如果從服務器的復制偏移量之后的資料仍然存在于緩沖區中,則采用部分同步,否則采用全量同步
[3] 3.0之后增加了WAIT命令,提供兩個引數,第一個引數時從庫的數量N,第二個引數時時間t,以毫秒為單位,它標識等待wait指令之前的所有寫操作同步到N個從庫,最多等待時間t,如果t=0則表示無限等待所有操作完成
(5) 主從同步策略
剛鏈接時進行全量同步,全量同步結束后進行增量同步,當有需要是slave可觸發全量同步,但通常只會觸發增量同步,只有增量同步失敗才會嘗試全量同步,
3.redis持久化
(1) RDB
[1] Redis是一個單行程的服務,通過fork產生子行程,父行程繼續處理Client請求,子行程負責將快照寫入臨時檔案中,完成后用臨時檔案替換原有的快照檔案
[2] rdbSave函式負責將記憶體中的資料庫資料以RDB格式保存到磁盤中,如果RDB檔案已存在,那么新檔案將替換原有檔案,Rdbload用于將RDB檔案中的資料重新載入到記憶體中
[3] SAVE和BGSAVE命令的區別
① SAVE直接呼叫rdbSave,阻塞Redis主行程,直到保存完成為止,
② BGSAVE則fork出一個子行程,子行程負責呼叫rdbSave,并在保存完成之后向主行程發送信號,通知保存已完成,
③ save配置
a)save s number
s:時間單位秒 number:資料修改次數
例:save 100 10
含義:當客戶端在100秒內對資料庫中資料,進行了10次修改,則自動執行BGSAVE命令
[4] 優點
① RDB檔案緊湊,全量備份,非常適合用于進行備份和容災處理恢復,
② 生成RDB檔案時,redis柱進行會呼叫fork()產生一個紫禁城來處理所有保存作業,柱進行不需要進行任何磁盤IO操作,
③ RDB在恢復大資料集時的速度比AOF的速度快,
[5] 缺點
RDB快照是一次全量備份,存盤的是記憶體資料的二進制序列化形式資料,粗出緊湊,當進行快照持久化時,會開啟一個字進行負責快照的持久化程序,但當子行程在持久化程序中不會保存主行程的變動,可能會導致丟失資料,
(2) AOF
[1] 容寫入緩沖區,子行程寫完退出,父行程接收退出訊息后,將緩沖區AOF寫入臨時檔案,覆寫原檔案
[2] AOF協議文本,將所有對資料庫進行寫操作命令記錄到檔案中,以此達到記錄資料庫狀態的目的
[3] AOF生成檔案程序
① 命令傳播:Redis將執行完的命令、引數等資訊發送到AOF程式中
② 快取追加:根據接收到的命令資料,將命令轉換為網路通訊協議的格式,然后將協議內容追加到服務器的AOF快取中
③ 檔案寫入:AOF快取中的內容被寫入AOF檔案末尾,如果社零的AOF保存條件被滿足的話,呼叫fsync函式或fdatasync函式,將寫入的內容真正保存到磁盤
[4] sync頻率配置:
通過appendfsync引數進行控制,有三個值
① AOF_FSYNC_NO 不保存
② AOF_FSYNC_EVERYSEC 每秒保存一次(默認)
③ AOF_FSYNC_ALWAYS 每執行一個命令保存一次
[5] AOF檔案加載程序
① 創建一個不帶網路連接的偽客戶端(fake client)
② 讀取AOF所保存的檔案,并根據內容還原出命令及引數等資訊
③ 根據命令使用偽客戶端進行執行
[6] 優點
① AOF可以更好的保護資料不丟失,一般AOF會間隔1s,通過一個后臺程式執行一次fsync操作,所以最多智慧丟失1s的資料,
② AOF日志檔案沒有任何磁盤尋址開銷,寫入性能搞,檔案不容易破損
③ AOF日志檔案及時過大的時候,出現后臺重寫操作也不會影響客戶端,
④ AOF日志檔案可以通過修改錯誤操作的日志檔案內容的方式回復所有資料,
[7] 缺點
① 對于同一份資料來說,AOF日志檔案通常比RDB資料快照檔案更大,
② AOF開啟后,支持的寫QPS會比RDB支持的寫QPS低,
③ AOF通過日志回復資料,不一定會與預期完全一致
(3) RDB與AOF的區別
[1] RDB使用快照生成檔案,崩潰恢復時在通過rdbloade將檔案加載到記憶體中
[2] AOF使用緩沖區記錄所有已執行命令,將命令寫入檔案,崩潰恢復時通過創建一個偽客戶端讀取檔案并執行
4.redis 鍵過期處理
(1) Redis所有的資料結構都可以設定過期時間,時間到了會自動洗掉,Redis會將每個設定了過期時間的key放入一個獨立的字典中,以后會定時遍歷這個字典來洗掉到期的key(redis采用惰性洗掉和定期洗掉結合的策略,以達到合理使用cpu時間和避免浪費記憶體空間之間的平衡)
(2) 定時洗掉:在設定key過期時間的同時創建一個定時器,讓定時器在key過期時執行洗掉命令
(3) 惰性洗掉:僅在每次收到對key的請求時才檢查是否過期,如果已過期則洗掉key
(4) 定期洗掉:每隔一段時間對key字典進行檢查,洗掉過期的key
(5) 從庫的過期策略:從庫對key的過期處理是被動的,會在AOF檔案中添加一條del指令,同步到所有從庫中,根據命令執行來洗掉過期key
5.redis 鍵踢出策略:
當redis記憶體超出物理記憶體限制時,記憶體的資料會開始和磁盤產生頻繁的交換(swap),交換會讓redis的性能急劇下降,所以我們是不允許redis出現交換行為的,為了限制最大使用記憶體,redis提供了配置引數maxmemory來限制記憶體超出期望大小時的處理策略,
(1) Noeviction:不踢出,當記憶體使用達到閾值的時候,所有引起申請記憶體的命令會報錯(默認策略)
(2) volatile-lru:在設定了過期時間的鍵空間中,優先移除最近未使用的key,如果鍵不存在則報錯
(3) volatile-ttl:在設定了過期時間的鍵空間中,優先移除過期時間最近的key,如果鍵不存在則報錯
(4) volatile-random:在設定了過期時間的建空間中,隨機移除個key
(5) allkeys-lru:在主鍵空間中,優先移除最近未使用的key
(6) allkeys-random:在主鍵空間中,隨機移除某個key,踢出時機:每個命令執行之前(redis.c/processCommand)
6.redis 最久未使用踢出策略:LRU演算法
(1) 新資料插入到鏈表頭部
(2) 每次訪問命中快取,則將資料移動到鏈表頭部
(3) 鏈表滿時,移除鏈表尾部元素
7.redis 超時策略LRU-K
(1) 資料第一次被訪問時,加入到訪問歷史串列
(2) 如果資料資料在訪問歷史串列后沒有達到K次訪問,則按照規則淘汰(FIFO,LRU)
(3) 當訪問歷史佇列中的資料訪問次數達到K次后,將資料索引從歷史佇列轉移到快取佇列中,并快取此資料,快取佇列重新按照時間排序
(4) 需要淘汰資料時,淘汰快取佇列中排在末尾的資料
8.redis哨兵
(1) 每個哨兵每秒想它所知的master、slave及其他哨兵發送ping命令,檢查存活狀態
(2) 如果一個實體距離最后一次有效回復ping命令時間超過預設值(down-after-milliseconds),則這個實體會被哨兵標記為主觀下線
(3) 如果一個master被標記為主觀下線,則正在監視這個master的所有哨兵要每秒確認一次master的確進入了主觀下線狀態
(4) 當有足夠的哨兵在制定的時間范圍內確認master的確進入了主觀下線狀態,則master會被標記為客觀下線
(5) 一般情況下,每個哨兵會以每10秒一次的頻率想它所制定的所有master、slave發送info命令
(6) 當master被哨兵標記為客觀下線時,info命令的頻率改為每秒一次
(7) 若沒有足夠數量的哨兵同意master已經下線,則master的客觀下線狀態會被移除
(8) 如果有足夠數量的哨兵同意master已下線,則進行投票選舉master,當被投slave的票數達到?n/2+1時,成為新的master
9.快取穿透
查詢一個一定不存在的資料,由于快取是不命中時需要從資料庫查詢,查不到資料則不寫入快取,這將導致這個不存在的資料每次請求都要到資料庫去查詢,造成快取穿透,
解決方案:
(1)布隆過濾
[1] 概念
對所有可能查詢的引數以hash形式存盤,在控制層先進行校驗,不符合則丟棄,
[2] 實作方式
將所有可能存在的資料哈希到一個足夠大的bitmap中,一個一定不存在的資料會被這個bitmap攔截掉,從而避免了對底層存盤系統的查詢壓力,
[3] 基本原理及要點:位陣列+k個獨立hash函式,
將hash函式對應的值的位陣列置1,查找時如果發現所有hash函式對應位都是1說明存在,很明顯這個程序并不保證查找的結果是100%正確的,同時也不支持洗掉一個已經插入的關鍵字,因為該關鍵字對應的位會牽動到其他的關鍵字,所以一個簡單的改進就是counting Bloom filter,用一個counter陣列代替位陣列,就可以支持洗掉了,添加時增加計數器,洗掉時減少計數器,
(2) 快取空物件
10.快取雪崩
如果快取集中在一段時間內失效,發生大量的快取穿透,所有的查詢都落在資料庫上,造成了快取雪崩,
解決方案:
(1) 加隨機過期時間
為所有并發查詢的的快取時間添加一個額外時間亂數在1~15分鐘使快取盡量不會再同一時間失效
(2) 加鎖排隊
在快取失效后,通過加鎖或者佇列來控制讀資料庫寫快取的執行緒數量,比如對某個key只允許一個執行緒查詢資料和寫快取,其他執行緒等待,比較常用的做法,是使用mutex,簡單地來說,就是在快取失效的時候(判斷拿出來的值為空),不是立即去loaddb,而是先使用快取工具的某些帶成功操作回傳值的操作(比如Redis的SETNX或者Memcache的ADD)去set一個mutex key,當操作回傳成功時,再進行load db的操作并回設快取;否則,就重試整個get快取的方法,SETNX,是「SET if Not eXists」的縮寫,也就是只有不存在的時候才設定,可以利用它來實作鎖的效果,
(3) 資料預熱
可以通過快取reload機制,預先去更新快取,再即將發生大并發訪問前手動觸發加載快取不同的key,設定不同的過期時間, 讓快取失效的時間點盡量均勻
(4) 二級快取或雙快取
A1為原始快取,A2為拷貝快取,A1失效時,可以訪問A2,A1快取失效時間設定為短期,A2設定為長期,
(5) 介面限流:計數器、時間視窗、令牌等演算法實作
11.CMS和G1區別
(1) CMS執行程序 是一種以獲取最短回收停頓時間為目標的收集器
[1] 初始標記:標記GC Root可直接連接的物件,運行期間會停止其他用戶操作
[2] 并發標記:在初始標記的基礎上繼續向下追溯標記,以所有已標記物件為根節點繼續搜索向下標記,
[3] 并發預清理:,虛擬機查找在執行并發標記階段新進入老年代的物件(可能會有一些物件從新生代晉升到老年代, 或者有一些物件被分配到老年代),通過重新掃描,減少下一個階段”重新標記”的作業,因為下一個階段會Stop The World,
[4] 重新標記 :停止其他用戶操作,收集器執行緒掃描在CMS堆中剩余的物件,掃描從”根物件”開始向下追溯,并處理物件關聯,
[5] 并發清理 :清理垃圾物件,這個階段收集器執行緒和應用程式執行緒并發執行,
[6] 并發重置:清理CMS堆疊,
(2) G1運行機制 有利于程式長時間運行,分配大物件時不會因為無法找到連續記憶體空間而提前觸發下一次GC,并且停頓時間可預測,
[1] 初始標記:僅標記GC Roots能直接到達的物件,并且修改TAMS的值,讓下一階段用戶程式并發運行時能在正確可用的Region中創建新物件,
[2] 根區域掃描:從GC Roots開始對對已標記的參考掃描,并標記對老年代的參考,
[3] 并發標記:在整個堆中查找可訪問的物件并標記,
[4] 最終標記:多執行緒修正在并發期間因用戶程式執行而導致標記產生變化的標記,切將物件的變化記錄在Remembered Set Logs里,把這里的資料合并到Remembered Set中,
[5] 篩選回收:對每個Region的回收價值和成本進行排序,根據用戶所期望的GC停頓時間來指定回收計劃,
未完待續,今天太晚了明后天有空再把后面的補上
12. 設計模式,會的每種一個demo撰寫,
13.Lucene
14.ES
15.Quartz 分布式定時原理
16.線上如何壓力測驗
17.如何影子表 隔離 壓力資料
18.故障演練如何做
19.Mysql事務隔離級別
20.手寫有序陣列二分查找
21.分布式鎖的實作
22.2pc,xa協議
23.mysql是如何做crash-safe的
24.ThreadLocal的使用場景
25.redis資料結構
26.juc下面公平非公平鎖的實作區別?
27.spring回圈依賴
28.各種分布式演算法場景等
1.分布式一致性演算法
2.投票選舉演算法
29.限流演算法
30.熔斷處理
31.降級處理
有幾個涉及到公司專案相關的問題及設計方案就不寫了
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/290821.html
標籤:其他
上一篇:rocketMQ的初步認識,topic、nameServer、broker相關概念的解釋
下一篇:Spark2.1.0安裝和配置
