2020年12月25日 星期五

[網站開發] 美股搜尋網站 Norn-StockScreener 加入Cache改善查詢效能

上次的開發心得:

[網站開發] 美股搜尋網站 Norn-StockScreener Ver1.0 Release

這次主要是幫後端程式加上cache, 這樣就不用每次查詢都要跑去DB問一次, 查詢時就直接從cache做條件過濾就好。 而cache的更新則是透過background thread每30分鐘去query DB更新cache, 雖然跟之前的查詢結果相比會有最多30分鐘的資料更新落差, 可是我的爬蟲跑完所有美股資料本來就要花上半天左右, 多個30分鐘的落差去換取使用者體驗還有DB查詢的負擔, 個人覺得是非常划算的! (畢竟以常理來說, 後端伺服器程式本來就不應該頻繁去DB查詢, 而是資料能存到cache就盡可能存cache, cache沒有或是資料庫有更新時在更新cache就好。)

決定好要加Cache之後, 再來就是想該怎麼實作了, 說到Cache第一個想到的就是火紅的Redis, 原本想說終於有機會可以開始玩Redis了, 可是研究下後發現, 覺得Redis並不適合用在我這個網站上, 原因有以下:

1. Redis本質上就是個cache server, 以cache的需求來說是非常強大的, 而且還支援簡單的query查詢, 可是他本質上依然不是DB, 不能做到NoSQL的各種查詢功能, 當然要做成類SQL查詢的cache table還是做得到的, 可是基本上就是做一堆reverse mapping table, 下面這篇就有教學怎麼設計Redis的cache table來做到SQL查詢:

How to get SQL-like Experience with Redis?

以上面的例子來說, 等於一個where條件我就要多做一個reverse mapping table, 而以stock screener來說幾乎是滿滿的過濾條件, 要做這麼大堆的reverse mapping table根本不划算, 除非今天我需要存到cache的物件很大, 用這種方式才划算, 以stock screener來說整個物件大小幾乎就等於過濾參數, 做這個感覺就撿不到便宜。

2. Redis基本上有需要用到的地方是可以水平擴展跨機器的程式, 讓所有程式都能共用 & 修改cache資料, 可是我的後端程式只放在一台VM上, 應該也沒有水平擴展的需求(畢竟要+機器就要要多花錢...), 如果是都在同一台機器上的process / thread需要共用cache的話, 那做shared memory就好, 根本沒有Redis出馬的必要阿...。

綜上所述, 就決定Cache直接用shared memory了, 而做法也很簡單, 後端伺服程式起來後就去跟Cosmos DB要資料, 然後存成JSON Array到記憶體裡, 之後有個background thread會每三十分鐘去跟DB更新cache, 而網頁前端打來的query資料則是直接用記憶體內的JSON Array做Linq查詢, 在吐回結果就好。

下面是有用cache跟每次去DB query的unit test比較結果, 48筆unit test沒有用cache要花1分53秒才跑完, 而有用cache則只要3秒就跑完了, 跟預期的一樣不用每次去query DB果然改善很多。


Cache的部分做完後, 還有些地方是需要設定的:

1. IIS的web application是會idle timeout以及regular recycling, idle timeout預設是20分鐘, 等於20分鐘沒有request那process就會直接停掉, 下次第一筆request就得等process起來 + 從DB讀資料, recycling的問題也一樣。

為了解決這問題, 這邊將設定改成6小時, 這樣至少process可以活6小時, 不改太大是怕IIS一直不recycling怕會有什麼奇怪的問題發生。 至於6小時後該怎麼辦, 這邊我是直接搭配freshping網站服務, 這個網站可以讓你設定50個網站, 然後他會每5分鐘幫你打一次request幫你檢驗網站是否正常工作, 搭配這服務我可以讓我的IIS網站就算idle太久而睡著, 也會在5分鐘以內被喚醒並更新cache。



2. 另外測試了一下, 從DB取得所有的個股資料大概要花1.7秒左右, 而這段更新cache的資料是得被lock保護的, 這代表使用者在query時如果撞到每30分鐘更新cache的時機的話, 會被那1.7秒卡住, 雖然1.7秒也不會說很長, 不過還是想解決這問題。 

至於想到的解決辦法也很簡單, 我就直接做兩份cache就好, 然後用一個flag去切換, 這樣cache更新跟使用者查詢用到的cache就不相同, 我只要lock保護那個flag就好, 這樣使用者就不用去花時間等待cache更新的時間, 畢竟切flag連1ms都不需要XD

這次更新就做到這邊, 下次更新應該是Google Play Store上架APP的部分, 目前網站的TWA App已經做好並提交到Google Play Store了, 就等審核結果如何~。

沒有留言:

張貼留言