後端好書閱讀與推薦系列文章:
後端好書閱讀與推薦
後端好書閱讀與推薦(續)
後端好書閱讀與推薦(續二)
後端好書閱讀與推薦(續三)
後端好書閱讀與推薦(續四)
後端好書閱讀與推薦(續五)html
Redis設計與實現 (豆瓣): https://book.douban.com/subje...前端
經過前面這本書咱們已經知道redis怎麼用比較好了,如今咱們來看看 Redis 的實現原理。這本書是做者本身看着源碼寫出來的,不得不佩服做者的智慧與毅力。這本書基於redis3.0,此刻redis最新版是4.0.9,咱們看書的時候能夠本身去看看源碼,看看redis有啥變化沒,源碼在此。java
亮點:node
SDS(簡單動態字符串)
這一抽象類型,被用於鍵、字符串的表示,還有AOF中的緩衝區、客戶端輸出緩衝區等buffer的表示。 SDS的優點在於:記錄了長度信息不須要遍歷(空間換時間)、有長度因此會先檢查空間是否足夠而不會溢出、記錄了free(未使用空間)長度從而避免頻繁的內存從新分配(實現了空間預分配和惰性釋放)、二進制安全等等List
結構、發佈訂閱、慢查詢、監視器等功能)、字典Dict(基於兩個hash表,一個平時用、一個rehash用,主要用於實現數據庫、Hash
結構,須要注意漸進式rehash而不是java中Hashmap的一次性rehash,漸進式主要是避免鍵數量太大致使服務器暫時中止服務)、跳躍表SkipList(用於實現SortedSet
結構、集羣節點)、整數集合(用於實現Set
結構)、壓縮列表(用於實現List
和Hash
結構,主要是面向小整數和短字符串,能夠節省空間)、對象redisObject(redis的五種數據結構就是五種對象,key value都是對象,是對前面全部數據結構的一種封裝,實現類型判斷、編碼、引用計數與對象共享和內存回收、過時刪除等功能)等數據結構來實現特定功能redisServer
數據結構,包含一個redisDb
的鏈表,每個數據庫都是一個數據結構redisDb
,中間有一個dict
的數據結構保存了這個數據庫全部的鍵值對,叫作鍵空間(key space)。鍵空間會維護命中次數、最後使用時間、過時清除、鍵監視、鍵空間(關注鍵自己)/鍵事件(關注操做自己如del、sadd、set等)通知等事件。此外還有一個clients
字段保存了全部客戶端redisDb
有一個dict
類型的鏈表expire
,保存了全部鍵的過時時間。過時鍵有三種刪除策略:定時刪除
,設置timer,過時當即刪除,對內存友好,可是浪費CPU時間片,並且大量的timer也不現實;惰性刪除
,聽任無論,獲取的時候檢查是否過時,過時再刪除,會浪費必定的內存,可是節省CPU時間;按期刪除
,每隔一段時間就檢查過時鍵並刪除,須要好好設計執行時長與頻率。redis實際使用的是後二者AOF
和RDB
。RDB能夠手動執行也可按期執行(BGSAVE)用內存數據生成壓縮過的二進制RDB文件,SAVE
命令會阻塞服務器,而BGSAVE
會fork一個子進程來建立RDB文件,因此期間新的數據變化是不能提現到RDB文件中的,此外,RDB文件的載入是服務器啓動自動完成的;AOF不直接記錄數據,而是記錄每個redis命令,分爲append、文件寫入(可能在系統緩衝中)、文件同步sync(強制刷到磁盤)三個步驟,文件同步有三種選項always(寫入文件就刷盤)、everysec(默認)、no(由操做系統決定什麼時候刷盤)while(true)
的無限循環,叫作事件循環,每一個循環裏服務器要處理兩種事件:文件事件,完成網絡通訊(基於Reactor模式);時間事件,完成定時、週期操做之類。Sentinel
實例監視任意多的redis主服務器以及所屬的從服務器(從服務器複製主服務器的數據),完成主備切換等功能。實現原理是Sentinel
每隔10秒就向全部主服務器發送info
命令,獲取各個主服務器及其對應的從服務器的信息,而後也會以相同形式給從服務器發送info
命令。另外會以兩秒一次的頻率向全部主從服務器發送一個publish
的命令,而後會subscribe
這個頻道,這樣就能得到每一個服務器的相關信息了。Sentinel
之間只有命令鏈接,沒有頻道鏈接。ping
來實現,當超過一個Sentinel
的時限down-after-milliseconds
還沒得到一個服務器的回覆這個Sentinel
就認爲此服務器主觀下線,而後會詢問其餘Sentinel
,若是超過quorum
個Sentinel
都認爲此服務器主觀下線那麼這些Sentinel
就認爲這個服務器就客觀下線了。當一個主服務器下線時,Sentinel
們會選舉一個領頭Sentinel
(Raft
leader選舉)來對這個服務器羣進行主備切換,具體算法就不說了redis-trib
實現。showlog-log-slower-than
選項執行時間的命令會被記錄到慢查詢日誌,日誌採用保存最近的,數量由slowlog-max-len決定。本書配合着官方文檔來學習是最佳的,文檔在此,中文文檔。mysql
MySQL技術內幕 (豆瓣): https://book.douban.com/subje...linux
經過前面這本書咱們已經知道 mysql 怎麼用比較好了,如今咱們來看看 mysql 的實現原理。nginx
亮點:git
InnoDB
支持事務、行鎖、外鍵,主要面向在線事務處理應用(OLTP),經過MVVC提升併發性,默承認重複讀級別使用 next-key locking避免幻讀,此外還提供插入緩衝、二次寫、自適應hash索引、預讀等高性能與高可用功能;MyISAM
不支持事務與行鎖,可是支持全文索引,主要面向OLAP應用;NDB
是一個集羣引擎,數據所有在內存因此速度很快,可是鏈接操做不是在引擎層面解決的,效率較低;Memory
也是內存存儲的引擎,適合臨時表存儲中間結果使用,默認使用hash索引,只支持表鎖;Archive
只支持insert和select,支持壓縮適合存儲歸檔數據;還有太多不經常使用的,就不一一列舉了Master Thread
負責將緩衝池中的數據異步刷新到磁盤,保證數據一致性,包括髒頁刷新,合併插入緩衝,undo頁回收;IO thread
負責寫操做AIO的回調處理;Purge Thread
負責undo log的回收,減輕Master Thread的負擔;Page cleanner Thread 負責髒頁刷新,減輕master thread 負擔寫緩衝
與WAL
將隨機寫改爲了順序寫提升了吞吐量,同時保證數據持久性,若是宕機就會用redo
與undo
兩階段的日誌來將數據恢復到數據庫文件中。可是mysql基本頁面通常是16KB,而操做系統基本頁面通常是4KB,若是在寫入到數據庫文件時發生宕機,就可能引發partial write
問題,亦即一個mysql頁面只寫入了一部分,這時就要依靠double write
:同步緩衝區數據時,不是直接寫入文件,而是寫入內存中的double write buffer
再調用fsync寫到共享表空間文件,而後立刻調用fsync同步至數據庫文件,這樣若是發生了partial write
,就能夠去共享表空間找到該頁副本並複製到數據庫文件中,而後再進行redo,undo
。固然,若是文件系統自己有防範機制就沒必要啓用double write
了Fileheader、Pageheader、FileTrailer
(檢查完整性)是固定的,記錄一些該頁的信息如checksum
、頁所在B+樹層數。userrecords、freespace、pagedirectory
(頁相對位置,B+索引只記錄一條數據所在頁,真正查找還需把這一頁加載如內存,靠二分搜索這一條記錄)是實際的行記錄存儲空間,所以大小是動態的。Cardinality
能幫助咱們決策是否須要創建索引,能夠經過show index
來觀察,通常好比性別這個字段Cardinality
就很低,由於可能一個類型female
就佔據了全部行的一半,根本不必創建索引,而名字這個字段Cardinality
就很高,適合創建索引(固然也得是應用經常按名字檢索,這樣纔有必要創建索引)事務的實現主要依靠:程序員
redo
實現持久性,亦即commit
操做必須將專門的redo
日誌文件fsync
刷新到磁盤才能返回成功,合併多條語句插入優於一句一句插入也是由於減小了日誌刷盤頻率,因爲redolog
塊與磁盤扇區塊大小一致,因此無需doublewrite
;undo
實現回滾操做和MVCC,是存在於數據庫內部共享表空間的一個特殊段(undo
段)中的邏輯日誌,記錄了事務執行的反效果便於回滾,MVCC的實現是經過若某行記錄已被其餘事物佔用,當前事務能夠經過undo
日誌獲得改行以前版本的信息,需注意undolog
也會產生redolog
,亦即undolog
也須要持久性維護;purge
最終完成delete
和update
操做,由於Innodb支持MVCC,因此記錄不能在提交時當即處理,purge
操做判斷合什麼時候真正清理數據並回收undo page
,具體來講,若是一行數據不被真正引用那就可清理delete
和update
數據了;group commit
將多個事務的數據一次性調用fsync刷新到磁盤減小刷盤次數;binlog
,用來實現Point-In-Time
的恢復以及主從複製的實現,很是相似於redolog
,可是二者本質有很大不一樣:redolog
產生於下層只針對Innodb引擎產生,是物理格式日誌,記錄針對每一頁的修改,事務過程當中不斷被寫入;binlog
產生於中層,針對任何引擎都會產生,是邏輯日誌,記錄針對每條SQL語句,事務提交後一次寫入binlog
的,事務提交時既要寫binlog
也要寫redolog
,這就會涉及原子性問題,亦即兩個日誌必須同時寫入,經過先作prepare操做,將事務的xid寫入,而後寫入binlog,而後提交存儲引擎並寫入redolog 深刻Linux內核架構 (豆瓣): https://book.douban.com/subje...github
這是一本能把linux內核全貌展示給咱們的大部頭,涵蓋了包括進程管理,內存管理、鎖與通訊、設備驅動、文件系統等等。要採起觀其大略,用時細讀的策略,去宏觀的把握linux的設計哲學。
亮點:
fork
(父子進程只有PID不一樣,使用COW使得fork更高效,亦即子進程只複製頁表,只有父子某一進程要向內存寫入數據時才真正複製物理內存,若只讀則能夠共享而沒必要複製,這樣就延遲甚至消除了了大量的複製,節約了內存和CPU時間)和exec
(將一個新程序加載到當前內存中執行,舊的程序內存頁將刷出)。linux使用clone建立線程(或者說輕量級進程),相似於fork,可是能精確檢查哪些資源與父進程共享哪些爲線程獨立建立實際運行時間*(NICE_0_LOAD/權重nice值)
)最小的進程位於左下方會被調度器優先考慮,休眠進程被放入等待隊列中,喚醒後會從新被加入紅黑樹。實時進程是指該進程必須在指定的時間內完成好比飛機飛行控制指令,於是通常都有相對非實時進程較高的優先級,不一樣於非實時進程調度proc
標準掛載點是/proc
,其信息不能從塊設備讀取,只有在讀取文件內容時才動態生成相關信息,也能夠在不從新編譯內核源碼的狀況下修改內核行爲,與內核通訊,包含網絡信息、內存管理、進程特徵數據、文件系統、設備驅動、電源、終端、系統控制參數;sysfs
的標準掛載點是/sys
,是一個向用戶空間導出內核對象的文件系統,提供了查看和修改內核數據結構的能力;用於專門目的的小文件系統同窗們,堪稱整個現代互聯網軟件基石的Linux內核源碼就在這裏,有沒有勇氣去瞅瞅?
還有這本書更精簡,推薦給不想看太多源碼和細節的同窗: Linux內核設計與實現(原書第3版)。
Kafka權威指南 (豆瓣): https://book.douban.com/subje...
Kafka是一個高吞吐量的分佈式(支持分區partition、多副本replica、使用zookeeper協調)消息系統,目前普遍用來進行實時大數據處理如:hadoop批處理、storm/Spark流式處理引擎,web日誌、消息隊列等等,因此做爲一個後端開發者,頗有必要了解一下。我想的是把kafka做爲消息隊列的表明進行學習,未來若是要用ActiveMQ、RabbitMQ、ZeroMQ、RocketMQ等或者要本身要開發一個MQ均可以觸類旁通或者進行借鑑。
亮點:
ProducerRecord
對象,包含Topic
和value
,還可能有key
或者partition
,對象序列化後發送到分區器上,若是有partition則不操做,若無則根據key來指定partition(partition的設計目的是取消消息大小限制和提升並行度)。選好partition後發往對應的topic和partition的記錄批次,這一批記錄等待一次性的發往對應的broker(因此批的大小影響延遲和吞吐量),整個過程有失敗自動重試功能,超過必定次數返回客戶端異常。生產者經過設置ack=n
,能夠保證一個ProducerRecord
有n個副本(一個Partition的全部副本中有一個Leader負責與客戶端交互,其他副本做爲Follower從Leader複製數據,提供容錯性)被寫入成功纔會收到成功的ack消息。整個topic的順序沒法保證,1個分區的順序能夠經過設置retries>0
(重試次數),和max.in.flight.requests.per.connection=1
(1次只發1條消息避免後到的消息先成功)來保證,不過會嚴重影響生產者性能,若非嚴格順序要求不建議使用/brokers/ids
的臨時節點並訂閱其變動事件,在broker加入或退出時獲得消息;集羣中有一個控制器對應/controller
臨時節點(全部broker均可以嘗試建立節點成功則成爲Controller,失敗則知道Controller已經存在,全部broker都會監聽這個節點的變動,經過遞增的controller epoch來忽略舊控制器消息避免腦裂),除了完成broker功能以外還負責partition副本的leader選舉;持續獲得來自leader最新消息的副本叫作同步的副本,當leader失效時,只有同步的副本纔可能被選爲新的leader;不一樣partition的副本和leader都均勻的分佈在全部broker之間避免熱點問題,副本儘可能放在不一樣機架提升容錯性partition
都分紅了許多segment,一個segment包含1GB或者1周的數據(較小爲準),正在寫入數據的叫作活躍片斷,永遠不會被刪除。每一個分區還有一個索引提高查詢效率看完這本書基本就能把kafka的使用方法和基本原理搞清楚了,可是翻譯有時候有點點問題,我以爲普通的段落能夠翻譯,可是專用名詞如segment
、partition
等仍是直接保留比較好,省得有歧義,固然總體上來來講配合官網文檔讀起來仍是沒問題的。
要想深刻的話源碼在此。
NoSQL精粹 (豆瓣): https://book.douban.com/subje...
本書先分析了傳統關係數據庫的不足而後引入NoSQL,講到了鍵值、文檔、列族、圖等多種數據庫並分析了其優點劣勢,可讓咱們對NoSQL有一個全面的瞭解,爲咱們進一步NoSQL的探索之路開一個好頭。
亮點:
schemaless
)的數據。傳統關係數據庫有可持久化、模型標準便於共享和集成、事務支持等優勢,NoSQL有無模式便於程序對象與數據庫之間的映射、適應集羣等優勢。因此NoSQL和傳統關係數據庫各有所長,發展過程當中也在互相借鑑優勢,誰也不能取代誰,未來都會在各自的領域中發光發熱aggregate
)。聚合的邊界劃分沒有標準答案,取決於你以後準備怎樣操做數據。由於以聚合爲單位複製和分片比較天然因此集羣中操做數據庫仍是聚合更簡單。若數據操做大多在同一聚合內執行則應使用面向聚合的數據庫(鍵值、文檔、列族數據庫),若交互須要多種不一樣的格式則最好選聚合無知式(aggregate-ignorant
)數據庫(關係數據庫、圖數據庫),若待處理數據中有大量的關係最好就選關係數據庫,可是若是關係複雜、並行交錯最好選圖數據庫(插入費時、查詢比複雜的join
快得多)polyglot persistence
),好比購物車能夠用鍵值數據庫存儲,可是訂單要用關係型數據庫。因此除非是編程語言狂熱愛好者,咱們大部分人都不該該去爭論什麼語言好,什麼數據庫好,不要想着一把刷子走遍世界,而應該普遍瞭解,解決問題的時候選擇合適的工具,必要的時候也要本身改工具甚至造工具 本書的一個問題就是有點舊了,2013年第一版,這5年來NoSQL發展很快,已經被普遍用於企業級的系統之中了,尤爲是Redis和MongoDB,因此有需求就大膽的用吧。
大型網站技術架構 (豆瓣): https://book.douban.com/subje...
把事情作大是咱們許多人的追求,這本書就可讓咱們瞭解一下一個大型網站的架構應該要注意些什麼,不管是摸得着的tech仍是比較摸不着的leadership,都值得借鑑。固然,書很薄,大多隻能泛泛而談,要想真正掌握,每一部分咱們都得本身單獨深挖,因此本書能夠看作一個大目錄,爲接下來的學習指引方向。
亮點:
99.99%
,一年小於53分鐘不可用),實現高可用架構的主要手段是數據和服務的冗餘備份和失效轉移。應用層(文庫、貼吧、知道)和服務層(帳戶服務、session服務)由於通常無狀態因此很容易擴展(負載均衡),新節點上下線都很容易,可是服務層須要注意好分級管理、超時設置、異步調用、服務降級、冪等設計等。數據層(數據庫、文件、緩存)爲了保證數據不丟失須要複製並均勻分佈在集羣中讀完發現本書幾乎全程「黑友商」,有的甚至好幾遍(* ̄︶ ̄),有點不純粹啊。
這本書是infoq上的系列博客造成的一本很薄的書,對於瞭解JMM仍是頗有用的。
深刻理解Java內存模型(二)——重排序: http://www.infoq.com/cn/artic...
亮點:
Store
和Load
的排列 ,其中StoreLoad Barriers
是一個全能型的屏障,同時具備其餘三個屏障的效果,它確保store
數據對其餘處理器的load
可見深刻分佈式緩存:從原理到實踐 (豆瓣): https://book.douban.com/subje...
緩存在現在的互聯網中已經幾乎是標配了,分佈式緩存更是大型網站不可或缺的,本書就讓咱們從原理到開源實現到業務實踐一塊兒打包瞭解了。
亮點:
1次和N次
結果同樣,這個在分佈式系統中很重要是由於網絡抖動等因素經常致使重發;分佈式系統的本質是一堆廉價的硬件攢在一塊兒得到更好的吞吐量和性能以及可用性,有幾個問題廣泛關心:活性檢測(週期心跳、累計失效檢測)、高可用(主備、雙主、集羣)、容錯處理(冷熱切換、冗餘、備份)、重試機制(失敗重試、事務補償)、負載均衡(多機分擔請求),也有幾個實踐很重要:全局ID(數據庫自增id如flicker、UUID、snowflake、預生成置於緩存中)、哈希取模分配、一致性哈希(單調性、分散性)、路由表與數據拆分