軟件架構-緩存技術

{"type":"doc","content":[{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文源自併發編程網的翻譯邀請,翻譯的是 Jakob Jenkov 的 ","attrs":{}},{"type":"link","attrs":{"href":"http://tutorials.jenkov.com/software-architecture/index.html","title":""},"content":[{"type":"text","text":"《軟件架構》","attrs":{}}]},{"type":"text","text":" 中關於緩存技術的內容,雖然是 2014 年的文章,但是從軟件架構層面上,並不過時。","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"緩存","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"緩存是一種加速數據查找(數據讀取)的技術,直接讀取本地緩存的數據,而不是從數據源讀取數據,數據源包括數據庫、其他遠程系統。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/78/78c5ea9dd8f0673009f82786560e26ef.png","alt":"caching","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"緩存是比源數據更靠近使用方的一塊存儲空間,可以更快的讀取操作。緩存的存儲介質一般是內存或磁盤,很多時候會選擇內存作爲緩存介質,但是內存緩存會在系統重啓時丟失數據。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在軟件系統中,數據緩存存在多層緩存級別或多層緩存系統。在 web 應用中,緩存至少有 3 種存儲位置,如下圖所示:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/80/8062581fe8f2901eaa8bff8930166285.png","alt":"caching","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 web 應用中,我們會使用各種各樣的數據庫存儲數據,這些數據庫可以將數據存放在內存中,以便我們直接讀取,而不需要從磁盤中讀取數據。web 服務器可以在內存中緩存圖片、css 文件、js 文件等,不需要每次需要的時候從硬盤中訪問文件。web 應用可以將從數據庫讀取的數據緩存起來,這樣就不需要每次使用的時候都通過網絡從數據庫中讀取數據了。最後,瀏覽器也可能存儲靜態文件和數據。在支持 HTML5 的瀏覽器中,有 localstorage 存儲空間、應用數據緩存、本地 sql 存儲等技術支持緩存。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當我們提到緩存的時候,有下面幾項內容需要考慮:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"寫緩存","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"保持緩存和遠程系統數據同步","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"管理緩存大小","attrs":{}}]}],"attrs":{}}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我會在接下來的內容中討論這幾項內容。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"寫緩存","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第一項挑戰是從遠程系統中讀取數據寫到緩存中,一般有兩種方式:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"提前寫緩存","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"用時寫緩存","attrs":{}}]}],"attrs":{}}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"提前寫緩存是在系統啓動的時候,就將需要的數據緩存起來。要做到這一點,需要提前知道哪些數據需要緩存。但是我們有時候並不知道哪些數據需要在系統啓動時候就緩存起來。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"用時寫緩存是說,在第一次使用數據的時候,將數據緩存起來,之後就可以使用緩存中的數據了。這種操作的方式是,首先檢查緩存中是否有數據,有就直接使用,如果沒有,就從遠程系統讀取數據,然後寫入緩存中。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下表中我列出了提前寫入和用時寫入的優缺點:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"提前寫緩存","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"優點:比用時寫入減少了第一次緩存數據的延遲","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"缺點:系統啓動初始化緩存數據的時候,需要比較長的時間。而且,有可能緩存的數據永遠不會被用到。","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"用時寫緩存","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"優點:緩存的數據都是需要被用到的數據,而且沒有啓動延遲","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"缺點:在第一次緩存數據的時候,用的時間比較長,可能導致用戶體驗不一致","attrs":{}}]}],"attrs":{}}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當然,在真正實踐過程中,我們可能兩種方式並用:我們可以對熱點數據使用提前緩存的方式,對其他數據使用用時緩存的方式。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"保持緩存和遠程系統數據同步","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"緩存數據的一個巨大挑戰是保持緩存數據與遠程系統數據保持同步,也就是數據一致。根據系統結構的不同,一般有不同的方式實現這個,我們來聊聊這幾種方式。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"直接式緩存","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"直寫式緩存是允許讀寫緩存的一種方式,這種方式是,保存緩存數據的計算機,在將數據寫入緩存的同時,將數據寫到遠程系統中。簡單說就是,寫入操作被寫到遠程系統中。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"只有遠程系統的數據只能被直寫式緩存修改時,這種方式才起作用。如果所有的數據讀寫都要經過直寫式緩存系統,那就很容易將寫入的數據更新到遠程系統中,保持緩存與遠程系統數據的一致性。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"基於過期時間","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果遠程系統可以不依賴遠程系統進行數據更新,那緩存和遠程系統之間數據同步就很難通過直寫式緩存方式保證了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"保持緩存數據同步的一種方法是,爲數據設置一個緩存時間。當數據過期時,就把這些數據從緩存中清除。如果再次需要讀取這些數據,可以從遠程系統中讀取最新的數據緩存起來。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"數據過期時間取決於系統需要,有些類型的數據(比如文章),可能不需要隨時的完全更新,可以設置 1 小時的過期時間。對於某些文章,你甚至可以忍受 24 小時的過期時間。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"需要注意的是,如果過期時間比較短,可能會頻繁讀取遠程系統,降低緩存的作用。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"主動過期","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"還有一種方式是主動過期,是指主動更新緩存數據。比如,遠程系統數據更新時,發送一條消息到緩存系統中,指示系統數據已被更新,可以將數據設置爲過期。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"主動過期的優點是,可能保證遠程系統數據更新後,緩存數據被儘快的更新。還有一個附加好處是“基於過期時間”方式沒有辦法是實現的,就是不會頻繁更新沒有修改的數據。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"主動過期的缺點是,需要能夠檢測遠程系統數據的變化。如果遠程系統是一個關係型數據庫,可以被不同的機制更新數據,那每種更新機制都需要報告他們更新了哪些數據,否則,就沒有辦法向緩存數據的系統通知過期消息了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"管理緩存大小","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"管理緩存大小,是一個重要的方面。許多系統存儲了大量數據,以至於不可能將所有數據都存儲在緩存中。因此,需要一種機制來管理緩存的數據量。管理緩存大小通常是將不需要的緩存數據清除,來騰出足夠的空間。一般有下面幾種方式:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基於時間清理","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"先進先出(FIFO)","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"先進後出(FILO)","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最少被使用","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最小訪問間隔","attrs":{}}]}],"attrs":{}}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基於時間清理方式是類似於前面提到的基於時間過期。除了可以保持數據與遠程系統同步,還能夠減少緩存數據的大小。可以開啓一個單獨的監聽線程,也可以在讀寫新值的時候清理數據。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"先進先出清理方式意味着,當寫入一個新的緩存的時候,就需要刪除最早插入的緩存值。如果空間足夠,也是可以不刪除任何數據的。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"先進後出的方式正好和先進先出相反,這種方式對於先存儲的數據時熱點數據的情況比較有用。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最少被使用清理方式是首先清理訪問次數最少的緩存數據。這種方式的目的是避免清理熱點數據,爲了實現這種方式,需要記錄緩存數據被訪問的次數。需要注意一個問題,緩存中的舊值可能有較高的訪問次數,這樣就意味着這些舊值不會被清理。比如一篇舊文章的緩存,以前被訪問過很多次,但是最近很少訪問了,但是因爲原來的訪問量很高,儘管目前訪問量較低,也不會被清理。爲了避免這種情況,訪問次數可以是針對 N 個小時統計。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最小訪問間隔清理方式是將訪問時間間隔考慮在內。訪問某個緩存數據時,就需要標記訪問該數據的時間並增加訪問次數。第二次訪問這個緩存數據時,就增加訪問次數,並計算平均訪問時間。那些曾經是熱點數據,被頻繁訪問,但是最近訪問時間間隔變長,訪問頻率下降的數據,其平均訪問時間會降低,當降到足夠低的時候,就會被清理。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有一種變化方式是,只計算最後 N 次訪問的時間。N 可以是 100、1 或者其他任何有意義的數。每當訪問計數到 N 時,訪問計數被重置爲 0,記錄下來訪問時間。這種方式可以更快的清理熱度下降的數據。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"還有一種變化方式是,定期重置訪問計數,並且只使用最小訪問的清理方式。比如,每緩存一個小時的數據,前一個小時的訪問計數會存儲在另一個變量中,以便決策清理時使用。下一個小時訪問計數重置爲 0。這種機制具有上次變化相同的效果。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最後兩個變體之間的差異總結起來就是在每次緩存檢查時,訪問計數是否已達到 N,或者時間間隔是否已超過 Y。第一種方式是每隔 N 次訪問一次系統時鐘,而第二種方式在每次訪問時都讀取一次系統時鐘(查看時間間隔是否已過期)。因爲檢查一個整數通常比讀取系統時鐘快,所以我會選擇第一種方式。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"請記住,即使使用緩存大小管理系統,也需要清理、讀取和存儲數據,以保證他們能夠與遠程系統保持一致。儘管緩存的數據被大量訪問而駐留在系統中,有時候也需要與遠程系統同步。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"服務器集羣中的緩存","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"單一服務中的緩存設計更加簡單,因爲你能夠保證,所有寫入操作都通過一個服務器,可以使用直寫式緩存方式。但是在分佈式集羣中,情況會比較複雜,下圖說明了這種情況:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/2e/2e3ee4c2f6fbb9a355a5eaf686ec3d1e.png","alt":"caching","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"簡單的使用直寫式緩存只會更新寫操作的服務器上的緩存,集羣中其他服務器對此完全不知情,也就不會更新數據。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在服務器集羣中,可以使用基於時間的過期策略或者主動過期策略,來保證緩存數據與遠程系統的同步。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"緩存產品","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"實現自己的緩存系統並不難弄,取決於是否需要深度定製。如果沒有必要自己實現緩存系統,可以用已經現成的緩存產品。比如:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"http://memcached.org/","title":""},"content":[{"type":"text","text":"Memcached","attrs":{}}]}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"http://ehcache.org/","title":""},"content":[{"type":"text","text":"Ehcache","attrs":{}}]}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://redis.io/","title":""},"content":[{"type":"text","text":"Redis","attrs":{}}]},{"type":"text","text":"【譯者加】","attrs":{}}]}],"attrs":{}}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我不知道這些產品是否能夠滿足需要,但是我知道他們用的比較廣泛。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/9e/9e305acd1cca75053c144cb28adc6061.png","alt":"公衆號:看山的小屋","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章