實戰(zhàn)Java高并發(fā)程序設計
實戰(zhàn)Java高并發(fā)程序設計 (豆瓣)?https://book.douban.com/subject/26663605/
這本書是國產(chǎn)書籍里面質(zhì)量較高的一本了(很多國產(chǎn)書都是東拼西湊或者敷衍了事)灰殴,作者從實際出發(fā)敬特,結合理論,講的很有邏輯牺陶,而且還有很多形象的手繪伟阔,和那本Java并發(fā)編程實戰(zhàn)相比更新一些,讀起來也更容易一些掰伸。
亮點:
并行不一定是從性能角度考慮皱炉,有的時候是自然而然的,比如獨立的任務分為不同的線程更易于理解
同步異步狮鸭,阻塞非阻塞合搅,并行并發(fā),這幾個概念估計很多人都混亂了很久歧蕉,和作者的觀點稍微有點出入灾部,我這里總結一下:同步異步的區(qū)別關鍵在于A對B請求發(fā)出后,如果A要等待B的結果那就是同步,如果A直接返回不需要B的結果或者等待B完成后再通知就是異步惯退;阻塞強調(diào)的是A請求B過后不能做其它事赌髓,只能干等著(自旋或者休眠),非阻塞指的是A在等B的過程中可以做其它事;并行是真正意義的的多個任務同時執(zhí)行锁蠕,并發(fā)可能是并行夷野,也可能只是多個任務交替執(zhí)行,但是切換的很快荣倾,給我們造成了并行的“假象”悯搔,真實的并行只可能出現(xiàn)在多核cpu上
死鎖:是指兩個或兩個以上的或線程在執(zhí)行過程中,因爭奪資源而互相等待舌仍,都阻塞起來妒貌;活鎖:是指線程A可以使用資源,但它讓其他線程先使用資源抡笼,線程B也可以使用資源苏揣,但它也讓其他線程先使用資源。這樣線程雖然是活躍的推姻,但是啥事也做不了平匈;饑餓:是指如果線程T1占用了資源R,線程T2又請求R藏古,于是T2等待增炭。T3也請求資源R,當T1釋放了R上的封鎖后拧晕,系統(tǒng)首先批準了T3的請求隙姿,T2仍然等待。然后T4又請求封鎖R厂捞,當T3釋放了R上的封鎖之后输玷,系統(tǒng)又批準了T4的請求...T2一直等待。
并行對于效率的提升主要取決于業(yè)務中串行代碼的比例和CPU數(shù)量靡馁,CPU數(shù)量越多欲鹏,串行化代碼比例越少,那么多線程的優(yōu)化方式效果越好
JMM關注原子性(某個操作不能被中斷)臭墨,可見性(一個線程對某變量的修改對另一個線程立馬可見)赔嚎,有序性(CPU為了性能可能指令重排,應用happen-before原則胧弛,能保證串行語義一致但是不一定保證多線程之間語義也一致)
類可以通過繼承Thread尤误,重寫run方法來實現(xiàn)多線程,但考慮到Java是單繼承的结缚,繼承是一種很寶貴的資源损晤,所以類應該實現(xiàn)Runable接口并重寫run方法,并把自己作為構造參數(shù)傳給Thread類來實現(xiàn)多線程红竭,這種做法也符合Effective Java里面提到的工作單元(Runable)與執(zhí)行機制(Thread)分離的概念
加鎖一定要注意加正確沉馆,主要有三種:指定加鎖對象码党,獲得該對象的鎖才能進入同步區(qū);作用于實例方法斥黑,鎖加在當前實例上;作用于靜態(tài)方法眉厨,鎖加在當前類上锌奴。而且要注意多線程的鎖一定要是真正的加在同一個對象上,比如
Integer i;
synchronized(i){
i++;
}
就不正確憾股,因為 Integer 是不變類鹿蜀,在執(zhí)行++運算的時候 實際上是創(chuàng)建了新類,所以那個同步塊實際上指向了不同的對象服球,自然不會正確 茴恰。事實上這段代碼 在 IDEA 里面他會提示你 synchronized 加在了非final變量上,都可能產(chǎn)生非預期結果斩熊。
java 內(nèi)置的線程池非常強大:newSingleThreadExecutor往枣,newFixedThreadPool,newCachedThreadPool粉渠,newScheduledThreadPool等等分冈,其核心都是ThreadPoolExecutor實現(xiàn)的,不過是參數(shù)不同霸株。而ThreadPoolExecutor又是可以高度定制的雕沉,threadFactory,handler 都可以自定義去件,實現(xiàn)自己的線程工廠坡椒,拒絕策略等。ThreadPoolExecutor可以擴展來實現(xiàn)更豐富的功能尤溜,例如監(jiān)聽所有任務的開始結束時間旧困,避免線程池“吃掉異常”石洗。
作者研究了ConcurrentLinkedQueue的源碼羞延,發(fā)現(xiàn)不用鎖而是用CAS來實現(xiàn)多線程安全,代碼復雜度高了很多梢睛,但是性能卻高了很多肥印;其實凡事有得必有失,就像Node一樣绝葡,異步帶來的性能提升是巨大的深碱,但是代碼的編寫難度也提升了很多。此外作者還分析了java.util.concurrent里面其他的大量的數(shù)據(jù)結構藏畅,如CopyOnWriteArrayList敷硅,BlockingQueue功咒,SkipList。這些數(shù)據(jù)結構都是Java設計者們精心設計的多線程安全數(shù)據(jù)結構绞蹦,比傳統(tǒng)的多線程安全數(shù)據(jù)結構性能提升很多
提高鎖性能:減小鎖持有時間力奋,亦即只在必要的時候加鎖;減小鎖粒度幽七,亦即縮小加鎖范圍景殷,比如ConcurrentHashMap不對整個對象加鎖而是一段;讀寫分離鎖(ReentrantReadWriteLock)替換獨占鎖澡屡;讀寫鎖的擴展猿挚,亦即按照功能分離不同功能的鎖,使用多個ReentrantLock 來表達不同條件的鎖驶鹉,使之不互相影響绩蜻,LinkedBlockingQueue就采用了這種思想;鎖粗化室埋,如果鎖不停地獲取釋放反而浪費資源办绝,所以把所有的鎖整合成一個鎖來提高性能,比如虛擬機就會實現(xiàn)這種操作词顾。按我理解八秃,如果鎖里面的操作耗時,那么就要細化肉盹,給其他線程機會昔驱,提高吞吐量,反之就應該粗化上忍,讓自己早點執(zhí)行完畢骤肛。
作者總結了一系列多線程相關的設計模式,比如單例模式窍蓝、不變模式腋颠、生產(chǎn)者消費者、介紹了用框架實現(xiàn)的無鎖生產(chǎn)者消費者吓笙、future模式實現(xiàn)的異步操作淑玫、并行流水線和搜索排序計算等等,這些都是我們業(yè)務中常常用到的模式面睛,總結一下絮蒿,以后運用更加自如
為了體會到本書的點,我寫了一些代碼叁鉴。另外AKKA部分我沒有看土涝,因為沒有用過,即使看了也體會不到精髓幌墓,所以暫時先不了解了但壮。
計算機網(wǎng)絡(第5版)
計算機網(wǎng)絡(第5版) (豆瓣)?https://book.douban.com/subject/10510747/
這本書當年大二的時候是教材冀泻,沒意識到它的珍貴,本科畢業(yè)的時候居然拿去賣了蜡饵,不過后來我又買了回來弹渔,好好的讀下來,感覺對整個計算機網(wǎng)絡都有了一個更清晰地概念验残。當然此書太厚捞附,若非必要,不宜一一細讀您没,挑些重要的基礎概念(比如TCP/IP)和如今越來越重要的內(nèi)容(比如CDN)細讀,其余看個大概即可胆绊。
亮點:
首先講了計算機網(wǎng)絡的重要性(郵件氨鹏,電子商務,web压状,在線娛樂游戲仆抵,GPS)以及廣闊前景(IOT的萬物互聯(lián),可穿戴計算機)种冬,事實上現(xiàn)在的人早就習慣了網(wǎng)絡的存在镣丑,反而不覺得它有那么重要,就像空氣一樣娱两,但是一旦你把它的作用列出來你就會發(fā)現(xiàn)莺匠,它是如此的重要,試著想想十兢,如果沒有網(wǎng)絡趣竣,現(xiàn)代社會怎么運轉?
為了降低網(wǎng)絡設計的復雜性旱物,絕大多數(shù)網(wǎng)絡都組織成一個層次棧遥缕,每一層都構建于其下一層之上。這種分層的概念在計算機科學中廣泛存在宵呛,比如面向?qū)ο蟮ハ弧DT、信息隱藏等宝穗,其根本思想都是提供服務但是隱藏實現(xiàn)户秤。這種分而治之的思想可被我們借鑒,用來簡化架構讽营,邏輯解耦虎忌。比如 nginx?處理請求也是分了不同的階段,Java 里面的 servlet 也是一樣分階段處理的
數(shù)據(jù)鏈路層只關注幀(frame)從一個節(jié)點到另一個節(jié)點的傳輸橱鹏,是點到點的膜蠢,而網(wǎng)絡層的目的是采用數(shù)據(jù)報或者虛電路技術將數(shù)據(jù)包(package)從發(fā)送方傳輸至接收方堪藐,中間可能要經(jīng)過很多點,是處理端到端數(shù)據(jù)傳輸?shù)淖畹讓犹粑В匀皇屈c到點的(因為它必須關心發(fā)送方到接收方的中間節(jié)點)礁竞,而傳輸層是真正的端到端,亦即發(fā)送接收方不必關心傳輸過程中有多少個節(jié)點杉辙,可以認為數(shù)據(jù)段(segment)是直接從發(fā)送方到接收方的模捂。從另一方面來看,一個數(shù)據(jù)報在傳輸過程中蜘矢,源/目的IP是不變的(除非NAT)狂男,但是源/目的MAC卻是一跳一跳地變化的
擁塞控制和流量控制有很大差異。前者指確保網(wǎng)絡能夠承載所有到達的流量品腹,是一個全局問題岖食;后者指發(fā)送方不會持續(xù)以超過接收方能力的速率傳輸數(shù)據(jù),解決這兩個問題的最佳解法通常都是主機慢下來
網(wǎng)絡層與傳輸層提供的服務有些類似舞吭,那么為什么不用一層做完呢泡垃?答案就是傳輸層代碼主要運行在用戶主機上,網(wǎng)絡層主要運行在運營商的路由器上羡鸥,對于網(wǎng)絡層蔑穴,用戶自己有著真正的控制權,可以通過差錯控制惧浴、順序控制存和、流量控制等方式來獲得比網(wǎng)絡層(盡力而為的服務,無保證)更加可靠的服務赶舆;另一個方面哑姚,分層也是解耦的思想體現(xiàn),只要實現(xiàn)了傳輸原語芜茵,就不必在乎網(wǎng)絡層的實現(xiàn)(以太網(wǎng)或者WiMAX)
簡單情況下叙量,我發(fā)一包,你回一包九串,但是網(wǎng)絡不佳的情況下绞佩,要保證包傳輸?shù)轿痪捅仨氁胫貍鳈C制,重傳機制一引入就必須考慮如何解決包重復接受的問題猪钮,所以限制了包生存周期(跳計數(shù)器)品山,然后通過段序號、日時鐘烤低、滑動窗口協(xié)議來丟棄已經(jīng)接受的重復數(shù)據(jù)包肘交,通過三步握手解決了初始序號獲得的問題。這一個出現(xiàn)問題扑馁、解決問題涯呻、出現(xiàn)新問題凉驻、解決新問題的反復的過程體現(xiàn)了協(xié)議設計者們的智慧和不屈不撓的毅力,非常值得我們學習
由“兩軍對壘”問題引出釋放連接的問題复罐,無論怎么確認通信涝登,也無法百分之百保證對方收到的消息,兩次效诅、三次胀滚、四次握手其實都是可行的(不一定是無誤的),事實上釋放連接的四步揮手完全就是“兩軍對壘”的一個折中方案乱投,既保證了準確率咽笼,又避免了帶寬浪費。建立連接的三次握手也同樣是一種折中
內(nèi)容分發(fā)不同于通信任務戚炫,目標主機不重要褐荷,重要的是獲取了什么內(nèi)容,獲取內(nèi)容的代價嘹悼。主要有兩個結構,CDN和P2P层宫。CDN采用分發(fā)樹結構杨伙,擴展性很高,實現(xiàn)原理是DNS重定向萌腿;P2P把多臺計算機(對等節(jié)點)的資源集中起來限匣,每臺計算機既可以作為服務器向其他計算機提供資源,也可以作為客戶端向其他計算機請求資源
本文最大特點就是故事性強毁菱,一環(huán)扣一環(huán)米死,引人入勝。
Netty實戰(zhàn)
Netty實戰(zhàn) (豆瓣)?https://book.douban.com/subject/27038538/
Netty是網(wǎng)絡編程中不可不談的一個大作贮庞,也是許多成功的網(wǎng)絡應用的基礎設施峦筒,本書就從為什么是Netty,引導我們嘗試使用窗慎,并進行了細致的講解物喷,為我們?nèi)娴钠饰隽薔etyy這個龐大而精妙的框架,組織得很有條理遮斥。
但是要注意峦失,看本書之前或者說學習Netty之前,務必要對Java IO术吗、NIO尉辑、AIO以及Reactor和Proactor的概念有一定的了解,不然就是沒學會走先去學跑了较屿。
亮點:
低級別的 API 不僅暴露了高級別直接使用的復雜性隧魄,而且引入了過分依賴于這項技術所造成的短板卓练。因此,面向?qū)ο笥幸粋€基本原則:通過抽象來隱藏背后的復雜性堤器。Netty提供了高層次的抽象來簡化TCP和UDP服務器的編程昆庇,但是你仍然可以使用底層地API。(David John Wheeler有一句名言“計算機科學中的任何問題都可以通過加上一層邏輯層來解決”闸溃,這個原則在計算機各技術領域被廣泛應用)
一個 Netty 的設計的主要目標是促進“關注點分離”:將你的業(yè)務邏輯從網(wǎng)絡基礎設施應用程序中分離
Netty組件說明:BOOTSTRAP啟動應用整吆,配置,為應用提供一個容器辉川;Channel是一條通信信道表蝙,類似于socket;ChannelHandler是數(shù)據(jù)處理的容器乓旗,也是我們要寫業(yè)務邏輯的地方府蛇,也是我們通常關注最多的地方;ChannelPipeline屬于一個Channel屿愚,是ChannelHandler鏈的容器汇跨;EventLoop?用于處理 Channel 的 I/O 操作,一個單一的 EventLoop通常會處理多個 Channel事件妆距,一個?EventLoopGroup?可以含有多于一個的 EventLoop穷遂;ChannelFuture?的 addListener 方法注冊了一個 ChannelFutureListener ,當操作完成時娱据,可以被通知(不管成功與否)蚪黑。可見中剩,Netty的組件劃分真的很細致精小忌穿,優(yōu)點就是模塊間易于解耦,模塊本身可重用性高结啼,但是也就有點啰嗦掠剑,這也是Java本身比較受到詬病的原因,還是那句話妆棒,凡事有得必有失嘛澡腾,它的優(yōu)點能讓你忍受它的缺點就行了
Transport 使用情景:OIO(即老的,最原始的阻塞IO)-在低連接數(shù)糕珊、需要低延遲時动分、阻塞時使用;NIO-在高連接數(shù)時使用红选;Local-在同一個JVM內(nèi)通信時使用澜公;Embedded-測試ChannelHandler時使用
Netty提出的ByteBuf優(yōu)于JDK原生的ByteBuffer因為:可以自定義緩沖類型(堆緩沖區(qū),直接緩沖區(qū),復合緩沖區(qū))坟乾,通過復合緩沖類型實現(xiàn)零拷貝迹辐;擴展性好,比如 StringBuilder甚侣;不需要調(diào)用 flip() 來切換讀/寫模式明吩;讀取和寫入索引分開
直接緩沖區(qū)”是另一個 ByteBuf 模式,允許 JVM 通過本地方法調(diào)用分配內(nèi)存殷费,優(yōu)點:通過免去 socket 發(fā)送數(shù)據(jù)之前印荔,JVM 先將數(shù)據(jù)從用戶區(qū)復制到內(nèi)核區(qū), 提升IO處理速度, 直接緩沖區(qū)的內(nèi)容可以駐留在垃圾回收掃描的堆區(qū)以外详羡;DirectBuffer 在 -XX:MaxDirectMemorySize=xxM大小限制下, 使用 Heap 之外的內(nèi)存, GC對此”無能為力”,也就意味著規(guī)避了在高負載下頻繁的GC過程對應用線程的中斷影響
Netty 的使用一個包含 EventLoop 的 EventLoopGroup 為 Channel 的 I/O 和事件服務仍律。EventLoop 創(chuàng)建并分配方式不同基于傳輸?shù)膶崿F(xiàn)。異步實現(xiàn)使用只有少數(shù) EventLoop(和Threads)共享于 Channel 之間 实柠。這允許最小線程數(shù)服務多個 Channel,不需要為他們每個Channel都有一個專門的 Thread
本書中對于異步同步和阻塞非阻塞的觀念有些模糊水泉,請見上面實戰(zhàn)Java高并發(fā)程序設計一節(jié)我的理解,讀者可以參考一下窒盐,自己取舍草则。事實上,Java的NIO不是異步的蟹漓,AIO(或者說NIO2.0)才是畔师,Netty基于NIO(嘗試過并拋棄了AIO),通過自己的封裝牧牢,實現(xiàn)了從使用者角度看起來的異步。學習Netty還有一個好地方就是官方文檔
分布式java應用
分布式java應用 (豆瓣)?https://book.douban.com/subject/4848587/
后端要搞得好姿锭,不上分布式肯定是不行的塔鳍,因為寫個小網(wǎng)站你可以懂點 SSM 或者 Spring Boot 就行了,但是如果要想搭建一個(或者說成為構建過程的一份子)用戶成千上萬甚至百萬呻此、千萬轮纫、上億的站點,那就必須要懂分布式了焚鲜。這本書就可以當做學習分布式的入門書籍掌唾。
亮點:
實踐是最好的成長,發(fā)表是最好的記憶忿磅。這句話的確可以放在電腦上當桌面背景
分布式系統(tǒng)通信底層都依賴于TCP糯彬、UDP,但是為了易用性葱她,通常會使用一些更貼近應用層的協(xié)議撩扒,書中提到了原始的jdk通信,以及webservice,Mina,實際上還有許多吨些,比如RPC搓谆、WebService炒辉、RMI、JMS(p2p或者發(fā)布訂閱)泉手、JNDI等等
網(wǎng)絡IO分三類黔寇。BIO:用戶線程在進行IO操作的時候進行系統(tǒng)調(diào)用,阻塞斩萌,只有讀到(寫入)了數(shù)據(jù)才釋放資源缝裤;NIO:同步非阻塞IO,用戶線程在發(fā)起IO操作之后可以立即返回术裸,只有流可讀(可寫)操作系統(tǒng)才會通知用戶線程進行讀忍仁恰(寫入),但是用戶線程需要不斷輪詢來請求數(shù)據(jù)袭艺,Linux采用epoll實現(xiàn)搀崭;AIO:用戶線程發(fā)起請求時,由操作系統(tǒng)來進行讀然唷(寫入)瘤睹,IO事件就緒的時候,操作系統(tǒng)會通知對應的用戶線程來處理答倡,實現(xiàn)真正的異步IO轰传,Windows下IOCP實現(xiàn)了AIO,Linux只有epoll實現(xiàn)模擬實現(xiàn)的AIO瘪撇。同時获茬,由于服務器的主力是Linux,所以AIO的用處目前不是特別廣
BIO對應的是一連接一線程倔既,可以引入線程池來優(yōu)化恕曲,但是一個操作系統(tǒng)線程數(shù)量終究有限,所以不可能支撐大量連接數(shù)渤涌;NIO對應的是一請求一線程佩谣,只有某個連接有讀寫事件時才為其生成一個線程來處理,只有連接數(shù)不多或者連接數(shù)多且都請求頻繁時才沒有優(yōu)勢实蓬,但實際情況中茸俭,服務器通常會支持大量連接數(shù),但是同時發(fā)送請求的連接不會太多安皱,所以NIO應用比價廣泛调鬓;AIO對應一個有效請求一個線程,亦即OS處理IO完畢后再生成用戶線程處理酌伊,充分調(diào)用了OS參與袖迎,可以應對連接數(shù)多且操作頻繁的場景,如果Linux對AIO的支持更好,這個模型可能會流行起來
SOA亦即面向服務的架構燕锥,強調(diào)系統(tǒng)之間以標準服務的方式進行交互辜贵,各系統(tǒng)可以采用不同的語言、框架來實現(xiàn)归形,交互則全部采用服務來進行,目前SCA和ESB是主流標準托慨,分別有Tuscany和Mule等常用框架實現(xiàn)
調(diào)優(yōu)的步驟:衡量系統(tǒng)現(xiàn)狀,設定調(diào)優(yōu)目標暇榴,尋找性能瓶頸厚棵,性能調(diào)優(yōu),衡量是否達標蔼紧,反復進行前面三步直至達標婆硬。
以前我對負載均衡的理解還是停留在引入一個(群)中間節(jié)點作為調(diào)度者,調(diào)度者(硬件或軟件)接受請求并轉發(fā)給實際應用服務器奸例。這實際上叫做中心化負載均衡彬犯,書中提到Gossip實現(xiàn)了無中間節(jié)點的軟件負載均衡實際上是一種去中心化傳播事件的負載均衡,去掉中心節(jié)點后請求響應直接進行加快了速度查吊,而且能避免調(diào)度者單點故障問題。最高級別的負載均衡是全局負載均衡逻卖,實現(xiàn)不同地域機房的負載均衡宋列,既可以避免單點故障還可以就近響應,提高訪問速度评也,實現(xiàn)高可用炼杖,一般由硬件GSLB實現(xiàn)(在合肥 ping 了一下?http://qq.com?得到的結果是深圳的,在天津得到的結果就是北京的盗迟,雖然不一定嘹叫,但是看得出來有差別),但是多機房的一致性很難保證诈乒,通常都要用消息中間件來實現(xiàn)
除了上面提到的機房等硬件上的故障,應用軟件本身的故障也是高可用的大敵婆芦,所以要注意避免故障怕磨,及時發(fā)現(xiàn)并處理故障,具體包括:明確使用場景消约,做到最貼近場景的最簡單系統(tǒng)肠鲫,或者分階段最簡單系統(tǒng);設計可容錯系統(tǒng)或粮,fail fast导饲;系統(tǒng)可自我保護,對第三方依賴保持弱依賴,避免連鎖失效渣锦;建立分級報警系統(tǒng)和日志記錄與分析系統(tǒng)硝岗;注意總結故障分析便于下次快速利用,這也是架構即未來里面提到過的袋毙;按照業(yè)務拆分子系統(tǒng)......
構建可伸縮的系統(tǒng)關鍵在于水平伸縮型檀,因為垂直伸縮是有限的(一臺機器的性能終究有限),而水平伸縮理論上是無限的(可以添加“無數(shù)”臺機器)听盖,水平伸縮通常通過SNA(share nothing architecture)實現(xiàn)胀溺,亦即應用系統(tǒng)之間不共享狀態(tài),把狀態(tài)信息統(tǒng)一放入緩存或數(shù)據(jù)庫(可以是分布式)皆看。文件系統(tǒng)的水平擴展思想也是類似的
本書可以當做入門書籍仓坞,但是書中真正關于分布式的內(nèi)容似乎少了些,倒是Java基礎知識占據(jù)了很大篇幅腰吟,感覺有點不對題目无埃,畢竟要看這些知識我可以看Java核心技術,Java并發(fā)編程實戰(zhàn)或者深入理解jvm啊蝎困,但是也可以用來復習一下录语,而且有許多實驗數(shù)據(jù)可供參考,還是可以的禾乘。
PS:我之前已經(jīng)看了Netty了澎埠,所以書中關于Mina的部分,時間不夠我就跳著看了始藕,時間夠還是可以了解一下的蒲稳,兩者對比。
分布式系統(tǒng) 概念與設計
分布式系統(tǒng) 原書第5版 (豆瓣)?https://book.douban.com/subject/21624776/
讀了上面一本分布式Java伍派,不免對分布式系統(tǒng)想要有一個更全面江耀、更系統(tǒng)的認識,那么這本書就是一本絕佳的書籍诉植。
亮點:
資源共享是構建分布式系統(tǒng)的主要目祥国;并發(fā)、缺乏全局時鐘晾腔、故障獨立性是其主要特征舌稀;處理其構件的異構性、開放性(允許增加或替換組件)灼擂、安全性(機密完整可用)壁查、可伸縮性(用戶的負載增加時能正常運行的能力)、故障處理剔应、組件并發(fā)性睡腿、透明性(分布式的組件對外展示為一個整體)语御、QoS(在傳輸數(shù)據(jù)時滿足要求的能力)等是其主要挑戰(zhàn)
無論是 請求-應答(比如http) 還是 RPC 或者 RMI(類似于RPC但是僅限于Java且支持對象概念),收發(fā)雙發(fā)都是雙向的(直接通信)席怪,要想解耦收發(fā)雙方(空間解耦和時間解耦)应闯,那么就得用間接通信:組通信(廣播),發(fā)布訂閱系統(tǒng)何恶,消息隊列孽锥,元組空間(生成通信),分布式共享內(nèi)存等方式
中間件是一組計算機上的進程或?qū)ο笙覆悖淠康氖瞧帘萎悩嬓韵Ъ嗉吹讓拥耐ㄓ崳换ヒ呤辏B接等復雜又通用的功能以服務的形式提供出來盛撑,分布式系統(tǒng)應用在交互時,直接使用中間件提供的高層編程抽象即可捧搞,實現(xiàn)了簡潔的分布式系統(tǒng)應用的通信和資源共享的支持
套接字(socket)是通信的抽象抵卫,無論是TCP還是UDP的方式,它提供了進程間通信的端點胎撇,必須和協(xié)議介粘,主機地址(分為目的端與源端),端口(分為目的端與源端)綁定起來
RPC的概念代表著分布式計算的重大突破晚树,使得分布式編程和傳統(tǒng)編程類似姻采,實現(xiàn)了高級的透明性,這種相似性將傳統(tǒng)的過程調(diào)用模型擴展到分布式環(huán)境中爵憎,隱藏了底層分布式環(huán)境的重要細節(jié)部分慨亲,簡化了分布式開發(fā)
操作系統(tǒng)的任務是提供一個物理層(處理器,內(nèi)存宝鼓,硬盤等)之上的面向問題的抽象刑棵,例如給程序員提供文件和套接字而不是磁盤塊和原始網(wǎng)絡訪問。操作系統(tǒng)分為網(wǎng)絡操作系統(tǒng)(具有內(nèi)置聯(lián)網(wǎng)功能愚铡,能自主管理自己的資源并網(wǎng)絡透明地訪問其它一些資源但是不能跨節(jié)點管理進程蛉签,也就是有多個系統(tǒng)映像)和分布式操作系統(tǒng)(用戶不必關心程序運行的地點和資源位置,能透明的將新的進程調(diào)度到合理的節(jié)點上沥寥,有單一的系統(tǒng)映像)碍舍,后者幾乎沒有普遍應用的案例,因為中間件和網(wǎng)絡操作系統(tǒng)的結合就能很好的滿足用戶需求
最重要的兩種中間件風格:分布式對象(允許面向?qū)ο缶幊棠P烷_發(fā)分布式系統(tǒng)营曼,通信實體被表示成對象,通信使用RMI愚隧,但也可以使用其他的比如分布式事件)蒂阱;組件(基于對象方法的自然演化锻全,主要克服其限制:隱式依賴,編程復雜性鳄厌,缺少關注點分離支持,無部署支持)
面向服務的體系結構(SOA)是一套設計原則妈踊,分布式系統(tǒng)用松耦合的服務集開發(fā),服務能被動態(tài)發(fā)現(xiàn)歪泳,能互相通信并通過編排進行協(xié)調(diào)從而提供更強的服務慎式。可以基于分布式對象或者組件來實現(xiàn)瘪吏,但實際中主要通過web服務實現(xiàn)掌眠,主要是因為web服務內(nèi)在的松耦合性(比如不管子系統(tǒng)是CORBA還是.NET蕾盯,只要用web服務暴露接口,就能輕易實現(xiàn)集成)
分布式是一門結合計算機網(wǎng)絡與操作系統(tǒng)等多種門類的交叉學科扇救,所以這本書也包含了許多這些方面的知識刑枝,不失為一種復習的方式。
大型網(wǎng)站系統(tǒng)與Java中間件開發(fā)實踐
大型網(wǎng)站系統(tǒng)與Java中間件開發(fā)實踐 (豆瓣)?https://book.douban.com/subject/25867042/
上面的分布式Java是一本很基礎的入門書籍迅腔,這本書算是一本更加全面和仔細的書籍装畅,把它沒講到的部分都講了一些,而且更注重中間件(支撐大型網(wǎng)站關鍵沧烈、必要的技術之一)的講解掠兄。
亮點:
分布式系統(tǒng)中的控制節(jié)點協(xié)調(diào)系統(tǒng)之間的協(xié)作,可以用:硬件均衡負載設備(昂貴)锌雀、軟件方式的透明代理(增加流量蚂夕、易出現(xiàn)單點失效)、采用名稱服務的直連請求(不易單點失效腋逆、流量少)婿牍、采用規(guī)則服務器的直連調(diào)用、采用master+worker的架構
從一個最基本惩歉、簡單等脂、部署在單機上的網(wǎng)站開始俏蛮,數(shù)據(jù)量和訪問量慢慢上去了,一步步演進:數(shù)據(jù)庫與應用分離到兩臺服務器上遥;多應用服務器與單數(shù)據(jù)庫搏屑,涉及到session問題(sticky、replication、集中存儲、cookie Based)暂吉;數(shù)據(jù)庫讀寫分離罗晕、引入搜索引擎、引入數(shù)據(jù)和頁面緩存;引入分布式存儲系統(tǒng);數(shù)據(jù)庫垂直拆分(一個業(yè)務的數(shù)據(jù)放到一個專用數(shù)據(jù)庫)、水平拆分(單個表放到兩個數(shù)據(jù)庫中)底靠;拆分應用,可以根據(jù)業(yè)務特性把應用拆開或者走服務化的路特铝,亦即每個web系統(tǒng)通過不同的服務來完成特定的業(yè)務暑中;引入消息中間件來完成拆分、服務化等目的
大型網(wǎng)站主要用到三類中間件:遠過程調(diào)用和對象訪問中間件(解決分布式下應用互相訪問的問題)鲫剿;消息中間件(解決應用之間消息傳遞鳄逾、解耦、異步的問題)灵莲;數(shù)據(jù)訪問中間件(解決數(shù)據(jù)庫訪問共性的問題)雕凹;
服務框架帶來的好處:結構上,架構更清晰政冻,底層資源由服務層統(tǒng)一管理枚抵,也更利于提高效率;穩(wěn)定性上明场,一些散落在多個系統(tǒng)中的代碼變成了服務汽摹,由專門的團隊統(tǒng)一維護,可以提高代碼質(zhì)量苦锨,另一方面由于核心穩(wěn)定逼泣,修改發(fā)布次數(shù)減少,也提高了穩(wěn)定性
通過消息中間件舟舒,業(yè)務系統(tǒng)不必知道有多少個其他業(yè)務系統(tǒng)需要了解某一項業(yè)務拉庶,只需要把消息發(fā)布給消息中間價,消息中間價負責把消息投遞給相關的其他業(yè)務系統(tǒng)秃励,這樣每個業(yè)務系統(tǒng)都能專注自己本身的業(yè)務氏仗,不必維護臃腫的依賴關系,達到解耦和消息異步的目的
消息中間件要點:保證業(yè)務與發(fā)布消息的一致性夺鲜,一般直接緊挨著寫代碼就行皆尔,出錯概率較小帚稠,但是對于要保證強一致的系統(tǒng),需要采用類似于TCP三步握手的方式來保證床佳;解決強依賴關系,盡量保證中間件的可靠性榄审,最好達到和業(yè)務系統(tǒng)本身可靠性相同砌们,從業(yè)務數(shù)據(jù)上能對消息進行補發(fā)是最徹底的容災手段;消息模型對消息接受的影響搁进,Queue(點對點)和Topic(發(fā)布/訂閱)都不能完全適應集群模式(發(fā)送接收方都是集群浪感,要做到不重不漏、互不干擾)饼问,解決方法是結合兩者使用影兽,集群之間用Topic模型,集群內(nèi)部用Queue模型莱革;做到持久訂閱(除非顯示取消訂閱峻堰,否則即使訂閱者宕機了重啟后也應該能收到所有消息)
服務框架,數(shù)據(jù)訪問層盅视,消息中間價背后的基礎產(chǎn)品就是軟負載和配置中心捐名。軟負載中心的基本職責有兩個:聚合地址信息,將所有方面的地址形成列表供其他方使用闹击;生命周期感知镶蹋,對服務的上下線自動感知并更新服務地址。軟負載中心管理非持久數(shù)據(jù)赏半,集中配置管理中心管理持久數(shù)據(jù)
ESI將頁面分為相對靜態(tài)的內(nèi)容和動態(tài)的內(nèi)容贺归,如果整個頁面在服務端渲染的話,可以將相對靜態(tài)的內(nèi)容進行緩存断箫,而不是每次都全部重新渲染
在解決具體的問題的時候拂酣,完全從頭寫代碼還是基于開源代碼去發(fā)展一定要慎重思考,如果場景類似那么以比較活躍的開源產(chǎn)品為基礎并根據(jù)自己的場景定制會起到事半功倍的效果瑰枫,如果沒有合適的那就需要從零開始了
京東基礎架構建設之路
京東基礎架構建設之路(全彩) (豆瓣)?https://book.douban.com/subject/27202674/
本書主要作者是我們學校的一位師兄踱葛,前不久來學校辦了個報告,主要講了他在京東的基礎架構經(jīng)驗光坝,介紹了新的架構從無到有的過程尸诽,他們團隊的技術現(xiàn)在一年能為京東省了很多億,這本書里凝聚了他們的技術精華盯另,當然值得我們?nèi)チ私庖幌驴┬院耶敃r的QA環(huán)節(jié)我提了個問題,主辦方就送了這本書鸳惯,師兄當場親筆簽名商蕴,我就更應該把這本書好好研究研究了叠萍。
亮點:
跳過虛擬化,直接容器化绪商,結合團隊的OpenStack經(jīng)驗苛谷,選擇OpenStack+Docker的架構,用OpenStack來管理調(diào)度Docker容器
建議鏡像和根目錄只保留只讀或者少量讀\寫文件格郁,對于頻繁的讀\寫或者大量寫的文件盡量用外掛的volume腹殿,規(guī)范業(yè)務對容器的使用行為
MySQL運維自動化包括:自動備份,包括按時間點精準恢復例书;自動歷史數(shù)據(jù)轉移锣尉,將不再變更的歷史數(shù)據(jù)定期轉入大容量分布式存儲系統(tǒng)(如HBASE),控制MySQL數(shù)據(jù)量决采;自動故障檢測與切換自沧,采用Orchestrator作為管理工具;全面容器化树瞭,提升MySQL實例交付效率
在故障檢測和故障切換的方案中拇厢,比較容易想到的就是ZooKeeper的臨時節(jié)點探測不存活的服務,但是由于需要修改服務端代碼晒喷,不便于跨機房部署和連接數(shù)過多的問題旺嬉,京東自己開發(fā)了分布式探測系統(tǒng),為了避免臨時網(wǎng)絡不通導致的誤判厨埋,采取多個探測程序部署到機房的不通機架里邪媳,對實例進行分布式投票,只要有一個探測存活就判斷為存活的荡陷,否則通知故障恢復程序進行主從切換
容器中的數(shù)據(jù)最原始的是直接使用物理機上的volume來存儲雨效,但是這樣容器數(shù)據(jù)就和物理機綁定了,無法實現(xiàn)數(shù)據(jù)的遷移也無法做到超大容量的存儲废赞。京東的ContainerFS就是為容器而生的分布式文件系統(tǒng)徽龟,它的每個volume都可以被一個或者多個容器當做本地文件直接使用,容器之間可以共享數(shù)據(jù)唉地,支持彈性伸縮据悔、線性擴展
JMQ由于要支撐訂單、支付等要求對服務質(zhì)量要求極其嚴格的業(yè)務耘沼,所以必須保證在整個機房都失效的情況下依然能恢復數(shù)據(jù)极颓,所以采取了一主一從且至少一個備份的架構。主從分布在同一個數(shù)據(jù)中心群嗤,采取同步復制菠隆;備份在另一個數(shù)據(jù)中心,采取異步復制
分布式服務跟蹤系統(tǒng)CallGraph通過核心的調(diào)用鏈(依靠全局唯一的ID實現(xiàn))的概念能追蹤到一次調(diào)用的從請求發(fā)出到最底層系統(tǒng)的所有環(huán)節(jié),便于排查問題骇径,而且具有低侵入性
全鏈路壓測通過全國各個公網(wǎng)節(jié)點發(fā)來的數(shù)據(jù)請求來較好地模擬真實用戶操作躯肌,同時壓測會有參數(shù)標識,進行真實流量與測試流量的隔離破衔,避免污染生產(chǎn)數(shù)據(jù)
大型互聯(lián)網(wǎng)公司的數(shù)據(jù)中心架構一般都會經(jīng)歷單機房清女,同城雙機房,異地災備晰筛,最后是異地多活的各個階段校仑。京東目前有三大數(shù)據(jù)中心,每個中心都能承擔讀寫業(yè)務(這就是異地多活)传惠,依據(jù)GLSB和HTTPDNS和全國網(wǎng)絡質(zhì)量檢測數(shù)據(jù)來動態(tài)優(yōu)化用戶到某個具體中心獲得服務,中心之間用專線打通保證數(shù)據(jù)秒級同步提供低延遲數(shù)據(jù)最終一致性保障
本書雖然很薄稻扬,但是講述的知識平常我們可能都用不到(不是誰都有機會接觸這么大的規(guī)模的集群管理)卦方,看的時候要想完全吸收還是有些費勁,還得在以后的實踐中加以琢磨才行泰佳。
Docker進階與實戰(zhàn)
Docker進階與實戰(zhàn) (豆瓣)?https://book.douban.com/subject/26701218/
第一本docker書?為我們?nèi)腴Tdocker提供了很好的途徑盼砍,這本書為我們提供了深入了解整個docker技術棧所需要的更多的知識,比如關鍵技術原理逝她,高級技巧如安全浇坐、測試、集群管理等等黔宛。這兩本書有重疊近刘,但是后者對前者有許多的補充,利于我們更好的使用臀晃、更好的理解docker觉渴。
亮點:
Docker并沒有傳統(tǒng)虛擬化中的Hypervisor層,使用輕量級虛擬化技術徽惋,基于Cgroup和Namespace等內(nèi)核容器技術案淋,與內(nèi)核深度融合,性能與物理機非常接近险绘。通信上踢京,Docker不與內(nèi)核直接通信,而是通過LibContainer宦棺。libContainer是真正意義上的容器引擎瓣距,通過clone系統(tǒng)調(diào)用直接創(chuàng)建容器(一個新的子進程),通過pivot_root進入容器(新的rootfs)代咸,通過cgroupfs控制資源旨涝,Docker本身更側重處理更上層的業(yè)務。
Docker主要工作是在LXC(linuxContainer亦即linux內(nèi)核容器技術)的基礎上提供了一些更高級的控制工具,包括:定義鏡像格式白华,包含所有程序和依賴慨默,使得鏡像可以跨主機部署,實現(xiàn)了進程沙盒弧腥,同時保證程序及其依賴環(huán)境的一致性厦取;提供自動構建工具,使得當前機器的配置不會影響鏡像構建過程管搪;提供了類似git的版本管理功能虾攻,支持鏡像版本追蹤、校驗更鲁、回退等功能霎箍;通過鏡像分層實現(xiàn)組件重用,減小鏡像大小澡为,加快構建速度漂坏;工具生態(tài)鏈......
虛擬機是硬件級別的虛擬化,利用VT-x媒至、AMD-V等硬件虛擬化技術通過Hypervisor來實現(xiàn)對資源的徹底隔離顶别;容器是操作系統(tǒng)級別的虛擬化,利用內(nèi)核的Cgroup和Namespace等軟件實現(xiàn)的特性實現(xiàn)來實現(xiàn)進程隔離拒啰,Docker容器與主機共享操作系統(tǒng)內(nèi)核驯绎,不同容器可以共享部分資源,因此容器更加輕量級谋旦,資源消耗更少剩失,啟動更快。而虛擬機獨占自己的資源册着,各個虛擬機幾乎完全獨立赴叹,不存在共享,消耗更多資源指蚜,啟動也慢
容器技術是一種操作系統(tǒng)級別的虛擬化技術(還有硬件虛擬化乞巧、半虛擬化等技術),已經(jīng)集成進linux內(nèi)核摊鸡,是內(nèi)核提供的原生特性绽媒,主要包含Namespace(主要做訪問隔離,針對一類資源進行抽象免猾,并將其封裝在一起供容器使用)和Cgroup(control group是辕,主要做資源控制,將一組進程放進一個控制組猎提,給這個控制組分配指定可用的資源获三,其原生接口由cgroupfs提供)。但是光有這兩個還不夠,還需要rootfs(文件系統(tǒng)隔離)和容器引擎(生命周期控制)
Docker引入聯(lián)合掛載技術(把多個目錄掛載到同一目錄疙教,對外呈現(xiàn)這些目錄的聯(lián)合)使得鏡像分層成為可能棺聊,使用git式的管理方式使得基礎鏡像的重用成為可能
如果你在尋找一個清晰、簡單贞谓、低耦合限佩、無狀態(tài)、面向資源的API設計方式裸弦,那么RESTFul API就是一種不錯的選擇祟同,它充分利用了HTTP本身的語義,使你的API更易用更具有擴展性理疙,同時優(yōu)雅的展示你的資源晕城。Docker API 就是一種 RESTFul API
Cgroup對系統(tǒng)資源的限制已經(jīng)比較完善了,但是Namespace的隔離還不算很好窖贤,比如procfs的很多接口都沒隔離砖顷,可以通過procfs可以讀取和修改宿主系統(tǒng)的相關信息,所以procfs是以只讀方式掛載的主之,還有syslog也是沒隔離的。Namespace的隔離不完善李根,也不太可能完善槽奕,這是共享內(nèi)核固有的缺陷。有許多安全策略被用來保護系統(tǒng)房轿,比如Cgroup限制粤攒、容器運行在虛擬機中、鏡像簽名囱持、日志審計夯接、監(jiān)控、文件保護
在制作鏡像的時候纷妆,源碼導入有兩種策略:靜態(tài)導入(使用COPY命令直接把代碼放入鏡像)盔几;動態(tài)導入(使用VOLUME命令把代碼文件動態(tài)掛載到容器)。建議使用兩個dockerfile掩幢,一個開發(fā)版本(dev)用動態(tài)掛載逊拍,便于隨時修改代碼,一個發(fā)布版本用靜態(tài)導入际邻,便于減少依賴芯丧、處處運行
作者還講述了怎么參與到docker的開發(fā)和維護的過程中,如果我們在使用過程中遇上了問題世曾,去看看源碼和社區(qū)也是不錯的缨恒,說不定就能解決
雖然只過去了1年多,但是書中已經(jīng)有內(nèi)容過時了,比如不要再安裝?http://docker.io?或者 docker-engine 骗露,而是使用docker-ce (免費版)或者 ee (企業(yè)版)岭佳。而且,如今 Docker-Compose椒袍、Swarm 已經(jīng)比較成熟了驼唱,完全可以用在生產(chǎn)環(huán)境中,當然驹暑,(超)大規(guī)模的部署最終都得按照自己的業(yè)務情況來造輪子玫恳,完全依靠開源的肯定是不行的,這樣是上面那本書的作者提到過的觀點优俘。