架構(gòu) 前后端分離: 部署架構(gòu): 補(bǔ)充:
分布式鎖線程鎖:當(dāng)某個(gè)方法或代碼使用鎖,,在同一時(shí)刻僅有一個(gè)線程執(zhí)行該方法或該代碼段,。線程鎖只在同一JVM中有效,因?yàn)榫€程鎖的實(shí)現(xiàn)在根本上是依靠線程之間共享內(nèi)存實(shí)現(xiàn)的,。如synchronized 進(jìn)程鎖:為了控制同一操作系統(tǒng)中多個(gè)進(jìn)程訪問某個(gè)共享資源,。 分布式鎖:當(dāng)多個(gè)進(jìn)程不在同一個(gè)系統(tǒng)中,用分布式鎖控制多個(gè)進(jìn)程對(duì)資源的訪問,。 分布式鎖一般有三種實(shí)現(xiàn)方式:
樂觀鎖的實(shí)現(xiàn):使用版本標(biāo)識(shí)來確定讀到的數(shù)據(jù)與提交時(shí)的數(shù)據(jù)是否一致,。提交后修改版本標(biāo)識(shí),,不一致時(shí)可以采取丟棄和再次嘗試的策略。 分布式鎖基于Redis的實(shí)現(xiàn):(本系統(tǒng)鎖才用的)基本命令:
加鎖方式: 這里的jedis是Java對(duì)Redis的集成
錯(cuò)誤的加鎖方式1: 如果程序在執(zhí)行完setnx()之后突然崩潰,,導(dǎo)致鎖沒有設(shè)置過期時(shí)間,。那么將會(huì)發(fā)生死鎖。
錯(cuò)誤的加鎖方式2: 分布式鎖才用(Key,過期時(shí)間)的方式,,如果鎖存在,,那么獲取它的過期時(shí)間,如果鎖的確已經(jīng)過期了,,那么獲得鎖,,并且設(shè)置新的過期時(shí)間 錯(cuò)誤分析:不同的客戶端之間需要同步好時(shí)間。
解鎖:判斷鎖的擁有者后可以使用 jedis.del(lockKey) 來釋放鎖,。 分布式鎖基于Zookeeper的實(shí)現(xiàn)Zookeeper簡(jiǎn)介:Zookeeper提供一個(gè)多層級(jí)的節(jié)點(diǎn)命名空間(節(jié)點(diǎn)稱為znode),每個(gè)節(jié)點(diǎn)都用一個(gè)以斜杠(/)分隔的路徑表示,而且每個(gè)節(jié)點(diǎn)都有父節(jié)點(diǎn)(根節(jié)點(diǎn)除外),。 例如,,/foo/doo這個(gè)表示一個(gè)znode,它的父節(jié)點(diǎn)為/foo,,父父節(jié)點(diǎn)為/,,而/為根節(jié)點(diǎn)沒有父節(jié)點(diǎn)。 client不論連接到哪個(gè)Server,,展示給它都是同一個(gè)視圖,,這是zookeeper最重要的性能。 Zookeeper 的核心是原子廣播,,這個(gè)機(jī)制保證了各個(gè)Server之間的同步,。實(shí)現(xiàn)這個(gè)機(jī)制的協(xié)議叫做Zab協(xié)議。Zab協(xié)議有兩種模式,,它們分別是恢復(fù)模式(選主)和廣播模式(同步),。當(dāng)服務(wù)啟動(dòng)或者在領(lǐng)導(dǎo)者崩潰后,Zab就進(jìn)入了恢復(fù)模式,,當(dāng)領(lǐng)導(dǎo)者被選舉出來,,且大多數(shù)Server完成了和 leader的狀態(tài)同步以后,恢復(fù)模式就結(jié)束了,。狀態(tài)同步保證了leader和Server具有相同的系統(tǒng)狀態(tài),。 為了保證事務(wù)的順序一致性,zookeeper采用了遞增的事務(wù)id號(hào)(zxid)來標(biāo)識(shí)事務(wù),,實(shí)現(xiàn)中zxid是一個(gè)64位的數(shù)字,。 Zookeeper的分布式鎖原理獲取分布式鎖的流程:
我的解釋: A在Locker下創(chuàng)建了Node_n —>循環(huán) ( 每次獲取Locker下的所有子節(jié)點(diǎn) —> 對(duì)這些節(jié)點(diǎn)按節(jié)點(diǎn)自增號(hào)排序順序 —> 判斷自己創(chuàng)建的Node_n是否是第一個(gè)節(jié)點(diǎn) —> 如果是則獲得了分布式鎖 —> 如果不是監(jiān)聽上一個(gè)節(jié)點(diǎn)Node_n-1 等它釋放掉分布式鎖,。)
分布式系統(tǒng)的下的Session1,、分布式系統(tǒng):多節(jié)點(diǎn),節(jié)點(diǎn)發(fā)送數(shù)據(jù)交互,,不共享主內(nèi)存,,但通過網(wǎng)絡(luò)發(fā)送消息合作。 分布式:不同功能模塊的節(jié)點(diǎn) 集群:相同功能的節(jié)點(diǎn) 2,、Session 與token 服務(wù)端在HTTP頭里設(shè)置SessionID而客戶端將其保存在cookie 而使用Token時(shí)需要手動(dòng)在HTTP頭里設(shè)置,,服務(wù)器收到請(qǐng)求后取出cookie進(jìn)行驗(yàn)證。 都是一個(gè)用戶一個(gè)標(biāo)志 3,、分布式系統(tǒng)中的Session問題: 高并發(fā):通過設(shè)計(jì)保證系統(tǒng)能夠同時(shí)并行處理很多請(qǐng)求,。 當(dāng)高并發(fā)量的請(qǐng)求到達(dá)服務(wù)端的時(shí)候通過負(fù)載均衡的方式分發(fā)到集群中的某個(gè)服務(wù)器,這樣就有可能導(dǎo)致同一個(gè)用戶的多次請(qǐng)求被分發(fā)到集群的不同服務(wù)器上,,就會(huì)出現(xiàn)取不到session數(shù)據(jù)的情況,。 根據(jù)訪問不同的URL,負(fù)載到不同的服務(wù)器上去 三臺(tái)機(jī)器,,A1部署類目,,A2部署商品,A3部署單服務(wù) 通用方案:用Redis保存Session信息,,服務(wù)器需要時(shí)都去找Redis要,。登錄時(shí)保存好key-value,登出時(shí)讓他失效 垂直擴(kuò)展:IP哈希 IP的哈希值相同的訪問同一臺(tái)服務(wù)器 session的一致性:只要用戶不重啟瀏覽器,,每次http短連接請(qǐng)求,,理論上服務(wù)端都能定位到session,保持會(huì)話,。 Redis作為分布式鎖高并發(fā):通過設(shè)計(jì)保證系統(tǒng)能夠同時(shí)并行處理很多請(qǐng)求,。 同步:Java中的同步指的是通過人為的控制和調(diào)度,保證共享資源的多線程訪問成為線程安全,。 線程的Block狀態(tài): a.調(diào)用join()和sleep()方法,,sleep()時(shí)間結(jié)束或被打斷 b.wait(),使該線程處于等待池,直到notify()/notifyAll():不釋放資源 此外,,在runnable狀態(tài)的線程是處于被調(diào)度的線程,,Thread類中的yield方法可以讓一個(gè)running狀態(tài)的線程轉(zhuǎn)入runnable。 Q:為什么wait,notify和notifyAll必須與synchronized一起使用,?Obj.wait(),、Obj.notify必須在synchronized(Obj){…}語句塊內(nèi)。 A:wait就是說線程在獲取對(duì)象鎖后,主動(dòng)釋放對(duì)象鎖,,同時(shí)本線程休眠,。 Q:Synchronized: A:Synchronized就是非公平鎖,它無法保證等待的線程獲取鎖的順序,。 公平和非公平鎖的隊(duì)列都基于鎖內(nèi)部維護(hù)的一個(gè)雙向鏈表,,表結(jié)點(diǎn)Node的值就是每一個(gè)請(qǐng)求當(dāng)前鎖的線程。公平鎖則在于每次都是依次從隊(duì)首取值,。 ReentrantLock重入性: Spring + Redis緩存的兩個(gè)重要注解:
對(duì)數(shù)據(jù)庫加鎖(樂觀鎖 與 悲觀鎖) 悲觀鎖依賴數(shù)據(jù)庫實(shí)現(xiàn):
這條sql 語句鎖定了account 表中所有符合檢索條件(name=”Erica”)的記錄,使該記錄在修改期間其它線程不得占有,。 代碼層加鎖:
其它@Data 類似于自動(dòng)生成了Getter()、Setter(),、ToString()等方法,。 JAVA1.8的新特性StreamAPI:Collectors中提供了將流中的元素累積到匯聚結(jié)果的各種方式
For - each 寫法: for each語句是java5新增,在遍歷數(shù)組,、集合的時(shí)候,,for each擁有不錯(cuò)的性能。
for each雖然能遍歷數(shù)組或者集合,,但是只能用來遍歷,,無法在遍歷的過程中對(duì)數(shù)組或者集合進(jìn)行修改。 BindingResult:一個(gè)@Valid的參數(shù)后必須緊挨著一個(gè)BindingResult 參數(shù),,否則spring會(huì)在校驗(yàn)不通過時(shí)直接拋出異常,。
后臺(tái):
result.getFeildError.getDefaultMessage()可拋出“姓名必填” 的異常,。 4、List轉(zhuǎn)為Map
5,、Collection的子類:List,、Set List:ArrayList,、LinkedList 、Vector List:有序容器,,允許null元素,允許重復(fù)元素 Set:元素是無序的,不允許元素 最流行的是基于 HashMap 實(shí)現(xiàn)的 HashSet,,由hashCode()和equals()保證元素的唯一性,。 可以用set幫助去掉List中的重復(fù)元素,set的構(gòu)造方法的參數(shù)可以是List,,構(gòu)造后是一個(gè)去重的set,。 HashMap的補(bǔ)充:它不是Collection下的 Map可以使用containsKey()/containsValue()來檢查其中是否含有某個(gè)key/value。 HashMap會(huì)利用對(duì)象的hashCode來快速找到key,。 插入過程:通過一個(gè)hash函數(shù)確定Entry的插入位置index=hash(key),,但是數(shù)組的長(zhǎng)度有限,可能會(huì)發(fā)生index沖突,,當(dāng)發(fā)生了沖突時(shí),,會(huì)使用頭插法,即為新來的Entry指向舊的Entry,,成為一個(gè)鏈表,。 每次插入時(shí)依次遍歷它的index下的單鏈表,如果存在Key一致的節(jié)點(diǎn),,那么直接替換,,并且返回新的值。 但是單鏈表不會(huì)一直增加元素,,當(dāng)元素個(gè)數(shù)超過8個(gè)時(shí),,會(huì)嘗試將單鏈表轉(zhuǎn)化為紅黑樹存儲(chǔ)。 為何加載因子默認(rèn)為0.75,?(0.75開始擴(kuò)容) 答:通過源碼里的javadoc注釋看到,,元素在哈希表中分布的桶頻率服從參數(shù)為0.5的泊松分布。 源碼地址:https://github.com/923310233/wxOrder |
|