一、叢集、分布式、微服務的了解
1、叢集是個實體形态,分布式是個工作方式。
分布式:一個業務分拆多個子業務,部署在不同的伺服器上
叢集:同一個業務,部署在多個伺服器上
2、分布式是指将不同的業務分布在不同的地方。而叢集指的是将幾台伺服器集中在一起,實作同一業務。
分布式的每一個節點,都完成不同的業務,一個節點垮了,那這個業務就不可通路了。分布式是以縮短單個任務的執行時間來提升效率的,而叢集則是通過提高機關時間内執行的任務數來提升效率。
分布式中的每一個節點,都可以做叢集。而叢集并不一定就是分布式的。
舉例:就比如新浪網,通路的人多了,他可以做一個群集,前面放一個響應伺服器,後面幾台伺服器完成同一業務,如果有業務通路的時候,響應伺服器看哪台伺服器的負載不是很重,就将給哪一台去完成。
而分布式,從窄意上了解,也跟叢集差不多,但是它的組織比較松散,不像叢集,有一個組織性,一台伺服器垮了,其它的伺服器可以頂上來。
3、微服務将子產品拆分成一個獨立的服務單元通過接口來實作資料的互動。把系統拆分成一個個小服務,技術團隊通過技術選型,每個服務單獨開發,獨立部署運作。
微服務将單一應用程式劃分成一組小的服務,每個服務運作獨立的自己的程序中,服務之間互相協調、互相配合,為使用者提供最終價值。
服務之間采用輕量級的通信機制互相溝通(通常是基于 HTTP 的 RESTful API) 。每個服務都圍繞着具體業務進行建構,并且能夠被獨立地部署到生産環境、類生産環境等。
二、springboot自動化配置
@SpringBootApplication裡面包含一下三個注解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
@SpringBootConfiguration:标記目前類為配置類。
@EnableAutoConfiguration:開啟自動配置,利用AutoConfigurationImportSelector給容器中導入一些元件。
@ComponentScan:掃描主類所在的同級包以及下級包裡的Bean,元件掃描和自動裝配。
關鍵是@EnableAutoConfiguration。
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
三、springcloud元件
SpringCloud分布式開發五大元件詳解
服務發現——Netflix Eureka
客服端負載均衡——Netflix Ribbon
斷路器——Netflix Hystrix,SOA/微服務架構中提供服務隔離、熔斷、降級機制的工具/架構。Netflix Hystrix是斷路器的一種實作,用于高微服務架構的可用性,是防止服務出現雪崩的利器。
服務網關——Netflix Zuul
分布式配置——Spring Cloud Config
四、常見負載均衡政策
1、輪詢法
将請求按順序輪流地配置設定到後端伺服器上,它均衡地對待後端的每一台伺服器,而不關心伺服器實際的連接配接數和目前的系統負載。
輪詢算法是最簡單的一種負載均衡算法。它的原理是把來自使用者的請求輪流配置設定給内部的伺服器:從伺服器1開始,直到伺服器N,然後重新開始循環。
算法的優點是其簡潔性,它無需記錄目前所有連接配接的狀态,是以它是一種無狀态排程。
每個請求按時間順序逐一配置設定到不同的後端伺服器,如果後端伺服器down掉,能自動剔除。
2、随機法
通過系統的随機算法,根據後端伺服器的清單大小值來随機選取其中的一台伺服器進行通路。由機率統計理論可以得知,随着用戶端調用服務端的次數增多,其實際效果越來越接近于平均配置設定調用量到後端的每一台伺服器,也就是輪詢的結果。
3、源位址哈希法
源位址哈希的思想是根據擷取用戶端的IP位址,通過哈希函數計算得到的一個數值,用該數值對伺服器清單的大小進行取模運算,得到的結果便是客服端要通路伺服器的序号。采用源位址哈希法進行負載均衡,同一IP位址的用戶端,當後端伺服器清單不變時,它每次都會映射到同一台後端伺服器進行通路。
每個請求按通路ip的hash結果配置設定,這樣每個訪客固定通路一個後端伺服器,可以解決session的問題。
4、權重輪詢法
不同的後端伺服器可能機器的配置和目前系統的負載并不相同,是以它們的抗壓能力也不相同。給配置高、負載低的機器配置更高的權重,讓其處理更多的請;而配置低、負載高的機器,給其配置設定較低的權重,降低其系統負載,權重輪詢能很好地處理這一問題,并将請求順序且按照權重配置設定到後端。
5、權重随機法
與權重輪詢法一樣,權重随機法也根據後端機器的配置,系統的負載配置設定不同的權重。不同的是,它是按照權重随機請求後端伺服器,而非順序。
6、最小連接配接數法
最小連接配接數算法比較靈活和智能,由于後端伺服器的配置不盡相同,對于請求的處理有快有慢,它是根據後端伺服器目前的連接配接情況,動态地選取其中目前積壓連接配接數最少的一台伺服器來處理目前的請求,盡可能地提高後端服務的利用效率,将負責合理地分流到每一台伺服器。
五、spring的了解
1、spring原理
spring是按照設計模式精心打造的,它實作了工廠模式的工廠類,這個類名為BeanFactory(接口),在程式中通常使用它的子類ApplicationContext(也是接口)。
spring的核心是IOC(反轉控制)容器,IOC也是一種程式設計思想,用于實作子產品之間的解耦,在Spring中它的作用是對對象的建立,維護和銷毀等生命周期的控制。IOC:把對象的建立、初始化、銷毀交給spring來管理,而不是由開發者控制,實作控制反轉。
spring是一個大的工廠類,spring的特點就是基于配置,在其配置檔案中通過<bean>元素來建立執行個體對象。
根據業務邏輯來看,對象經常不是獨立的,一個對象的建立往往涉及另一個對象的建立,當然這個對象也要由IOC容器負責,負責的方式就是依賴注入DI,通過反射機制實作。
有三種注入方式:(1)接口注入(2)構造器注入(3)Setter方法注入。
2.spring的核心技術
spring的核心技術有:IOC,AOP
java 的 進階特性:反射機制,代理
IOC:依賴注入,就是由IOC容器在運作期間,動态地将某種依賴關系注入到對象之中。
AOP:面向切面程式設計,系統中有很多各不相幹的類的方法,在這衆多方法中加入某種系統功能的代碼,如加入日志,權限判斷等,AOP可以實作橫切關注點(如日志,安全,緩存和事務管理)與他們所影響的對象之間的解耦。
實作AOP 功能采用的是代理技術,調用代理類,代理類與目标類具有相同的方法聲明。
AOP 在spring中主要表現在兩個方面:提供聲明式的事務管理 、spring支援使用者自定義切面。
AOP主要包括通知(Advice)切點(PointCut)連接配接點(JoinPoint)
AspectJ實際上是對AOP程式設計思想的一個實踐
3、spring 優缺點
Spring的核心概念是IOC和AOP,這兩個核心服務的對象算是bean(POJO)。
它具備以下優點:
spring中避免了關鍵字new造成的耦合問題。
spring本身就是一個工廠,不需要再編寫工廠類了。
spring不需要進行明确的引用關系的傳遞,直接通過配置完成
所有架構幾乎都可以在spring中整合在一起使用。
spring程式設計=factory設計模式+proxy設計模式
當然,它的缺點也是不少的:
spring基于大量的xml 配置檔案,使得我們花了大量的時間放在配置上,拖慢了開發的進度,springboot 問世後,提倡代碼優于配置解決了這個問題。
spring的内容太龐大,随便打斷點檢視的時候會出現十幾二十層代碼,閱覽性不強。
六、jdk動态代理和cglib代理的差別
JDK動态代理隻能對實作了接口的類生成代理,而不能針對類
CGLIB是針對類實作代理,主要是對指定的類生成一個子類,覆寫其中的方法(繼承)
Spring在選擇用JDK還是CGLiB的依據:
(1)當Bean實作接口時,Spring就會用JDK的動态代理(java.lang.reflect.Proxy類代理)
優點:因為有接口,是以使系統更加松耦合
缺點:為每一個目标類建立接口
(2)當Bean沒有實作接口時,Spring使用CGlib
優點:因為代理類與目标類是繼承關系,是以不需要有接口的存在。
缺點:因為沒有使用接口,是以系統的耦合性沒有使用JDK的動态代理好。
(3)可以強制使用CGlib(在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)
CGlib比JDK快?
(1)使用CGLib實作動态代理,CGLib底層采用ASM位元組碼生成架構,使用位元組碼技術生成代理類,比使用Java反射效率要高。唯一需要注意的是,CGLib不能對聲明為final的方法進行代理,因為CGLib原理是動态生成被代理類的子類。
(2)在對JDK動态代理與CGlib動态代理的代碼實驗中看,1W次執行下,JDK7及8的動态代理性能比CGlib要好20%左右。
七、HashMap底層(待完善)
在JDK1.6,JDK1.7中,HashMap采用位桶+連結清單實作,即使用連結清單處理沖突,同一hash值的連結清單都存儲在一個連結清單裡。但是當位于一個桶中的元素較多,即hash值相等的元素較多時,通過key值依次查找的效率較低。而JDK1.8中,HashMap采用位桶+連結清單+紅黑樹實作,當連結清單長度超過門檻值(8)時,将連結清單轉換為紅黑樹,這樣大大減少了查找時間。
HashMap采用Entry數組來存儲key-value對,每一個鍵值對組成了一個Entry實體,Entry類實際上是一個單向的連結清單結構,它具有Next指針,可以連接配接下一個Entry實體,依次來解決Hash沖突的問題,因為HashMap是按照Key的hash值來計算Entry在HashMap中存儲的位置的,如果hash值相同,而key内容不相等,那麼就用連結清單來解決這種hash沖突。
HashMap初始容量16,每次擴容的次數是2倍。
1.HashMap jdk 1.8有哪些變化:
在jdk1.6,jdk1.7 中HashMap 采用 位桶+連結清單 方式
jdk1.8 中采用 位桶 + 連結清單 + 紅黑樹 方式(當連結清單大于8的時候轉換為紅黑樹)優勢:查詢性能得都很大提升。
2.什麼是紅黑樹,優勢劣勢:
紅黑樹是平衡二叉樹的一種算法提現(AVL、Treap…),它有很多限制組成,其中包括
(1).每個節點不是紅色就是黑色。
(2).跟節點永遠是黑色。
(3).所有葉子節點都是黑色。
(4).每個葉子不會有兩個連續的節點。
(5).從任一節點到其子樹中每個葉子節點的路徑都包含相同數量的黑色節點。中和來說 紅黑樹中最長路徑就是一條紅黑交替的路徑。(可以多元度去了解它在記憶體中的位置區間)
優劣勢:優點,由于限制是以紅黑樹的深度不像二叉樹那麼深,隻要保持平衡,它的檢索性能比較高。
缺點,紅黑樹在進行插入或删除操作的時候由于需要維護紅黑樹的特點,是以需要提供樹結構維護。
3. HashMap描述
(1). Hash索引的計算,根據HashMap 長度計算與計算出的hashCode值做位于運算決定索引/位置(結論:長度取2次方是減少沖突的最好方式)
(2). Hash沖突 hashMap使用連結清單發解決沖突,當發生沖突的時候将key/vlaue放在該位置的連結清單末端。
八、mysql隔離級别
mysql預設隔離級别repeatable可重複讀,oracle,sql server預設隔離級别read commited讀取送出内容
事務的 四個特征(ACID)
事務具有四個特征:原子性( Atomicity )、一緻性( Consistency )、隔離性( Isolation )和持續性( Durability )。這四個特性簡稱為 ACID 特性。
1 、原子性。事務是資料庫的邏輯工作機關,事務中包含的各操作要麼都做,要麼都不做
2 、一緻性。事 務執行的結果必須是使資料庫從一個一緻性狀态變到另一個一緻性狀态。是以當資料庫隻包含成功事務送出的結果時,就說資料庫處于一緻性狀态。如果資料庫系統 運作中發生故障,有些事務尚未完成就被迫中斷,這些未完成事務對資料庫所做的修改有一部分已寫入實體資料庫,這時資料庫就處于一種不正确的狀态,或者說是 不一緻的狀态。
3 、隔離性。一個事務的執行不能其它事務幹擾。即一個事務内部的操作及使用的資料對其它并發事務是隔離的,并發執行的各個事務之間不能互相幹擾。
4 、持續性。也稱永久性,指一個事務一旦送出,它對資料庫中的資料的改變就應該是永久性的。接下來的其它操作或故障不應該對其執行結果有任何影響。
Mysql的四種隔離級别
SQL标準定義了4類隔離級别,包括了一些具體規則,用來限定事務内外的哪些改變是可見的,哪些是不可見的。低級别的隔離級一般支援更高的并發處理,并擁有更低的系統開銷。
Read Uncommitted(讀取未送出内容)
在該隔離級别,所有事務都可以看到其他未送出事務的執行結果。本隔離級别很少用于實際應用,因為它的性能也不比其他級别好多少。讀取未送出的資料,也被稱之為髒讀(Dirty Read)。
Read Committed(讀取送出内容)
這是大多數資料庫系統的預設隔離級别(但不是MySQL預設的)。它滿足了隔離的簡單定義:一個事務隻能看見已經送出事務所做的改變。這種隔離級别 也支援所謂的不可重複讀(Nonrepeatable Read),因為同一事務的其他執行個體在該執行個體處理其間可能會有新的commit,是以同一select可能傳回不同結果。
Repeatable Read(可重讀)
這是MySQL的預設事務隔離級别,它確定同一事務的多個執行個體在并發讀取資料時,會看到同樣的資料行。不過理論上,這會導緻另一個棘手的問題:幻讀 (Phantom Read)。簡單的說,幻讀指當使用者讀取某一範圍的資料行時,另一個事務又在該範圍内插入了新行,當使用者再讀取該範圍的資料行時,會發現有新的“幻影” 行。InnoDB和Falcon存儲引擎通過多版本并發控制(MVCC,Multiversion Concurrency Control)機制解決了該問題。
Serializable(可串行化)
這是最高的隔離級别,它通過強制事務排序,使之不可能互相沖突,進而解決幻讀問題。簡言之,它是在每個讀的資料行上加上共享鎖。在這個級别,可能導緻大量的逾時現象和鎖競争。
出現問題
這四種隔離級别采取不同的鎖類型來實作,若讀取的是同一個資料的話,就容易發生問題。例如:
髒讀(Drity Read):某個事務已更新一份資料,另一個事務在此時讀取了同一份資料,由于某些原因,前一個RollBack了操作,則後一個事務所讀取的資料就會是不正确的。
不可重複讀(Non-repeatable read):在一個事務的兩次查詢之中資料不一緻,這可能是兩次查詢過程中間插入了一個事務更新的原有的資料。
幻讀(Phantom Read):在一個事務的兩次查詢中資料筆數不一緻,例如有一個事務查詢了幾列(Row)資料,而另一個事務卻在此時插入了新的幾列資料,先前的事務在接下來的查詢中,就會發現有幾列資料是它先前所沒有的。
在MySQL中,實作了這四種隔離級别,分别有可能産生問題如下所示:
九、Hibernate 和Mybatis
1 簡單簡介
1.1 Hibernate 架構
Hibernate是一個開放源代碼的對象關系映射架構,它對JDBC進行了非常輕量級的對象封裝,建立對象與資料庫表的映射。是一個全自動的、完全面向對象的持久層架構。
1.2 Mybatis架構
Mybatis是一個開源對象關系映射架構,原名:ibatis,2010年由谷歌接管以後更名。是一個半自動化的持久層架構。
2 兩者差別
2.1 開發方面
在項目開發過程當中,就速度而言:
hibernate開發中,sql語句已經被封裝,直接可以使用,加快系統開發;
Mybatis 屬于半自動化,sql需要手工完成,稍微繁瑣;
但是,凡事都不是絕對的,如果對于龐大複雜的系統項目來說,發雜語句較多,選擇hibernate 就不是一個好方案。
2.2 sql優化方面
Hibernate 自動生成sql,有些語句較為繁瑣,會多消耗一些性能;
Mybatis 手動編寫sql,可以避免不需要的查詢,提高系統性能;
2.3 對象管理比對
Hibernate 是完整的對象-關系映射的架構,開發工程中,無需過多關注底層實作,隻要去管理對象即可;
Mybatis 需要自行管理 映射關系;
2.4 緩存方面
相同點:
Hibernate和Mybatis的二級緩存除了采用系統預設的緩存機制外,都可以通過實作你自己的緩存或為其他第三方緩 存方案,建立擴充卡來完全覆寫緩存行為。
不同點:
Hibernate的二級緩存配置在SessionFactory生成的配置檔案中進行詳細配置,然後再在具體的表-對象映射中配置是那種緩存。
MyBatis的二級緩存配置都是在每個具體的表-對象映射中進行詳細配置,這樣針對不同的表可以自定義不同的緩存機制。并且Mybatis可以在命名空間中共享相同的緩存配置和執行個體,通過Cache-ref來實作。
比較:
Hibernate 具有良好的管理機制,使用者不需要關注SQL,如果二級緩存出現髒資料,系統會儲存,;
Mybatis 在使用的時候要謹慎,避免緩存Cache 的使用。
Hibernate優勢
Hibernate的DAO層開發比MyBatis簡單,Mybatis需要維護SQL和結果映射。
Hibernate對對象的維護和緩存要比MyBatis好,對增删改查的對象的維護要友善。
Hibernate資料庫移植性很好,MyBatis的資料庫移植性不好,不同的資料庫需要寫不同SQL。
Hibernate有更好的二級緩存機制,可以使用第三方緩存。MyBatis本身提供的緩存機制不佳。
Mybatis優勢
MyBatis可以進行更為細緻的SQL優化,可以減少查詢字段。
MyBatis容易掌握,而Hibernate門檻較高。
一句話總結
Mybatis:小巧、友善、高效、簡單、直接、半自動化
Hibernate:強大、友善、高效、複雜、間接、全自動化
mybatis緩存問題
#使全局的映射器啟用或禁用緩存。
mybatis.configuration.cache-enabled=true
#全局啟用或禁用延遲加載。當禁用時,所有關聯對象都會即時加載。
mybatis.configuration.lazy-loading-enabled=true
#當啟用時,有延遲加載屬性的對象在被調用時将會完全加載任意屬性。否則,每種屬性将會按需要加載。
mybatis.configuration.aggressive-lazy-loading=true
十、Redis21問
1.什麼是 redis?
Redis 是一個基于記憶體的高性能 key-value 資料庫。
2.Reids 的特點
Redis 本質上是一個 Key-Value 類型的記憶體資料庫,很像 memcached,整個資料庫統統加載在記憶體當中進行操作,定期通過異步操作把資料庫資料 flush 到硬碟上進行儲存。因為是純記憶體操作,Redis 的性能非常出色,每秒可以處理超過 10 萬次讀寫操作,是已知性能最快的 Key-Value DB。
Redis 的出色之處不僅僅是性能,Redis 最大的魅力是支援儲存多種資料結構,此外單個 value 的最大限制是 1GB,不像 memcached 隻能儲存 1MB 的資料,是以 Redis 可以用來實作很多有用的功能,比方說用他的 List 來做 FIFO 雙向連結清單,實作一個輕量級的高性 能消息隊列服務,用他的 Set 可以做高性能的 tag 系統等等。另外 Redis 也可以對存入的 Key-Value 設定 expire 時間,是以也可以被當作一 個功能加強版的 memcached 來用。
Redis 的主要缺點是資料庫容量受到實體記憶體的限制,不能用作海量資料的高性能讀寫,是以 Redis 适合的場景主要局限在較小資料量的高性能操作和運算上。
3.使用 redis 有哪些好處?
1.速度快,因為資料存在記憶體中,類似于 HashMap,HashMap 的優勢就是查找和操作的時間複雜度都是 O(1)
2.支援豐富資料類型,支援 string,list,set,sorted set,hash
1)String
常用指令:set/get/decr/incr/mget 等;
應用場景:String 是最常用的一種資料類型,普通的 key/value 存儲都可以歸為此類;
實作方式:String 在 redis 内部存儲預設就是一個字元串,被 redisObject 所引用,當遇到 incr、decr 等操作時會轉成數值型進行計算,此時 redisObject 的 encoding 字段為 int。
2)Hash
常用指令:hget/hset/hgetall 等
應用場景:我們要存儲一個使用者資訊對象資料,其中包括使用者 ID、使用者姓名、年齡和生日,通過使用者 ID 我們希望擷取該使用者的姓名或者年齡或者生日;
實作方式:Redis 的 Hash 實際是内部存儲的 Value 為一個 HashMap,并提供了直接存取這個 Map 成員的接口。Key 是使用者 ID, value 是一個 Map。這個 Map 的 key 是成員的屬性名,value 是屬性值。這樣對資料的修改和存取都可以直接通過其内部 Map 的 Key(Redis 裡稱内部 Map 的 key 為 field), 也就是通過 key(使用者 ID) + field(屬性标簽) 就可以操作對應屬性資料。
目前 HashMap 的實作有兩種方式:當 HashMap 的成員比較少時 Redis 為了節省記憶體會采用類似一維數組的方式來緊湊存儲,而不會采用真正的 HashMap 結構,這時對應的 value 的 redisObject 的 encoding 為 zipmap,當成員數量增大時會自動轉成真正的 HashMap,此時 encoding 為 ht。
3)List
常用指令:lpush/rpush/lpop/rpop/lrange 等;
應用場景:Redis list 的應用場景非常多,也是 Redis 最重要的資料結構之一,比如 twitter 的關注清單,粉絲清單等都可以用 Redis 的 list 結構來實作;
實作方式:Redis list 的實作為一個雙向連結清單,即可以支援反向查找和周遊,更友善操作,不過帶來了部分額外的記憶體開銷,Redis 内部的很多實作,包括發送緩沖隊列等也都是用的這個資料結構。
4)Set
常用指令:sadd/spop/smembers/sunion 等;
應用場景:Redis set 對外提供的功能與 list 類似是一個清單的功能,特殊之處在于 set 是可以自動排重的,當你需要存儲一個清單資料,又不希望出現重複資料時,set 是一個很好的選擇,并且 set 提供了判斷某個成員是否在一個 set 集合内的重要接口,這個也是 list 所不能提供的;
實作方式:set 的内部實作是一個 value 永遠為 null 的 HashMap,實際就是通過計算 hash 的方式來快速排重的,這也是 set 能提供判斷一個成員是否在集合内的原因。
5)Sorted Set
常用指令:zadd/zrange/zrem/zcard 等;
應用場景:Redis sorted set 的使用場景與 set 類似,差別是 set 不是自動有序的,而 sorted set 可以通過使用者額外提供一個優先級(score)的參數來為成員排序,并且是插入有序的,即自動排序。當你需要一個有序的并且不重複的集合清單,那麼可以選擇 sorted set 資料結構,比如 twitter 的 public timeline 可以以發表時間作為 score 來存儲,這樣擷取時就是自動按時間排好序的。
實作方式:Redis sorted set 的内部使用 HashMap 和跳躍表(SkipList)來保證資料的存儲和有序,HashMap 裡放的是成員到 score 的映射,而跳躍表裡存放的是所有的成員,排序依據是 HashMap 裡存的 score,使用跳躍表的結構可以獲得比較高的查找效率,并且在實作上比較簡單。
3.支援事務,操作都是原子性,所謂的原子性就是對資料的更改要麼全部執行,要麼全部不執行
4.豐富的特性:可用于緩存,消息,按 key 設定過期時間,過期後将會自動删除
4.redis 相比 memcached 有哪些優勢?
◎memcached 所有的值均是簡單的字元串,redis 作為其替代者,支援更為豐富的資料類型
◎ redis 的速度比 memcached 快很多
◎ redis 可以持久化其資料
5.Memcache 與 Redis 的差別都有哪些?
◎ 存儲方式 Memecache 把資料全部存在記憶體之中,斷電後會挂掉,資料不能超過記憶體大小。Redis 有部份存在硬碟上,這樣能保證資料的持久性。
◎ 資料支援類型 Memcache 對資料類型支援相對簡單。Redis 有複雜的資料類型。
◎ 使用底層模型不同 它們之間底層實作方式 以及與用戶端之間通信的應用協定不一樣。Redis 直接自己建構了 VM 機制 ,因為一般的系統調用系統函數的話,會浪費一定的時間去移動和請求。
6.redis 适用于的場景?
Redis 最适合所有資料 in-momory 的場景,如:
1.會話緩存(Session Cache)
最常用的一種使用 Redis 的情景是會話緩存(session cache)。用 Redis 緩存會話比其他存儲(如 Memcached)的優勢在于:Redis 提供持久化。
2.全頁緩存(FPC)
除基本的會話 token 之外,Redis 還提供很簡便的 FPC 平台。回到一緻性問題,即使重新開機了 Redis 執行個體,因為有磁盤的持久化,使用者也不會看到頁面加載速度的下降,這是一個極大改進,類似 PHP 本地 FPC。
3.隊列
Reids 在記憶體存儲引擎領域的一大優點是提供 list 和 set 操作,這使得 Redis 能作為一個很好的消息隊列平台來使用。Redis 作為隊列使用的操作,就類似于本地程式語言(如 Python)對 list 的 push/pop 操作。
如果你快速的在 Google 中搜尋“Redis queues”,你馬上就能找到大量的開源項目,這些項目的目的就是利用 Redis 建立非常好的後端工具,以滿足各種隊列需求。例如,Celery 有一個背景就是使用 Redis 作為 broker,你可以從這裡去檢視。
4.排行榜/計數器
Redis 在記憶體中對數字進行遞增或遞減的操作實作的非常好。集合(Set)和有序集合(Sorted Set)也使得我們在執行這些操作的時候變的非常簡單,Redis 隻是正好提供了這兩種資料結構。是以,我們要從排序集合中擷取到排名最靠前的 10 個使用者–我們稱之為“user_scores”,我們隻需要像下面一樣執行即可:
當然,這是假定你是根據你使用者的分數做遞增的排序。如果你想傳回使用者及使用者的分數,你需要這樣執行:
ZRANGE user_scores 0 10 WITHSCORES
Agora Games 就是一個很好的例子,用 Ruby 實作的,它的排行榜就是使用 Redis 來存儲資料的,你可以在這裡看到。
5.釋出/訂閱
最後(但肯定不是最不重要的)是 Redis 的釋出/訂閱功能。釋出/訂閱的使用場景确實非常多。
7、redis 的緩存失效政策和主鍵失效機制
作為緩存系統都要定期清理無效資料,就需要一個主鍵失效和淘汰政策.
在 Redis 當中,有生存期的 key 被稱為 volatile。在建立緩存時,要為給定的 key 設定生存期,當 key 過期的時候(生存期為 0),它可能會被删除。
1、影響生存時間的一些操作
生存時間可以通過使用 DEL 指令來删除整個 key 來移除,或者被 SET 和 GETSET 指令覆寫原來的資料,也就是說,修改 key 對應的 value 和使用另外相同的 key 和 value 來覆寫以後,目前資料的生存時間不同。
比如說,對一個 key 執行 INCR 指令,對一個清單進行 LPUSH 指令,或者對一個哈希表執行 HSET 指令,這類操作都不會修改 key 本身的生存時間。另一方面,如果使用 RENAME 對一個 key 進行改名,那麼改名後的 key 的生存時間和改名前一樣。
RENAME 指令的另一種可能是,嘗試将一個帶生存時間的 key 改名成另一個帶生存時間的 another_key ,這時舊的 another_key (以及它的生存時間)會被删除,然後舊的 key 會改名為 another_key ,是以,新的 another_key 的生存時間也和原本的 key 一樣。使用 PERSIST 指令可以在不删除 key 的情況下,移除 key 的生存時間,讓 key 重新成為一個 persistent key 。
2、如何更新生存時間
可以對一個已經帶有生存時間的 key 執行 EXPIRE 指令,新指定的生存時間會取代舊的生存時間。過期時間的精度已經被控制在 1ms 之内,主鍵失效的時間複雜度是 O(1),EXPIRE 和 TTL 指令搭配使用,TTL 可以檢視 key 的目前生存時間。設定成功傳回 1;當 key 不存在或者不能為 key 設定生存時間時,傳回 0 。
最大緩存配置,在 redis 中,允許使用者設定最大使用記憶體大小
server.maxmemory 預設為 0,沒有指定最大緩存,如果有新的資料添加,超過最大記憶體,則會使 redis 崩潰,是以一定要設定。redis 記憶體資料集大小上升到一定大小的時候,就會實行資料淘汰政策。
redis 提供 6 種資料淘汰政策:
◎ volatile-lru:從已設定過期時間的資料集(server.db[i].expires)中挑選最近最少使用的資料淘汰
◎ volatile-ttl:從已設定過期時間的資料集(server.db[i].expires)中挑選将要過期的資料淘汰
◎ volatile-random:從已設定過期時間的資料集(server.db[i].expires)中任意選擇資料淘汰
◎ allkeys-lru:從資料集(server.db[i].dict)中挑選最近最少使用的資料淘汰
◎ allkeys-random:從資料集(server.db[i].dict)中任意選擇資料淘汰
◎ no-enviction(驅逐):禁止驅逐資料
注意這裡的 6 種機制,volatile 和 allkeys 規定了是對已設定過期時間的資料集淘汰資料還是從全部資料集淘汰資料,後面的 lru、ttl 以及 random 是三種不同的淘汰政策,再加上一種 no-enviction 永不回收的政策。
使用政策規則:
◎ 如果資料呈現幂律分布,也就是一部分資料通路頻率高,一部分資料通路頻率低,則使用 allkeys-lru
◎ 如果資料呈現平等分布,也就是所有的資料通路頻率都相同,則使用 allkeys-random
三種資料淘汰政策:
ttl 和 random 比較容易了解,實作也會比較簡單。主要是 Lru 最近最少使用淘汰政策,設計上會對 key 按失效時間排序,然後取最先失效的 key 進行淘汰
8.為什麼 redis 需要把所有資料放到記憶體中?
Redis 為了達到最快的讀寫速度将資料都讀到記憶體中,并通過異步的方式将資料寫入磁盤。是以 redis 具有快速和資料持久化的特征。如果不将資料放在記憶體中,磁盤 I/O 速度為嚴重影響 redis 的性能。在記憶體越來越便宜的今天,redis 将會越來越受歡迎。
如果設定了最大使用的記憶體,則資料已有記錄數達到記憶體限值後不能繼續插入新值。
9.Redis 是單程序單線程的
redis 利用隊列技術将并發通路變為串行通路,消除了傳統資料庫串行控制的開銷
10.redis 的并發競争問題如何解決?
Redis 為單程序單線程模式,采用隊列模式将并發通路變為串行通路。Redis 本身沒有鎖的概念,Redis 對于多個用戶端連接配接并不存在競争,但是在 Jedis 用戶端對 Redis 進行并發通路時會發生連接配接逾時、資料轉換錯誤、阻塞、用戶端關閉連接配接等問題,這些問題均是由于用戶端連接配接混亂造成。對此有 2 種解決方法:
1、用戶端角度,為保證每個用戶端間正常有序與 Redis 進行通信,對連接配接進行池化,同時對用戶端讀寫 Redis 操作采用内部鎖 synchronized。
2、伺服器角度,利用 setnx 實作鎖。
注:對于第一種,需要應用程式自己處理資源的同步,可以使用的方法比較通俗,可以使用 synchronized 也可以使用 lock;第二種需要用到 Redis 的 setnx 指令,但是需要注意一些問題。
11、redis 常見性能問題和解決方案:
1.Master 寫記憶體快照,save 指令排程 rdbSave 函數,會阻塞主線程的工作,當快照比較大時對性能影響是非常大的,會間斷性暫停服務,是以 Master 最好不要寫記憶體快照。
2.Master AOF 持久化,如果不重寫 AOF 檔案,這個持久化方式對性能的影響是最小的,但是 AOF 檔案會不斷增大,AOF 檔案過大會影響 Master 重新開機的恢複速度。Master 最好不要做任何持久化工作,包括記憶體快照和 AOF 日志檔案,特别是不要啟用記憶體快照做持久化,如果資料比較關鍵,某個 Slave 開啟 AOF 備份資料,政策為每秒同步一次。
3.Master 調用 BGREWRITEAOF 重寫 AOF 檔案,AOF 在重寫的時候會占大量的 CPU 和記憶體資源,導緻服務 load 過高,出現短暫服務暫停現象。
4.Redis 主從複制的性能問題,為了主從複制的速度和連接配接的穩定性,Slave 和 Master 最好在同一個區域網路内。
12.redis 事務的了解 CAS(check-and-set 操作實作樂觀鎖 )?
和衆多其它資料庫一樣,Redis 作為 NoSQL 資料庫也同樣提供了事務機制。在 Redis 中,MULTI/EXEC/DISCARD/WATCH 這四個指令是我們實作事務的基石。相信對有關系型資料庫開發經驗的開發者而言這一概念并不陌生,即便如此,我們還是會簡要的列出 Redis 中事務的實作特征:
1). 在事務中的所有指令都将會被串行化的順序執行,事務執行期間,Redis 不會再為其它用戶端的請求提供任何服務,進而保證了事物中的所有指令被原子的執行。
2). 和關系型資料庫中的事務相比,在 Redis 事務中如果有某一條指令執行失敗,其後的指令仍然會被繼續執行。
3). 我們可以通過 MULTI 指令開啟一個事務,有關系型資料庫開發經驗的人可以将其了解為"BEGIN TRANSACTION"語句。在該語句之後執行的指令都将被視為事務之内的操作,最後我們可以通過執行 EXEC/DISCARD 指令來送出/復原該事務内的所有操作。這兩個 Redis 指令可被視為等同于關系型資料庫中的 COMMIT/ROLLBACK 語句。
4). 在事務開啟之前,如果用戶端與伺服器之間出現通訊故障并導緻網絡斷開,其後所有待執行的語句都将不會被伺服器執行。然而如果網絡中斷事件是發生在用戶端執行 EXEC 指令之後,那麼該事務中的所有指令都會被伺服器執行。
5). 當使用 Append-Only 模式時,Redis 會通過調用系統函數 write 将該事務内的所有寫操作在本次調用中全部寫入磁盤。然而如果在寫入的過程中出現系統崩潰,如電源故障導緻的當機,那麼此時也許隻有部分資料被寫入到磁盤,而另外一部分資料卻已經丢失。Redis 伺服器會在重新啟動時執行一系列必要的一緻性檢測,一旦發現類似問題,就會立即退出并給出相應的錯誤提示。此時,我們就要充分利用 Redis 工具包中提供的 redis-check-aof 工具,該工具可以幫助我們定位到資料不一緻的錯誤,并将已經寫入的部分資料進行復原。修複之後我們就可以再次重新啟動 Redis 伺服器了。
13.WATCH 指令和基于 CAS 的樂觀鎖?
在 Redis 的事務中,WATCH 指令可用于提供 CAS(check-and-set)功能。假設我們通過 WATCH 指令在事務執行之前監控了多個 Keys,倘若在 WATCH 之後有任何 Key 的值發生了變化,EXEC 指令執行的事務都将被放棄,同時傳回 Null multi-bulk 應答以通知調用者事務執行失敗。例如,我們再次假設 Redis 中并未提供 incr 指令來完成鍵值的原子性遞增,如果要實作該功能,我們隻能自行編寫相應的代碼。
其僞碼如下:
val = GET mykey
val = val + 1
SET mykey $val
以上代碼隻有在單連接配接的情況下才可以保證執行結果是正确的,因為如果在同一時刻有多個用戶端在同時執行該段代碼,那麼就會出現多線程程式中經常出現的一種錯誤場景--競态争用(race condition)。
比如,用戶端 A 和 B 都在同一時刻讀取了 mykey 的原有值,假設該值為 10,此後兩個用戶端又均将該值加一後 set 回 Redis 伺服器,這樣就會導緻 mykey 的結果為 11,而不是我們認為的 12。為了解決類似的問題,我們需要借助 WATCH 指令的幫助,見如下代碼:
WATCH mykey
MULTI
EXEC
和此前代碼不同的是,新代碼在擷取 mykey 的值之前先通過 WATCH 指令監控了該鍵,此後又将 set 指令包圍在事務中,這樣就可以有效的保證每個連接配接在執行 EXEC 之前,如果目前連接配接擷取的 mykey 的值被其它連接配接的用戶端修改,那麼目前連接配接的 EXEC 指令将執行失敗。這樣調用者在判斷傳回值後就可以獲悉 val 是否被重新設定成功。
14.使用過 Redis 分布式鎖麼,它是什麼回事?
先拿 setnx 來争搶鎖,搶到之後,再用 expire 給鎖加一個過期時間防止鎖忘記了釋放。
這時候對方會告訴你說你回答得不錯,然後接着問如果在 setnx 之後執行 expire 之前程序意外 crash 或者要重新開機維護了,那會怎麼樣?
這時候你要給予驚訝的回報:唉,是喔,這個鎖就永遠得不到釋放了。緊接着你需要抓一抓自己得腦袋,故作思考片刻,好像接下來的結果是你主動思考出來的,然後回答:我記得 set 指令有非常複雜的參數,這個應該是可以同時把 setnx 和 expire 合成一條指令來用的!對方這時會顯露笑容,心裡開始默念:摁,這小子還不錯。
15.假如 Redis 裡面有 1 億個 key,其中有 10w 個 key 是以某個固定的已知的字首開頭的,如果将它們全部找出來?
使用 keys 指令可以掃出指定模式的 key 清單。
對方接着追問:如果這個 redis 正在給線上的業務提供服務,那使用 keys 指令會有什麼問題?
這個時候你要回答 redis 關鍵的一個特性:redis 的單線程的。keys 指令會導緻線程阻塞一段時間,線上服務會停頓,直到指令執行完畢,服務才能恢複。這個時候可以使用 scan 指令,scan 指令可以無阻塞的提取出指定模式的 key 清單,但是會有一定的重複機率,在用戶端做一次去重就可以了,但是整體所花費的時間會比直接用 keys 指令長。
16.使用過 Redis 做異步隊列麼,你是怎麼用的?
一般使用 list 結構作為隊列,rpush 生産消息,lpop 消費消息。當 lpop 沒有消息的時候,要适當 sleep 一會再重試。
如果對方追問可不可以不用 sleep 呢?list 還有個指令叫 blpop,在沒有消息的時候,它會阻塞住直到消息到來。
如果對方追問能不能生産一次消費多次呢?使用 pub/sub 主題訂閱者模式,可以實作 1:N 的消息隊列。
如果對方追問 pub/sub 有什麼缺點?在消費者下線的情況下,生産的消息會丢失,得使用專業的消息隊列如 rabbitmq 等。
如果對方追問 redis 如何實作延時隊列?我估計現在你很想把面試官一棒打死如果你手上有一根棒球棍的話,怎麼問的這麼詳細。但是你很克制,然後神态自若的回答道:使用 sortedset,拿時間戳作為 score,消息内容作為 key 調用 zadd 來生産消息,消費者用 zrangebyscore 指令擷取 N 秒之前的資料輪詢進行處理。
到這裡,面試官暗地裡已經對你豎起了大拇指。但是他不知道的是此刻你卻豎起了中指,在椅子背後。
17.如果有大量的 key 需要設定同一時間過期,一般需要注意什麼?
如果大量的 key 過期時間設定的過于集中,到過期的那個時間點,redis 可能會出現短暫的卡頓現象。一般需要在時間上加一個随機值,使得過期時間分散一些。
18.Redis 如何做持久化的?
bgsave 做鏡像全量持久化,aof 做增量持久化。因為 bgsave 會耗費較長時間,不夠實時,在停機的時候會導緻大量丢失資料,是以需要 aof 來配合使用。在 redis 執行個體重新開機時,會使用 bgsave 持久化檔案重新建構記憶體,再使用 aof 重放近期的操作指令來實作完整恢複重新開機之前的狀态。
對方追問那如果突然機器掉電會怎樣?取決于 aof 日志 sync 屬性的配置,如果不要求性能,在每條寫指令時都 sync 一下磁盤,就不會丢失資料。但是在高性能的要求下每次都 sync 是不現實的,一般都使用定時 sync,比如 1s1 次,這個時候最多就會丢失 1s 的資料。
對方追問 bgsave 的原理是什麼?你給出兩個詞彙就可以了,fork 和 cow。fork 是指 redis 通過建立子程序來進行 bgsave 操作,cow 指的是 copy on write,子程序建立後,父子程序共享資料段,父程序繼續提供讀寫服務,寫髒的頁面資料會逐漸和子程序分離開來。
19.Pipeline 有什麼好處,為什麼要用 pipeline?
可以将多次 IO 往返的時間縮減為一次,前提是 pipeline 執行的指令之間沒有因果相關性。使用 redis-benchmark 進行壓測的時候可以發現影響 redis 的 QPS 峰值的一個重要因素是 pipeline 批次指令的數目。
20.Redis 的同步機制了解麼?
Redis 可以使用主從同步,從從同步。第一次同步時,主節點做一次 bgsave,并同時将後續修改操作記錄到記憶體 buffer,待完成後将 rdb 檔案全量同步到複制節點,複制節點接受完成後将 rdb 鏡像加載到記憶體。加載完成後,再通知主節點将期間修改的操作記錄同步到複制節點進行重放就完成了同步過程。
21.是否使用過 Redis 叢集,叢集的原理是什麼?
Redis Sentinal 着眼于高可用,在 master 當機時會自動将 slave 提升為 master,繼續提供服務。
Redis Cluster 着眼于擴充性,在單個 redis 記憶體不足時,使用 Cluster 進行分片存儲。
————————————————
版權聲明:本文為CSDN部落客「All is well!8023」的原創文章,遵循CC 4.0 BY-SA版權協定,轉載請附上原文出處連結及本聲明。
原文連結:https://blog.csdn.net/qq_36073688/article/details/113818298
