跳槽了,給大家整理一波面試題
來源:阿Q說程式碼
哈嘍大家好,我是阿Q!
最近好久沒有輸出原創文章了,究其原因是工作上出現了一些變動,順勢就跳了一波槽。
出去面了一圈後,雖說也順利拿了不少offer,但是不知道是不是年底的緣故,面試機會比往常要少許多。所以勸一下今年有打算換工作的朋友,還是先苟到年底,拿了年終獎再走吧~
趁我還記得住這些面試題,在第一時間給大家整理一波,希望對大家有所幫助。老規矩,字數有點多,建議收藏。
java基礎
ThreadLocal 的記憶體洩漏
ThreadLocalMap 中使用的 key 為 ThreadLocal 的弱引用,value 是強引用。當 ThreadLocal 沒有被外部強引用的情況下,在垃圾回收的時候,key 會被清理掉,而 value 不會被清理掉,從而導致記憶體溢位。
解決方法:線上程使用完 ThreadLocal 後,手動呼叫 remove() 方法清理 ThreadLocal 中的資料,確保及時釋放資源。
Synchronized 與 ReentrantLock 如何選擇
相同點:兩者都是“可重入鎖“,即當前執行緒獲取到鎖物件之後,如果想繼續獲取鎖物件還是可以繼續獲取的,只不過鎖物件的計數器進行“+1”操作就可以了。不同點
ReentrantLock是基於API實現的,Synchronized是依賴於JVM實現的; ReentrantLock可以響應中斷,Synchronized是不可以的; ReentrantLock可以指定是公平鎖還是非公平鎖,而Synchronized只能是非公平鎖; ReentrantLock的lock是同步非阻塞,採用的是樂觀併發策略,Synchronized是同步阻塞的,使用的是悲觀併發策略; ReentrantLock藉助Condition可以實現多路選擇通知,Synchronized透過wait()和notify()/notifyAll()方法可以實現等待/通知機制(單路通知);
執行緒池的使用及場景
執行緒池是一個共享的執行緒資源池,用於管理和重用工作執行緒。其主要目的是減少建立和銷燬執行緒的次數,以及減少執行緒的數量,從而提高系統效能。
執行緒池適用場景
需要處理大量短時間的任務:執行緒池可以透過重用執行緒來減少執行緒建立和銷燬的開銷,在任務完成後將執行緒返回到執行緒池中,避免了頻繁地建立和銷燬執行緒,從而提高了效率。 需要限制併發執行緒數量:執行緒池可以限制併發執行緒的數量,防止因為過多的執行緒導致系統負載過高等問題,從而保證系統的穩定性和可靠性。 需要非同步執行一些任務:執行緒池可以非同步執行一些任務,從而提高程式的響應速度,使程式具有更好的使用者體驗。 需要實現任務佇列:執行緒池可以將任務放入佇列中,並由工作執行緒逐個取出並執行,從而實現任務佇列的功能。
不同場景下適用的類別
newFixedThreadPool:建立一個固定執行緒數量的執行緒池,該執行緒池中的執行緒數量始終不變。當有一個新的任務提交時,執行緒池中若有空閒執行緒,則立即執行。若沒有,則新的任務會被暫存在一個任務佇列中,待有執行緒空閒時,便處理在任務佇列中的任務。 newSingleThreadExecutor:建立一個只有一個執行緒的執行緒池。若多餘一個任務被提交到該執行緒池,任務會被儲存在一個任務佇列中,待執行緒空閒,按先入先出的順序執行佇列中的任務。 newCachedThreadPool:建立一個快取執行緒池。執行緒池的執行緒數量不確定,如果有空閒執行緒可以複用,則會優先使用可複用的執行緒。如果所有執行緒均在工作,又有新的任務提交,則會建立新的執行緒處理任務。所有執行緒在當前任務執行完畢後,將返回執行緒池進行復用,預設60s之內未使用自動釋放。極端情況下,這樣會導致耗盡 cpu 和記憶體資源。 newScheduledThreadPool:建立一個可以執行延遲任務的執行緒池;可以實現迴圈或延遲任務,在對延遲任務和迴圈任務要求嚴格的時候,就需要考慮使用ScheduledExecutorService了。 newSingleThreadScheduledExecutor:建立一個單執行緒的可以執行延遲任務的執行緒池; newWorkStealingPool:建立一個搶佔式執行的執行緒池(任務執行順序不確定)【JDK 1.8 新增,使用ForkJoinPool實現】;
注意JDK、Tomcat以及Undertow 下核心執行緒、最大執行緒、工作佇列等數值及先後策略的不同!
設計模式在專案中的應用
先總結一下在Spring中用到的設計模式:
工廠設計模式 : Spring 使用工廠模式透過 BeanFactory、ApplicationContext 建立 bean 物件。 代理設計模式 : Spring AOP 功能的實現。 單例設計模式 : Spring 中的 Bean 預設都是單例的。 模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 結尾的對資料庫操作的類,它們就使用到了模板模式。 包裝器設計模式 : 我們的專案需要連線多個資料庫,而且不同的客戶在每次訪問中根據需要會去訪問不同的資料庫。這種模式讓我們可以根據客戶的需求能夠動態切換不同的資料來源。 觀察者模式: Spring 事件驅動模型就是觀察者模式很經典的一個應用。 介面卡模式 :Spring AOP 的增強或通知(Advice)使用到了介面卡模式、Spring MVC 中也是用到了介面卡模式適配Controller。
再舉兩三個在工作中用到的設計模式例子:
策略模式:在對接第三方系統時,採用策略模式來實現非同步通知返回引數的統一處理。推薦文章 模板方法模式:專案中的程式碼生成器基本都是採用了模板方法模式。透過定義一個抽象的程式碼生成演算法,並允許子類透過實現特定的步驟來定製生成演算法的不同部分。 單例模式:專案開發過程中,快取管理器、資料來源管理器等都會使用單例模式來確保在整個應用程式中只有一個例項,並提供全域性訪問點。
Spring
Spring 的生命週期
掃描包,透過註解掃描找到所有的Bean,生成 BeanDefinition 在 doGetBean 方法中例項化 bean,透過構造方法反射例項化 populateBean 方法進行屬性填充,遍歷所有需要注入的屬性,透過 inject 方法反射注入 執行回撥方法,例如 BeanNameAware、BeanClassLoaderAware、BeanFactoryAware 的方法 執行所有後置處理器的 postProcessBeforeInitialization 方法 執行bean生命週期回撥中的 init-method ,若 bean 實現了 InitializingBean 介面,執行 afterPropertiesSet 方法 執行所有後置處理器的 postProcessAfterInitialization
方法後續銷燬時,如果實現了 DisposableBean,執行destroy介面 如果定義了destroy-method,呼叫destroy方法
Spring 事務
事務管理方式
首先說一下 Spring 支援的兩種方式的事務管理
程式設計式事務 :在程式碼中硬編碼(不推薦使用) : 透過 TransactionTemplate 或者 TransactionManager 手動管理事務,實際應用中很少使用,但是對於你理解 Spring 事務管理原理有幫助。 宣告式事務 :在 XML 配置檔案中配置或者直接基於註解(推薦使用) : 實際是透過 AOP 實現(基於@Transactional 的全註解方式使用最多)
三大介面
然後說一下 Spring 事務管理中重要的介面
PlatformTransactionManager:(平臺)事務管理器,Spring 事務策略的核心。 TransactionDefinition:事務定義資訊(事務隔離級別、傳播行為、超時、只讀、回滾規則)。 TransactionStatus:事務執行狀態。
PlatformTransactionManager 介面可以被看作是事務上層的管理者,而 TransactionDefinition 和 TransactionStatus 這兩個介面可以看作是事務的描述。
PlatformTransactionManager 會根據 TransactionDefinition 的定義比如事務超時時間、隔離級別、傳播行為等來進行事務管理 ,而 TransactionStatus 介面則提供了一些方法來獲取事務相應的狀態比如,是否新事務、是否可以回滾等等。
透過 PlatformTransactionManager 介面,Spring 為各個平臺如:JDBC(DataSourceTransactionManager)、Hibernate(HibernateTransactionManager)、JPA(JpaTransactionManager)等都提供了對應的事務管理器,但是具體的實現就是各個平臺自己的事情了。
其次可以說一下資料的屬性
什麼是事務屬性呢?事務屬性可以理解成事務的一些基本配置,描述了事務策略如何應用到方法上。事務屬性包含了 5 個方面:隔離級別、傳播行為、回滾規則、是否只讀、事務超時。
其中隔離級別和傳播行為用的比較多
隔離級別
TransactionDefinition.ISOLATION_DEFAULT :使用後端資料庫預設的隔離級別,MySQL 預設採用的 REPEATABLE_READ 隔離級別 Oracle 預設採用的 READ_COMMITTED 隔離級別 TransactionDefinition.ISOLATION_READ_UNCOMMITTED :最低的隔離級別,使用這個隔離級別很少,因為它允許讀取尚未提交的資料變更,可能會導致髒讀、幻讀或不可重複讀 TransactionDefinition.ISOLATION_READ_COMMITTED : 允許讀取併發事務已經提交的資料,可以阻止髒讀,但是幻讀或不可重複讀仍有可能發生 TransactionDefinition.ISOLATION_REPEATABLE_READ : 對同一欄位的多次讀取結果都是一致的,除非資料是被本身事務自己所修改,可以阻止髒讀和不可重複讀,但幻讀仍有可能發生。 TransactionDefinition.ISOLATION_SERIALIZABLE : 最高的隔離級別,完全服從 ACID 的隔離級別。所有的事務依次逐個執行,這樣事務之間就完全不可能產生干擾,也就是說,該級別可以防止髒讀、不可重複讀以及幻讀。但是這將嚴重影響程式的效能。通常情況下也不會用到該級別。
事務傳播行為
TransactionDefinition.PROPAGATION_REQUIRED 使用的最多的一個事務傳播行為,我們平時經常使用的 @Transactional 註解預設使用就是這個事務傳播行為。如果當前存在事務,則加入該事務;如果當前沒有事務,則建立一個新的事務。 TransactionDefinition.PROPAGATION_REQUIRES_NEW 建立一個新的事務,如果當前存在事務,則把當前事務掛起。也就是說不管外部方法是否開啟事務,Propagation.REQUIRES_NEW 修飾的內部方法會新開啟自己的事務,且開啟的事務相互獨立,互不干擾。 TransactionDefinition.PROPAGATION_NESTED 如果當前存在事務,就在巢狀事務內執行——是指B事務巢狀在A事務中,兩者不是單獨的;如果當前沒有事務,就執行與 TransactionDefinition.PROPAGATION_REQUIRED 類似的操作。 TransactionDefinition.PROPAGATION_MANDATORY 如果當前存在事務,則加入該事務;如果當前沒有事務,則丟擲異常。(mandatory:強制性)這個使用的很少。 若是錯誤的配置以下 3 種事務傳播行為,事務將不會發生回滾:
TransactionDefinition.PROPAGATION_SUPPORTS: 如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續執行。 TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事務方式執行,如果當前存在事務,則把當前事務掛起。 TransactionDefinition.PROPAGATION_NEVER: 以非事務方式執行,如果當前存在事務,則丟擲異常。
注意事項
最後說一下 @Transactional 的使用注意事項
@Transactional 註解只有作用到 public 方法上事務才生效,不推薦在介面上使用; 避免同一個類中呼叫 @Transactional 註解的方法,這樣會導致事務失效; 正確的設定 @Transactional 的 rollbackFor 和 propagation 屬性,否則事務可能會回滾失敗; 被 @Transactional 註解的方法所在的類必須被 Spring 管理,否則不生效; 底層使用的資料庫必須支援事務機制,否則不生效;
Spring 如何實現多繼承的效果
在 Spring 框架中,有幾種方式可以實現多繼承的效果:
介面繼承:在 Spring 中,可以定義多個介面,並讓一個類實現多個介面。介面可以定義一組方法的規範,一個類可以實現多個介面來獲得這些方法的實現。透過介面繼承,一個類可以具備多個不同介面的功能。 組合:組合是指一個類包含其他類作為其成員變數。在 Spring 中,可以透過組合的方式將多個類組合成一個複合類,從而實現多個類的功能組合。這樣,複合類可以呼叫所包含類的方法,達到多繼承的效果。 AOP(面向切面程式設計):Spring 框架提供了面向切面程式設計的支援,透過切面可以在不修改原有類的情況下,為類動態地新增額外的功能。透過 AOP,可以將多個類的功能進行解耦和重用,實現類似於多繼承的效果。
SpringBoot 的自動裝配原理
@SpringBootApplication 註解由三個註解組成:@SpringBootConfiguration、@ComponentScan、@EnableAutoConfiguration。
基於 Spring 的 spi 擴充套件機制, @EnableAutoConfiguration 會讀取 META-INF/spring.factories
檔案,決定載入哪些類。
在引入的 SpringBoot Starter
中,在這個檔案中引入了 @Configuration 配置類:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.test.MyAutoConfiguration
配置類中的 @Bean 會被自動載入。
MySQL
JOIN 與 IN 如何選擇
查詢效率
在查詢效率方面,連表和IN子句都有各自的優缺點:
資料量大的情況下:
當涉及大量資料時,JOIN 通常比 IN 更有效率。因為資料庫最佳化器可以更好地對 JOIN 進行最佳化,執行計劃更穩定。 IN 子查詢在處理大資料量時可能會導致效能下降,特別是當子查詢返回大量結果集時。
如果表上有合適的索引,JOIN 通常會更快。因為資料庫可以利用索引直接定位到需要的資料。 IN 子查詢也可以利用索引,但是在某些情況下可能不如 JOIN 高效。
當子查詢返回的結果集非常小且能夠被高效地快取時,IN 子查詢可能會與 JOIN 一樣高效甚至更高效。
總的來說,如果你擁有合適的索引並且在大資料量的情況下,傾向於使用 JOIN 而不是 IN 子查詢。然而,在特定情況下,IN 子查詢也可能會更有效率。最佳做法是根據具體情況對兩種方法進行測試和比較,以確定哪種方法在特定場景下更高效。
可讀性
在可讀性方面,連表通常會比IN子句更易於理解和維護。
因為連表可以將兩個表中的資料進行關聯,從而在查詢結果中展現出來,而IN子句則需要使用列表或子查詢來進行匹配,不易於直觀地理解和維護。
靈活性
在靈活性方面,連表通常會比IN子句更具有靈活性。
因為連表可以根據不同的匹配條件進行查詢,可以實現比較複雜的查詢邏輯,而IN子句則只能進行簡單的列表或子查詢匹配,不太適用於複雜的查詢場景。
MySQL 什麼情況下需要調優
資料庫出現效能瓶頸時。如果資料庫遇到了讀取和寫入資料時的複雜操作或者面臨大量併發訪問時,可能會導致效能問題,需要透過最佳化來解決。 資料庫應用程式需要處理大量資料。如果應用程式需要處理大量的資料,需要使用索引來加快查詢速度。 查詢請求的響應時間很長。如果查詢將花費很長時間來執行操作,可能需要考慮資料庫最佳化,以降低響應時間。 資料庫訪問負載增加。如果資料庫訪問負載增加,可能會影響伺服器的響應能力和效能表現,因此需要最佳化。
MySQL 調優
說到MySQL調優,這個問題範圍比較寬泛,既可以包含硬體和系統調優,比如使用SSD硬碟,提高I/O效能,使用RAID配置,以提高磁碟讀寫效能等,又可以包含安全方面的調優:制定備份和恢復策略,複製和高可用性等。但是我們平時在面試的時候基本都是在問如何提高sql的查詢速度,接下來我們就從這個方向梳理一下思路。
執行計劃
我們通常會使用 EXPLAIN 命令來獲取SQL的執行計劃資訊。透過執行計劃,我們可以瞭解到資料表的查詢順序、資料查詢操作的操作型別、哪些索引可以被命中、哪些索引實際會命中、每個資料表有多少行記錄被查詢等資訊,以便我們更好的調優。
當我們執行 EXPLAIN 命令之後,我們主要關注type、key和 Extra 等幾項資訊:
type 被稱為連線型別(join type)或者訪問型別(access type),它顯示了 MySQL 如何訪問表中的資料。訪問型別會直接影響到查詢語句的效能,效能從好到差依次為(特別重要,被問多次):
system:表中只有一行資料(系統表),這是 const 型別的特殊情況; const:最多返回一條匹配的資料,在查詢的最開始讀取;常用於使用主鍵或唯一索引的所有欄位作為查詢條件。 eq_ref:當連表查詢時,對於前面的每一行,從該表中讀取一行資料;是除了 system 與 const 之外最好的 join 方式。 ref:對於前面的每一行,從該表中讀取匹配索引值的所有資料行; fulltext:透過 FULLTEXT 索引查詢資料; ref_or_null:與 ref 類似,額外加上 NULL 值查詢; index_merge:當查詢條件使用了多個索引時,表示開啟了 Index Merge 最佳化,此時執行計劃中的 key 列列出了使用到的索引。 unique_subquery:替代以下情況時的 eq_ref: value IN (SELECT primary_key FROM single_table WHERE some_expr)
;index_subquery:與 unique_subquery 類似,用於子查詢中的非唯一索引: value IN (SELECT key_column FROM single_table WHERE some_expr)
;range:使用索引查詢範圍值; index:與 ALL 型別相同,只不過掃描的是索引; ALL:全表掃描,通常表示存在效能問題。
key 列表示 MySQL 實際使用到的索引。如果為 NULL,則表示未用到索引。
Extra包含了 MySQL 解析查詢的額外資訊,透過這些資訊,可以更準確的理解 MySQL 到底是如何執行查詢的。常見的值如下:
Using filesort:在排序時使用了外部的索引排序,沒有用到表內索引進行排序。 Using temporary:MySQL 需要建立臨時表來儲存查詢的結果,常見於 ORDER BY 和 GROUP BY。 Using index:表明查詢使用了覆蓋索引,不用回表,查詢效率非常高。 Using index condition:表示查詢最佳化器選擇使用了索引條件下推這個特性。 Using where:表明查詢使用了 WHERE 子句進行條件過濾。一般在沒有使用到索引的時候會出現。 Using join buffer (Block Nested Loop):連表查詢的方式,表示當被驅動表的沒有使用索引的時候,MySQL 會先將驅動表讀出來放到 join buffer 中,再遍歷被驅動表與驅動表進行查詢。
最後我們再說一下根據執行計劃的結果進行SQL最佳化和索引最佳化的規則。
SQL最佳化
應儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引; 應儘量避免在 where 子句中對欄位進行 null 值判斷, 使用!=或<>;減少or來連線條件,使用union all代替;in 和 not in 也要慎用;減少表示式操作和函式操作;否則將導致引擎放棄使用索引而進行全表掃描。 任何地方都不要使用 select * from t ,用具體的欄位列表代替"*",不要返回用不到的任何欄位。 一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有必要。 很多時候用 exists 代替 in 是一個好的選擇。 儘量減少多表聯合查詢,可以在表中冗餘所需的欄位。
索引最佳化
此類最佳化可以參考下文建立索引的規則來進行索引最佳化。
Hash 索引和B+樹索引的區別
雜湊索引適合等值查詢,但是無法進行範圍查詢 ; 雜湊索引沒法利用索引完成排序; 雜湊索引不支援多列聯合索引的最左匹配規則; 如果有大量重複鍵值的情況下,雜湊索引的效率會很低,因為存在雜湊碰撞問題;
建立索引規則
限制每張表上的索引數量,建議單張表索引不超過 5 個; 被頻繁查詢的欄位建立索引; 經常用於 WHERE、ORDER BY、GROUP BY、DISTINCT 後的的欄位建議建立索引; 上條中的欄位列不要都建立索引,建議建立聯合索引; 多表 join 的關聯列建議建立索引; 禁止使用全文索引; 被頻繁更新的欄位應該慎重建立索引; 字串型別的欄位使用字首索引代替普通索引; 刪除長期未使用的索引;
Redis
快取穿透
快取穿透說簡單點就是大量請求的 key 是不合理的,根本不存在於快取中,也不存在於資料庫中 。這就導致這些請求直接到了資料庫上,根本沒有經過快取這一層,對資料庫造成了巨大的壓力,可能直接就被這麼多請求弄當機了。
有哪些解決辦法?
最基本的就是首先做好引數校驗,一些不合法的引數請求直接丟擲異常資訊返回給客戶端。比如查詢的資料庫 id 不能小於 0、傳入的郵箱格式不對的時候直接返回錯誤訊息給客戶端等等。
(1)快取無效 key。
如果快取和資料庫都查不到某個 key 的資料就寫一個到 Redis 中去並設定過期時間,這種方式可以解決請求的 key 變化不頻繁的情況。
如果駭客惡意攻擊,每次構建不同的請求 key,會導致 Redis 中快取大量無效的 key 。很明顯,這種方案並不能從根本上解決此問題。如果非要用這種方式來解決穿透問題的話,儘量將無效的 key 的過期時間設定短一點比如 1 分鐘。
(2)布隆過濾器
把所有可能存在的請求的值都存放在布隆過濾器中,當使用者請求過來,先判斷使用者發來的請求的值是否存在於布隆過濾器中。不存在的話,直接返回請求引數錯誤資訊給客戶端,存在的話才會走下面的流程。
但是,需要注意的是布隆過濾器可能會存在誤判的情況。布隆過濾器說某個元素存在,小機率會誤判。布隆過濾器說某個元素不在,那麼這個元素一定不在。如果想減少誤判率,可以適當增加 hash 函式。
快取擊穿
快取擊穿中,請求的 key 對應的是熱點資料 ,該資料存在於資料庫中,但不存在於快取中(通常是因為快取中的那份資料已經過期) 。這就可能會導致瞬時大量的請求直接打到了資料庫上,對資料庫造成了巨大的壓力,可能直接就被這麼多請求弄當機了。
有哪些解決辦法?
設定熱點資料永不過期或者過期時間比較長。 針對熱點資料提前預熱,將其存入快取中並設定合理的過期時間比如秒殺場景下的資料在秒殺結束之前不過期。 請求資料庫寫資料到快取之前,先獲取互斥鎖,保證只有一個請求會落到資料庫上,減少資料庫的壓力。
快取雪崩
快取在同一時間大面積的失效,導致大量的請求都直接落到了資料庫上,對資料庫造成了巨大的壓力。這就好比雪崩一樣,摧枯拉朽之勢,資料庫的壓力可想而知,可能直接就被這麼多請求弄當機了。另外,快取服務當機也會導致快取雪崩現象,導致所有的請求都落到了資料庫上。
有哪些解決辦法?
針對 Redis 服務不可用的情況:
採用 Redis 叢集,避免單機出現問題整個快取服務都沒辦法使用。 限流:避免同時處理大量的請求。
針對熱點快取失效的情況:
設定不同的失效時間比如隨機設定快取的失效時間。 快取永不失效(不太推薦,實用性太差)。 設定二級快取。
Redis 當機了怎麼辦?
當聽到這個面試題的時候我最先想到的是Redis的持久化,可以採用RDB或者AOF來實現,以及兩種方式的備份策略和機器重啟之後的資料恢復機制。
當我回頭將面試題拋給我的小夥伴時,他們紛紛表示面試官是在問單體架構的不完整性,我聽完之後才恍然大悟。那麼我們今天就簡單介紹下Redis的哨兵機制和叢集吧。
哨兵機制
Redis的哨兵機制是一種高可用性解決方案,由一個或多個Sentinel 例項組成的 Sentinel 系統可以監視任意多個主伺服器以及這些主伺服器屬下的所有從伺服器,並在被監視的主伺服器進入下線狀態時,自動將下線主伺服器屬下的某個從伺服器升級為新的主伺服器。簡單的說,哨兵就是帶有自動故障轉移功能的主從架構。
其主要功能包括:
叢集監控:負責監控主從伺服器程式是否正常工作。 故障轉移:如果master當機,會自動從slave中選舉出新的master,進行主從自動切換。 配置中心:如果發生了故障轉移,sentinel負責通知客戶端新的master地址。 訊息通知:如果某個redis節點有故障,sentinel會傳送報警訊息給系統管理員。
Redis叢集
Redis3.0 加入了 Redis 的叢集模式,實現了資料的分散式儲存,對資料進行分片,將不同的資料儲存在不同的 master 節點上面,從而解決了海量資料的儲存問題。
Redis叢集採用去中心化的思想,沒有中心節點的說法,對於客戶端來說,整個叢集可以看成一個整體,可以連線任意一個節點進行操作,就像操作單一Redis 例項一樣,不需要任何代理中介軟體,當客戶端操作的 key 沒有分配到該 node 上時,Redis 會返回轉向指令,指向正確的 node。
Redis 也內建了高可用機制,支援N個 master 節點,每個 master 節點都可以掛載多個 slave 節點,當 master 節點掛掉時,叢集會提升它的某個 slave 節點作為新的 master 節點。
Redis叢集可以看成多個主從架構組合起來的,每一個主從架構可以看成一個節點(其中,只有 master 節點具有處理請求的能力,slave 節點主要是用於節點的高可用)
Redis在專案中的使用場景
使用 String 結構來儲存 token、驗證碼等資訊; 使用 List 結構來查詢最新的文章或者最新的動態; 使用 Hash 結構來儲存使用者資訊、商品資訊、文章資訊、購物車資訊; 使用 Set 結構根據差集可以做好友推薦、音樂推薦,根據交集可以做共同關注、共同好友,還可以利用隨機函式來做抽獎系統; 使用 ZSet 結構來開發直播間送禮物的排行榜、朋友圈的微信步數排行榜等; 使用 Bitmap 結構來統計使用者簽到情況、還可以用來做數十億資料的去重; 使用 HyperLogLog 結構可以用來做熱門網站每日訪問 ip 數統計、熱門帖子 uv 統計; 使用 GEO 可以輕鬆實現兩個位置距離的計算,獲取指定位置附近的元素等功能; 透過監聽 redis 的過期 key 來實現訂單自動關閉的功能; 可以使用 Redis Cluster 基於 Redis 的 incr 命令實現分散式id; 使用 Redis+Lua 指令碼實現分散式鎖;
SpringCloud
服務熔斷
在微服務架構中通常會有多個服務層呼叫,基礎服務的故障可能會導致級聯故障,進而造成整個系統不可用的情況,這種現象被稱為服務雪崩效應。服務雪崩效應是一種因“服務提供者”的不可用導致“服務消費者”的不可用,並將不可用逐漸放大的過程。
熔斷器的原理很簡單,如同電力過載保護器。它可以實現快速失敗,如果它在一段時間內偵測到許多類似的錯誤,會強迫其以後的多個呼叫快速失敗,不再訪問遠端伺服器,從而防止應用程式不斷地嘗試執行可能會失敗的操作,使得應用程式繼續執行而不用等待修正錯誤,或者浪費 CPU時間去等到長時間的超時產生。熔斷器也可以使應用程式能夠診斷錯誤是否已經修正,如果已經修正,應用程式會再次嘗試呼叫操作。
Hystrix 斷路器機制
當 Hystrix Command 請求後端服務失敗數量超過一定比例(預設 50%),斷路器會切換到開路狀態(Open)。這時所有請求會直接失敗而不會傳送到後端服務,斷路器保持在開路狀態段時間後(預設 5 秒),自動切換到半開路態(HALF-OPEN),這時會判斷下一次請求的返回情況如果請求成功,斷路器切回閉路狀態(CLOSED),否則重新切換到開路狀態(OPEN)。
Eureka 和 Nacos 的對比
Eureka | Nacos | |
---|---|---|
開源社群 | Netflix | 阿里巴巴 |
註冊中心 | 是 | 是 |
CAP | AP | AP + CP |
配置中心 | 否 | 是,支援動態重新整理 |
服務發現 | 定時拉取 | 定時拉取、訂閱推送 |
例項型別 | 臨時例項 | 永久例項、臨時例項(預設,由引數決定 ephemeral=true) |
健康檢測 | 心跳模式 | 臨時例項採用心跳檢測模式,永久例項採用主動請求檢測模式 |
保護方式 | 如果15分鐘之內,心跳傳送失敗的比例低於85%,就會觸發Eureka服務端的自我保護機制。在該機制下,Eureka Server 不會剔除任何的微服務,等到正常後,再退出自我保護機制。 | 當域名健康例項佔總服務例項的比例小於閾值時,無論例項是否健康,都會將這個例項返回給客戶端。客戶端可能訪問到不健康的例項,請求失敗,但不至於造成雪崩。犧牲了⼀些請求,保證了整個系統的可⽤。 |
高可用機制 | 多副本之間的複製採用對等複製(peer to peer模式),每個副本都可以處理讀寫請求,透過彼此之間的資料複製使資料進行同步更新。但是資料同步可能會出現衝突。Eureka對此的解決方案是校驗 lastDirtyTimestamp。 | 內部提供兩種資料同步方案AP和CP,而且是混用的。例項是臨時的預設用AP,AP使用 Distro 協議,採用對等複製模式;例項是永久的用CP,CP使用 Raft 協議作為預設的一致性協議,採用 Leader-Follower 同步方式保證資料一致性。 |
參考連結:
來自 “ ITPUB部落格 ” ,連結:https://blog.itpub.net/70024924/viewspace-3000415/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 整理了一波免費好用的api,分享給大家API
- 最近去騰訊面試了,分享一波面試題面試題
- 一波了!一波了!==== 今天閱讀原始碼學習了一個 204 的狀態碼,分享給大家。原始碼
- 寫給自己看的面試題整理面試題
- 梳理一波面試題面試題
- Github | Rust整理資料,分享給大家,多謝大家的支援GithubRust
- 面試題整理面試題
- 金三銀四跳槽季,這些面試題你都會了嗎?面試題
- [求職]大家有開始跳槽麼?求職
- 「面試題」20+Vue面試題整理面試題Vue
- CSS面試題整理CSS面試題
- JavaScript面試題整理JavaScript面試題
- Laravel 面試題整理Laravel面試題
- Flume面試題整理面試題
- 近期面試題整理面試題
- 寫給自己看的面試題整理-演算法&某東筆試題面試題演算法筆試
- 一文整理使用過的好用api,分享給大家API
- 常見面試題整理,金三銀四全靠它了面試題
- [面試題]大廠常見面試題整理面試題
- 【面試】面試常見問題整理面試
- 小小java面試題(請教大家)Java面試題
- 面試題,大家也可以看看(piner)面試題
- linux面試題整理Linux面試題
- 面試題整理—CSS部分面試題CSS
- Java面試題整理《上》Java面試題
- 前端面試題整理前端面試題
- Spark面試題整理(三)Spark面試題
- iOS 面試題整理(一)iOS面試題
- C++ 面試題整理C++面試題
- 前端掌握這一波面試題,面試加薪無憂無慮前端面試題
- 分享一波特別騷的 PHP 面試題目PHP面試題
- Web前端年後跳槽必看的各種面試題Web前端面試題
- 我的面試題,大家也可以看看面試題
- HashMap常見面試題整理HashMap面試題
- Vue.js 面試題整理Vue.js面試題
- Vue常見面試題整理Vue面試題
- 整理kafka常見面試題Kafka面試題
- 面試題整理之Vue篇面試題Vue