文章目錄
- 面試專題-java高級篇
- 1. JVM
- 有做過jvm的調優嗎?常用的jvm參數調優有哪些?
- 如果jvm持續一段時間頻繁的發生Young GC (輕GC) 可能原因有哪些?
- 2. Mysql
- 2.1. 基本功(見為知筆記)
- 2.2. 什么是索引
- 2.3. 索引的優劣勢
- 2.4. MySQL的索引結構
- 2.4.1. B-Tree索引
- 2.4.2. B+Tree索引
- 2.4.3. 聚簇索引與非聚簇索引
- 2.4.4. MySQL回表
- 2.5. 索引的使用場景
- 2.6. SQL語句如何優化
- 2.6.1. 單表優化
- 2.6.2. 關聯查詢優化
- 2.6.3. 子查詢優化
- 2.6.4. 排序優化
- 2.6.5. 分組優化
- 2.6.6. 覆蓋索引
- 2.7. 如何批量將百萬數據快速導入數據庫
- 3. Redis
- 3.1.簡單介紹一下redis
- 3.2. 單線程的redis為什么讀寫速度快?
- 3.3. redis為什么是單線程的?
- 3.4.redis單線程如何解決keys 模糊匹配的查詢阻塞問題?
- 3.5. redis服務器的的內存是多大?
- 3.6. 為什么Redis的操作是原子性的,怎么保證原子性的?
- 3.7. 對redis的持久化了解不?
- redis的過期策略以及內存淘汰機制有了解過嗎
- 3.8. 做過redis的集群嗎?你們做集群的時候搭建了幾臺,都是怎么搭建的?
- 3.8.1. 下載Redis源碼,編譯安裝
- 3.8.2. 編寫配置文件
- 3.8.3. 啟動Redis節點
- 3.8.4. 創建集群
- 3.9. 說說Redis哈希槽的概念?
- 3.10. 什么是redis的緩存穿透?如何防止穿透?
- 3.11. 什么是redis的緩存雪崩?如何防止?
- 3.12. 什么是redis的緩存擊穿?如何防止?
- 4. Kafka
- 4.1 什么是Kafka?它的特點和使用場景是什么?
- 4.2 Kafka的消息有哪些主要組件?
- 4.3 消息的保留策略有哪些?它們分別有什么作用?
- 4.4 Kafka如何保證消費的順序和可靠性?
- 4.5 Kafka的缺點是什么?
- 4.6 Kafka 實際生產環境中是否會存在消息積壓的問題,如果有,該如何處理?
- 4.7 Kafka如何防止消息不丟失?請具體說一下
- 4.6 Kafka 實際生產環境中是否會存在消息積壓的問題,如果有,該如何處理?
- 4.7 Kafka如何防止消息不丟失?請具體說一下
面試專題-java高級篇
1. JVM
有做過jvm的調優嗎?常用的jvm參數調優有哪些?
? 回答話術: jvm參數之前在工作的時候也偶爾做過,但是也不能完全記得住,每次都是在需要的時候去查詢文檔 一般情況下都是使用默認值,只有在真正需要調優的時候會去重新設置值去覆蓋默認值…停頓幾秒思考
? 根據我的回憶,jvm參數分為三種
? 標準參數: 主要用于查看一些基本信息 比如jvm版本號
? X參數: 用于設置內存大小 基本都是傳給 JVM 的,默認 JVM 實現這些參數的功能,但是并不保證所有 JVM 實 現都滿足,且不保證向后兼容 穩定性好
? XX參數 用于設置內存大小 專門用于控制 JVM 的行為,跟具體的 JVM 實現有關,隨時可能會在下個版本取消
? 穩定性差一些
? 接下來舉例說明幾個常用的參數
? -Xms 內存的初始值大小 以M(兆)為單位 默認為系統內存的1/64
? -Xmx 內存的最大值 也是以M(兆)為單位 最大值為系統內存的1/4
? 一般情況下,會將如下兩個參數設置為相同的值,可以避免jvm內存的自動擴展,因為當堆內存大小發生擴展的時候,就會發生內存的抖動,會影響到程序的穩定性
? -Xmn 用于設置新生代的內存大小,一般設置為堆空間的1/3或者1/4,因為新生代大的話,老年代就會變小
? -Xss 用于設置每個線程的虛擬機棧的大小也即堆棧的大小
? -XX -XX:+UseG1GC 設置垃圾回收器
? 當然還有很多的參數,一般都是需要的時候會按照文檔就行設置,具體的就記不住那么多了…
-Xmx1024M 最大堆內存
-Xms1024M 初始化堆內存,正常和最大堆內存相同,減少動態改變的內存損耗
-Xmn384M 年輕代內存-XX:+PrintGCDetails 打印gc信息,可參考gc的比例進行調優
-XX:+UseConcMarkSweepGC 老年代使用cms,標記-清除算法會產生碎片
-XX:+UseParNewGC 年輕代使用并行收集器
如果jvm持續一段時間頻繁的發生Young GC (輕GC) 可能原因有哪些?
? 首先頻繁的YGC 說明會頻繁的創建對象并立馬被回收了 我想造成這個問題的原因可能有兩點
? 第一點: for循環內部 頻繁的創建局部對象從而導致頻繁的GC 當然也有可能是死循環導致的
? 第二點: 年輕代內存大小設置不足,無法滿足程序邏輯的需要從而導致頻繁GC
? 為了解決這個問題,要么就是減少對象的創建,當然這個要修改程序,難度和周期都比較長一些,要么就是增大年輕代的內存大小,這樣可以更快的解決這個問題.當然了,最可靠的還是修改代碼,通過GC日志定位問題
2. Mysql
2.1. 基本功(見為知筆記)
2.2. 什么是索引
MySQL官方對索引的定義為:索引(Index)是幫助MySQL高效獲取數據的數據結構。可以得到索引的本質:索引是數據結構。
索引的目的在于提高查詢效率,可以類比字典
2.3. 索引的優劣勢
優勢:
- 類似大學圖書館建書目索引,提高數據檢索的效率,降低數據庫的IO成本。
- 通過索引列對數據進行排序,降低數據排序的成本,降低了CPU的消耗。
劣勢:
- 雖然索引大大提高了查詢速度,同時卻會降低更新表的速度,如對表進行INSERT、UPDATE和DELETE。因為更新表時,MySQL不僅要保存數據,還要保存一下索引文件。每次更新添加了索引列的字段,都會調整因為更新所帶來的鍵值變化后的索引信息
- 實際上索引也是一張表,該表保存了主鍵與索引字段,并指向實體表的記錄,所以索引列也是要占用空間的
2.4. MySQL的索引結構
2.4.1. B-Tree索引
【初始化介紹】
一顆b樹,包含多個磁盤塊,可以看到每個磁盤塊包含幾個鍵值(表中記錄的主鍵)、數據(表中除主鍵外的數據)和指針(指向下一個磁盤塊的指針)如磁盤塊1包含鍵值17和35,包含指針P1、P2、P3,P1表示小于17的磁盤塊,P2表示在17和35之間的磁盤塊,P3表示大于35的磁盤塊。真實的數據存在于葉子節點即3、5、9、10、13、15、28、29、36、60、75、79、90、99。非葉子節點不存儲真實的數據,只存儲指引搜索方向的鍵值信息,如17、35并不真實存在于數據表中。
【查找過程】
如果要查找數據項29,那么首先會把磁盤塊1由磁盤加載到內存,此時發生一次IO,在內存中用二分查找確定29在17和35之間,鎖定磁盤塊1的P2指針,內存時間因為非常短(相比磁盤的IO)可以忽略不計,通過磁盤塊1的P2指針的磁盤地址把磁盤塊3由磁盤加載到內存,發生第二次IO,29在26和30之間,鎖定磁盤塊3的P2指針,通過指針加載磁盤塊8到內存,發生第三次IO,同時內存中做二分查找找到29,結束查詢,總計三次IO。
真實的情況是,3層的b+樹可以表示上百萬的數據,如果上百萬的數據查找只需要三次IO,性能提高將是巨大的,如果沒有索引,每個數據項都要發生一次IO,那么總共需要百萬次的IO,顯然成本非常非常高。
2.4.2. B+Tree索引
通常在B+Tree上有兩個頭指針,一個指向根節點,另一個指向關鍵字最小的葉子節點,而且所有葉子節點(即數據節點)之間是一種鏈式環結構。因此可以對B+Tree進行兩種查找運算:一種是對于主鍵的范圍查找和分頁查找,另一種是從根節點開始,進行隨機查找。
B+Tree相對于B-Tree有幾點不同:
-
非葉子節點只存儲鍵值信息。
-
所有葉子節點之間都有一個鏈指針。
-
數據記錄都存放在葉子節點中。
1)B+樹的磁盤讀寫代價更低
B+樹的內部結點并沒有指向關鍵字具體信息的指針。因此其內部結點相對B 樹更小。如果把所有同一內部結點的關鍵字存放在同一盤塊中,那么盤塊所能容納的關鍵字數量也越多。一次性讀入內存中的需要查找的關鍵字也就越多。相對來說IO讀寫次數也就降低了;
2)B+樹查詢效率更加穩定
由于非終結點并不是最終指向文件內容的結點,而只是葉子結點中關鍵字的索引。所以任何關鍵字的查找必須走一條從根結點到葉子結點的路。所有關鍵字查詢的路徑長度相同,導致每一個數據的查詢效率相當;
3)B+樹便于范圍查詢(最重要的原因,范圍查找是數據庫的常態)
B樹在提高了IO性能的同時并沒有解決元素遍歷時候效率低下的問題,正是為了解決這個問題,B+樹應用而生。B+樹只需要去遍歷葉子節點就可以實現整棵樹的遍歷。而且在數據庫中基于范圍的查詢是非常頻繁的,而B樹不支持這樣的操作或者說效率太低。
2.4.3. 聚簇索引與非聚簇索引
聚簇索引:將數據存儲與索引放到了一塊,找到索引也就找到了數據
非聚簇索引:將數據存儲與索引分開結構,索引結構的葉子節點指向了數據的對應行,myisam通過key_buffer把索引先緩存到內存中,當需要訪問數據時(通過索引訪問數據),在內存中直接搜索索引,然后通過索引找到磁盤相應數據這也就是為什么索引不在key buffer命中時,速度慢的原因
innodb中,在聚簇索引之上創建的索引稱之為輔助索引,輔助索引訪問數據總是需要二次查找,非聚簇索引都是輔助索引。輔助索引葉子節點存儲的不再是行的物理位置,而是主鍵值。
InnoDB使用的是聚簇索引,將主鍵組織到一棵B+樹中,而行數據就儲存在葉子節點上,若使用"where id = 14"這樣的條件查找主鍵,則按照B+樹的檢索算法即可查找到對應的葉節點,之后獲得行數據。若對Name列進行條件搜索,則需要兩個步驟:第一步在輔助索引B+樹中檢索Name,到達其葉子節點獲取對應的主鍵。第二步使用主鍵在主索引B+樹種再執行一次B+樹檢索操作,最終到達葉子節點即可獲取整行數據。(重點在于通過其他鍵需要建立輔助索引)
2.4.4. MySQL回表
Mysql回表指的是在InnoDB存儲引擎下,二級索引查詢到的索引列,如果需要查找所有列的數據,則需要到主鍵索引里面去取出數據。這個過程就稱為回表。因為行的數據都是存在主鍵B+tree的葉子節點里面,二級索引的B+樹葉子節點都是存放的(索引列,主鍵)
2.5. 索引的使用場景
哪些情況需要創建索引
主鍵自動建立唯一索引
頻繁作為查詢條件的字段應該創建索引
查詢中與其它表關聯的字段,外鍵關系建立索引
單鍵/組合索引的選擇問題, 組合索引性價比更高
查詢中排序的字段,排序字段若通過索引去訪問將大大提高排序速度
查詢中統計或者分組字段
哪些情況不要創建索引
表記錄太少
經常增刪改的表或者字段。
Why:提高了查詢速度,同時卻會降低更新表的速度,如對表進行INSERT、UPDATE和DELETE。因為更新表時,MySQL不僅要保存數據,還要保存一下索引文件
Where條件里用不到的字段不創建索引
過濾性不好的不適合建索引
2.6. SQL語句如何優化
2.6.1. 單表優化
- 不在索引列上做任何操作(計算、函數、(自動or手動)類型轉換),會導致索引失效而轉向全表掃描
- like以通配符開頭(‘%abc…’)mysql索引失效會變成全表掃描的操作
- mysql 在使用**不等于(!=或者<>)**的時候無法使用索引會導致全表掃描
- is not null 也無法使用索引,但是is null是可以使用索引的
- 字符串不加單引號索引失效
組合索引
- 全值匹配我最愛
- 符合最左原則:不跳過索引中的列。
- 如果where條件中是OR關系,加索引不起作用
- 范圍查詢右邊的索引條件不走索引
總結
對于單鍵索引,盡量選擇針對當前query過濾性更好的索引在選擇組合索引的時候,當前Query中過濾性最好的字段在索引字段順序中,位置越靠前越好。在選擇組合索引的時候,盡量選擇可以能夠包含當前query中的where字句中更多字段的索引在選擇組合索引的時候,如果某個字段可能出現范圍查詢時,盡量把這個字段放在索引次序的最后面書寫sql語句時,盡量避免造成索引失效的情況
2.6.2. 關聯查詢優化
- 保證被驅動表的join字段已經被索引
- left/right join 時,選擇小表作為驅動表,大表作為被驅動表。
- inner join 時,mysql會自己幫你把小結果集的表選為驅動表。
- 子查詢盡量不要放在被驅動表,有可能使用不到索引。
- 能夠直接多表關聯的盡量直接關聯,不用子查詢。
2.6.3. 子查詢優化
盡量不要使用not in 或者 not exists
2.6.4. 排序優化
ORDER BY子句,盡量使用Index方式排序,避免使用FileSort方式排序
排序順序要保持一致
2.6.5. 分組優化
group by 使用索引的原則幾乎跟order by一致 ,唯一區別是groupby 即使沒有過濾條件用到索引,也可以直接使用索引。
2.6.6. 覆蓋索引
最后使用索引的手段:覆蓋索引
什么是覆蓋索引?簡單說就是,select 到 from 之間查詢的列 <=使用的索引列+主鍵
2.7. 如何批量將百萬數據快速導入數據庫
要批量將百萬數據快速導入數據庫,可以考慮以下幾個步驟:
- 選擇合適的數據庫:選擇能夠支持快速批量導入的數據庫。例如,MySQL和PostgreSQL都提供了快速導入數據的功能。
- 準備數據:將數據準備成符合數據庫要求的格式,例如使用CSV格式或者數據庫支持的其他格式。
- 使用命令行工具導入數據:許多數據庫都提供了命令行工具來導入數據,這些工具可以快速地導入大量數據。例如,可以使用MySQL的"LOAD DATA INFILE"命令或者PostgreSQL的"COPY"命令。
- 使用批量插入API:許多數據庫還提供了批量插入API,這些API可以在代碼中使用,可以快速地將大量數據批量插入數據庫。例如,MySQL提供了"LOAD DATA LOCAL INFILE"命令和"INSERT INTO … VALUES"語句,而PostgreSQL提供了"pg_bulkload"工具和"INSERT INTO … VALUES"語句。
- 調整數據庫配置:在導入大量數據時,可能需要調整數據庫的配置以提高性能。例如,可以增加數據庫緩存大小,調整日志記錄級別等。
需要注意的是,在導入大量數據時,可能會影響數據庫的性能和可用性。因此,在導入數據之前應該備份數據庫,并且在導入過程中應該監視數據庫的狀態,以確保不會出現意外的問題。
3. Redis
3.1.簡單介紹一下redis
(1)redis是一個key-value類型的非關系型數據庫,基于內存也可持久化的數據庫,相對于關系型數據庫(數據主要存在硬盤中),性能高,因此我們一般用redis來做緩存使用;并且redis支持豐富的數據類型,比較容易解決各種問題
類型 | 底層數據結構/介紹 | 使用場景 |
---|---|---|
string | 簡單動態字符串(Simple Dynamic string 縮寫SDS).是可以修改的字符串,內部結構實現上類似java中的ArrayList,采用預分配冗余空間的方式來減少內存的頻繁分配.需要注意的是字符串最大長度為512M | 項目中我們主要利用單點登錄中的token用string類型來存儲;商品詳情 |
hash | Hash類型第一段數據結構有兩種:ziplist(壓縮列表),hashtable(哈希表).當field-value長度較短且個數較少時,使用ziplist,否則使用HashTable | Hash類型中的key是string類型,value又是一個map(key-value),針對這種數據特性,比較適合存儲對象,在我們項目中由于購物車是用redis來存儲的,因此選擇redis的散列(hash)來存儲; |
list | 單鍵多值,底層是快速雙向鏈表quicklist,在列表元素較少的情況下會使用一塊連續的內存存儲,結構為ziplist即壓縮列表,它將所有的元素緊挨著一起存儲,分配的是一塊連續的內存.當數據量比較多的時候才會改成quicklist,因為普通的鏈表需要的附加指針空間太大,浪費空間,eg:列表中存儲的只是int類型的數據,結構上還需要兩個額外的指針prev與next.redis將鏈表和ziplist組合起來組成quicklist,即將多個ziplist使用雙向指針串起來使用,既滿足了快速插入刪除性能,又不會出現太大的空間冗余 | List類型是按照插入順序的字符串鏈表(雙向鏈表),主要命令是LPOP和RPUSH,能夠支持反向查找和遍歷,如果使用的話主要存儲商品評論列表,key是該商品的ID,value是商品評論信息列表;消息隊列 |
set | set數據結構是dict字典,字典是用哈希表實現的,java中HashSet內部使用的是HashMap,只不過所有的value都指向同一個對象.Redis中的set也是一樣的,他的內部結構也使用hash結構,所有的value都指向同一個內部值 | 可以基于 Set 玩兒交集、并集、差集的操作,比如交集吧,我們可以把兩個人的好友列表整一個交集,看看倆人的共同好友是誰? |
zset | zset底層使用了兩個數據結構 (1)hash,hash的作用就是關聯元素value和權重score,保障元素value的唯一性,可以通過元素value找到對應的score的值 (2)跳躍表,跳躍表的目的在于給元素value排序,根據score的范圍獲取元素列表 | zset(sorted set)類型和set類型基本是一致的,不同的是zset這種類型會給每個元素關聯一個double類型的分數(score),這樣就可以為成員排序,并且插入是有序的。這種數據類型如果使用的話主要用來統計商品的銷售排行榜,比如:items:sellsort 10 1001 20 1002 這個代表編號是1001的商品銷售數量為10,編號為1002的商品銷售數量為20/附件的人 |
Bitmaps | bitmaps可以實現對位的操作,節約內存空間(前提是數據量大) (1) bigmaps本身不是一種數據類型,實際上是字符串,但是它可以對字符串進行位運算 (2)bitmaps單獨提供了一套命令,可以把bitmaps理解成一個以位為單位的數組,數組的每一個單元只能存儲0或者1,數組的小標在bitmaps中叫做偏移量 | 統計網站活躍用戶 解決redis隨機穿透攻擊 |
HyperLogLog | 統計uv,獨立ip數,搜索記錄數等需要去重和計數的問題如何解決?這種求集合中不重復元素個數的問題成為基數問題.常規的解決辦法包括mysql中的distinct與redis的hash set等方案精確計算,但是隨著數據不斷增加,導致空間越來越大,對于非常大的數據集是不切實際的.該數據類型可以通過降低精度來平衡存儲空間,是用來做基數(集合中不重復元素的個數)統計的算法 | 計算基數的應用場景 網站的uv 固定IP數 搜索記錄數 |
Geospatial | 地理信息的縮寫,該類型,就是元素的二維坐標,在地圖上基數經緯度,redis基于該類型,提供了經緯度設置,查詢,范圍查詢,距離查詢 經緯度hash等常見操作 |
3.2. 單線程的redis為什么讀寫速度快?
- 純內存操作
- 單線程操作,避免了頻繁的上下文切換
- 采用了非阻塞I/O多路復用機制
3.3. redis為什么是單線程的?
官方FAQ表示,因為Redis是基于內存的操作,CPU不是Redis的瓶頸,Redis的瓶頸最有可能是機器內存的大小或者網絡帶寬。既然單線程容易實現,而且CPU不會成為瓶頸,那就順理成章地采用單線程的方案了Redis利用隊列技術將并發訪問變為串行訪問
1)絕大部分請求是純粹的內存操作
2)采用單線程,避免了不必要的上下文切換和競爭條件
3.4.redis單線程如何解決keys 模糊匹配的查詢阻塞問題?
由于Redis是單線程,keys命令是以阻塞的方式執行的,keys是以遍歷的方式實現的復雜度是 O(n),Redis庫中的key越多,查找實現代價越大,產生的阻塞時間越長
為了解決Keys命令的痛點,Redis2.8版本中加入了Scan指令,特點是迭代遍歷,并可以指定返回數據的條數
SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]
cursor:游標,當次遍歷的起始位置pattern:與Keys命令中的patterns相同,支持通配符匹配count:返回數據條數,但只是一個hint(暗示),具體返回條數可多可少。type: Redis 6.0 支持的參數,指定返回Key的類型,類型可選值與 TYPE命令相同:string, list, set, zset, hash and stream。
scan 命令是一個游標式的遍歷命令,可以返回符合給定模式的所有鍵值對。scan 命令可以在不阻塞服務器的情況下返回大量的數據,并且可以通過游標參數分批次進行查詢,從而避免了單次查詢數據量過大的問題。同時,scan 命令還支持限定返回數量,以及返回指定的字段等高級功能
3.5. redis服務器的的內存是多大?
Redis服務器的內存大小可以根據需求進行配置,可以配置為幾十MB到幾十GB不等。具體而言,可以在redis.conf配置文件中通過 maxmemory 參數來設置Redis實例的最大內存限制。例如,如果要將Redis實例的最大內存限制設置為1GB,則可以將該參數設置為maxmemory 1GB不設置該參數,則Redis將使用系統的所有可用內存。
3.6. 為什么Redis的操作是原子性的,怎么保證原子性的?
對于Redis而言,命令的原子性指的是:一個操作的不可以再分,操作要么執行,要么不執行。
Redis的操作之所以是原子性的,是因為Redis是單線程的。
Redis本身提供的所有API都是原子操作,Redis中的事務其實是要保證批量操作的原子性。
多個命令在并發中也是原子性的嗎?
不一定, 將get和set改成單命令操作,incr 。使用Redis的事務,或者使用Redis+Lua==的方式實現.
3.7. 對redis的持久化了解不?
持久化就是將內存的數據寫入到磁盤當中,防止服務突然宕機,造成內存數據的丟失。
類型 | 介紹 | 具體配置 | 優點 | 缺點 |
---|---|---|---|---|
RDB | 默認持久化機制是按照一定的時間將內存中的數據以快照的形式保存到硬盤中 rdb.dump | ![]() | ||
數據恢復速度快 | 可能丟失少量新數據持久化時存儲數據效率低 | |||
AOF | 是將Redis的每一次操作都寫入到單獨的日志文件中,當重啟redis會重新從持久化的的日志中恢復數據 文件名為appendonly.aof | ![]() | ||
持久化效率高 不會丟失數據 | 恢復數據時效率低aof中記錄的所有命令進行重放,效率低 | |||
混合模式(RDB+AOF) | 將RDB和AOF混合一起使用,在使用混合模式時,所有的數據操作也是保存在AOF當中,當進行恢復文件的時候,會將原有的AOF刪除,并且將其中的數據全部以快照的形式保存至RDB文件當中 | ![]() | ||
持久化效率高保證數據的安全性不會丟失數據且恢復的速度快 |
redis的過期策略以及內存淘汰機制有了解過嗎
Redis的過期策略主要有兩種:惰性刪除和定期刪除。惰性刪除是指在讀取鍵值對時,先判斷該鍵是否過期,如果過期就刪除,否則直接返回。定期刪除是指Redis定期檢查所有鍵的過期時間,將其中已經過期的鍵刪除。
內存淘汰機制指的是Redis在內存占用達到限制時,如何選擇要刪除的鍵。Redis的內存淘汰機制有6種:
- noeviction:達到內存限制時,直接返回錯誤,不會刪除任何鍵值對。
- allkeys-lru:Redis會遍歷所有鍵值對,選擇最近最少使用的鍵值對進行刪除。
- allkeys-random:Redis會隨機選擇一些鍵值對進行刪除。
- volatile-lru:Redis只會刪除設置了過期時間的鍵值對中最近最少使用的那些。
- volatile-random:Redis只會隨機刪除設置了過期時間的鍵值對。
- volatile-ttl:Redis只會刪除設置了過期時間的鍵值對中,剩余時間最短的那些。
3.8. 做過redis的集群嗎?你們做集群的時候搭建了幾臺,都是怎么搭建的?
搭建Redis集群的方式有多種,比如可以使用Redis Sentinel或Redis Cluster。其中Redis Cluster是官方推薦的方式,也是比較常用的一種方式。在搭建Redis Cluster時,需要進行以下步驟:
- 搭建多個Redis實例并配置集群模式。
- 配置每個Redis實例的節點信息,包括節點IP和端口號。
- 啟動每個Redis實例,并創建集群。
- 將數據分配到不同的槽位上,可以使用Redis Cluster提供的命令進行數據遷移和槽位分配。
在搭建Redis集群時,還需要考慮節點之間的網絡通信、數據同步和故障處理等問題,需要進行適當的配置和調優。
具體操作:
3.8.1. 下載Redis源碼,編譯安裝
$ wget http://download.redis.io/releases/redis-x.x.x.tar.gz
$ tar xzf redis-x.x.x.tar.gz
$ cd redis-x.x.x
$ make
$ sudo make install
3.8.2. 編寫配置文件
port 6379
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
appendonly yes
其中,cluster-enabled
參數需要設置為yes
,表示開啟集群模式;
? cluster-config-file
參數表示集群節點信息的存儲文件;
? cluster-node-timeout
表示節點超時時間,單位為毫秒。
3.8.3. 啟動Redis節點
$ redis-server /path/to/redis.conf
可以使用不同的配置文件啟動多個Redis節點,比如:
$ redis-server /path/to/redis-6379.conf
$ redis-server /path/to/redis-6380.conf
$ redis-server /path/to/redis-6381.conf
3.8.4. 創建集群
$ redis-cli --cluster create 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381
然后會提示輸入yes確認搭建集群,完成后集群就搭建好了
3.9. 說說Redis哈希槽的概念?
Redis哈希槽是Redis集群的核心概念之一。在Redis集群中,數據會被分布在不同的節點上,而哈希槽則是用來劃分數據所在節點的邏輯單位。哈希槽的數量是固定的,Redis默認將其劃分為16384個槽位。
當一個新的節點加入Redis集群時,集群會將部分哈希槽從已有節點上遷移至新節點上,直到集群中所有節點的哈希槽數量都比較平均。當有數據需要存儲時,Redis會根據數據的鍵值對應的哈希值,將其映射到一個哈希槽中,并根據哈希槽的分布情況,將數據存儲到相應的節點上。
哈希槽的使用使得Redis集群可以更加高效地進行數據存儲和訪問,同時還能夠實現數據的分布式存儲和負載均衡。
3.10. 什么是redis的緩存穿透?如何防止穿透?
緩存穿透是指查詢一個不存在的數據,由于緩存無法命中,將去查詢數據庫,但是數據庫也無此記錄,并且出于容錯考慮,我們沒有將這次查詢的null寫入緩存,這將導致這個不存在的數據每次請求都要到存儲層去查詢,失去了緩存的意義。在流量大時,可能DB就掛掉了,要是有人利用不存在的key頻繁攻擊我們的應用,這就是漏洞。
解決:
- 對不存在的數據進行數據空值緩存
- 設置白名單;(?可訪問的數據id作為偏移值存入bitmaps;?訪問時先檢查bitmaps)
- 使用布隆過濾器
3.11. 什么是redis的緩存雪崩?如何防止?
大量key集中過期,數據庫短時訪問量激增
解決:
- 多級緩存架構(Nginx-本地緩存(ehcache/guava) -Redis)
- 鎖或隊列對并發訪問進行序列化
- Key設置過期標志,對即將過期數據進行提前更新,自動續期(類似擊穿的解決方案)
- 數據的過期時間使用隨機值,分散過期時間
3.12. 什么是redis的緩存擊穿?如何防止?
突發熱點訪問時,熱點數據在Redis緩存中不存在或已過期。大量的對熱點數據的訪問,都將直接訪問數據庫,造成數據庫訪問壓力短時激,從而增造成故障。
解決:
- 提前預設熱門緩存數據
- 實時調整過期時間、自動續期
- 使用鎖
- 緩存數據不存在時,把數據庫數據放入緩存
4. Kafka
4.1 什么是Kafka?它的特點和使用場景是什么?
答: Apache Kafka是一個分布式的流平臺。它的主要特點有:
- 高吞吐量,支持每秒數百萬的消息處理。
- 分布式的、可擴展的和高度容錯的。
- 可以同時支持發布/訂閱和隊列消息的處理模式。
- 適用于大規模日志收集、日志聚合和流數據處理等場景。
4.2 Kafka的消息有哪些主要組件?
答:Kafka的消息主要有以下組件:
- Topic:消息的發布和訂閱是通過主題來實現的,一個主題可以有多個訂閱者。生產者將消息發布到一個主題上,而消費者從它感興趣的主題上訂閱消息。
- Broker:Kafka集群中的每個服務器都被稱為broker。
- Partition:每個topic在Kafka集群中都有一個或者多個分區,一個分區就是一個提交日志文件。
- Offset:對于每個主題分區,Kafka在消息傳遞過程中對它們進行編號,這個編號稱為“offset”。
- Producer:負責發布消息到Kafka broker。
- Consumer:用來從Kafka broker讀取消息。
4.3 消息的保留策略有哪些?它們分別有什么作用?
答:Kafka提供了三種保留策略:
- 刪除策略(Delete Policy):逐出已經過期的消息(比如7天前的消息)。
- 壓縮策略(Compaction Policy):只保留最后一個版本的相同鍵的消息,用于在“鍵-值”存儲中。
- 原始數據策略(Custom Policy):能夠應對一個具有特定業務需求的場景。
4.4 Kafka如何保證消費的順序和可靠性?
答:Kafka可以通過兩種方式來保證消費的順序和可靠性:
- 分區和副本(Partition and Replica):每個分區內的所有消息都是順序寫入的,而且分區具有可擴展性,使Kafka可以分散負載。使用副本,Kafka可以增加容錯性和高可用性,以及在節點故障事件時提供無縫恢復。
- 消費者組(Consumer Group):為了保證消費順序,每個消費者都被分配至某個特定的消費者組內,在同一個組內消費者可以協同工作以實現負載均衡。消費者可以看到消息,但每個消息只會由一個消費者進行處理,這樣可以確保消息的順序和可靠性。
4.5 Kafka的缺點是什么?
答:Kafka的缺點包括:
- Kafka需要額外的組件才可以提供必要的管理和監控。例如,Zookeeper用于Kafka集群和Topic配置,以及Kafka Connect用于數據導入和導出等。
- Kafka Broker在進行故障轉移時需要一些準備工作, Kafka集群和服務必須保持可用狀態。
- Kafka需要隊列和/或分區的寫入操作才能開始處理數據。無法逐步處理其中一部分。
4.6 Kafka 實際生產環境中是否會存在消息積壓的問題,如果有,該如何處理?
- 增加消費者
4.7 Kafka如何防止消息不丟失?請具體說一下
- 副本存儲:Kafka 通過副本機制來保證數據可靠性。副本存儲可以提供數據冗余,如果其中一個節點故障,可以通過副本節點的數據來進行恢復。
- 配置消息的最小 ISR:Kafka 支持配置消息的最小 ISR(In-Sync Replicas)值,該值代表了至少有多少個副本節點需要和主節點保持同步。只有當 ISR 副本接收并確認了生產者發送的消息,才會認為該消息已經被成功寫入。
- 消費者確認機制:Kafka 支持消費者對消息進行確認。當消費者成功消費一條消息后,需要向 Kafka 服務端發送確認請求,通知 Kafka 服務端哪些消息已經被成功消費。如果 Kafka 服務端收到了消費者的確認請求,就認為該消息已經被成功消費;否則,該消息將會被重新發送。
分區的寫入操作才能開始處理數據。無法逐步處理其中一部分。
4.6 Kafka 實際生產環境中是否會存在消息積壓的問題,如果有,該如何處理?
- 增加消費者
4.7 Kafka如何防止消息不丟失?請具體說一下
- 副本存儲:Kafka 通過副本機制來保證數據可靠性。副本存儲可以提供數據冗余,如果其中一個節點故障,可以通過副本節點的數據來進行恢復。
- 配置消息的最小 ISR:Kafka 支持配置消息的最小 ISR(In-Sync Replicas)值,該值代表了至少有多少個副本節點需要和主節點保持同步。只有當 ISR 副本接收并確認了生產者發送的消息,才會認為該消息已經被成功寫入。
- 消費者確認機制:Kafka 支持消費者對消息進行確認。當消費者成功消費一條消息后,需要向 Kafka 服務端發送確認請求,通知 Kafka 服務端哪些消息已經被成功消費。如果 Kafka 服務端收到了消費者的確認請求,就認為該消息已經被成功消費;否則,該消息將會被重新發送。
- Kafka 也提供了可靠模式(At-Least-Once,Exactly-Once)來保證數據可靠性。在可靠模式下,一旦消息被成功發送,就不會再丟失或重復發送,保證數據的完整性和正確性