# 採用快取機制的歷程 # Introduction 在後端工作中可能不時會聽到 - API 太慢了能不能再快一點? - API 速度是變快了,但為什麼每次的結果都不太一樣?有點不穩定呢! 在這些疑問之下,我們究竟面對哪些挑戰,有何種方式可以妥善處理? # Background 我們是一電商網站,因應銷售需求需要 API 來提供『百大熱門零食』的資訊。 - 資料存放在關連式資料庫中 - 零食銷售紀錄『每小時』更新一次 - 商品數量龐大,排行資料計算需要 **10 ~ 15 分鐘** - 分秒必爭,賺錢的機會不等人,API 的 response time 必須落在 **200ms** - response size 小於 2kb # Single Application 這時候只是一家剛起步的小公司,只是芝麻綠豆大的流量,一台機器就可以撐住全部的流量。 ## Pre-generate data 面對每次的排行紀錄都要耗費 10 ~ 15 分鐘,根本不可能在 200ms 內回應,於是做了下面這個決定 :bulb: 既然商品銷售紀錄每小時才會更新一次,那每小時預產一次『百大熱門零食』資料,我們直接取這張表的資料出來用吧! 歸功於預產資料,現在可以只花費 **50ms** 就從資料庫中取出『百大熱門零食』。 ## Database limitation (in-memory cache) 屋漏偏逢連夜雨,DB 的狀況時好時壞,忙碌起來的時候就算是一個簡單的查詢都需要 300ms 才能完成。 :bulb:既然每小時會預產一次資料,那表示這一個小時內資料不會變,我們從資料庫查詢出結果後直接存在 application memory 保存一小時吧! 歸功於省去 network round trip time (RTT) 和不穩定的資料庫處理時間,現在我們的 response 來到了穩定的 **35ms**。 # Distributed system 運氣不錯,隨著使用者數量的增加,公司也挖到了石油,現在我們的機器不只一台,也增加了 auto scaling 的機制。 在前面 single application 的設計開始出現了一些民怨:『誒,怎麼熱門零食的資料每次打開都不太一樣啊?』 原來是因為各個 application 都各自保留了一份『一小時』的紀錄,但卻來自於不同時段的預產資料。 ## 時間軸與其對應的事件 2:00 預產資料計算完成 **[仙貝、洋芋片]** 2:10 application(A) in-memory cache generated 3:00 預產資料計算完成 **[果凍、軟糖]** 3:05 application(B) in-memory cache generated 如果多位使用者在 3:06 的時候去拉『百大熱門零食』,就會分別有兩種樣貌的資料,來自於不同 application response :one: [仙貝、洋芋片] :two: [果凍、軟糖] ## Consistency (CAP theorem) 這樣可如何是好,難不成又要回去查 DB 紀錄嗎?那可不行! :bulb:既然是因為各個 application 保存一份資料才導致資料不一致,那我們統一一個來源,把預產紀錄放到 Redis去吧! 於是現在每小時統計後的紀錄都會放到 Redis 中,各個 application 就不再去 DB 也不自己保留資料在 memory 中,而是統一都透過 Redis 拿到一致的資料。 但因為多了一些 Redis network round trip time,回應時間上升到了 40ms,但還是可以接受。 透過這篇分享,是想給一些不知道快取機制是什麼,為何要採用 in-memory 或是 Redis 做快取的朋友們一個簡單的方向。
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up