Thursday, February 16, 2023

Web application 生成的報表速度太慢

 最近在 Gaiwan 公司遇到客戶委任我們做一些效能改進:

  1. 客戶把 code 的 link 給我之後,他們留下的訊息是說,覺得有沒有可能,把一些 code 改成用 Transducer 來改寫,效能就會好了。
  2. 我第一時間就覺得,八成不是這個問題。一般來講,web application 這種東西,會慢,十之八九都是資料庫的查詢在慢,更何況,客戶用的資料庫還是 Datomic 。
  3. 但是,光是有直覺沒有用,還是要設法証明。我很久沒有做 profiling 了,上次做疑似是十年前,總之,基本的概念還有,技術完全沒有。花了一些時間研究工具之後,發現有兩個程式很有用。
    (3.a) jcmd => 這個可以快速找到 java program 對應的啟動 argument 與 pid
    (3.b) VisualVM => 我是用 statistical mode 去量測。它可以幫你一層又一層地向下展開,看到 x function calls y function ,且 x function 的 total time, CPU time, self time 。我用了這個之後,層層展開函數呼叫後,果然,定位出來,最耗時的地方是資料庫查詢 (Database Query)
  4. 該怎麼改進呢? 一旦找到關鍵點了,要改就有很多可能性。在眾多的改法之中,我個人覺得工程略為耗大,但是一勞永逸的改法,是把資料 sync 到資料倉儲 (Data warehouse) 裡,把本來很慢的資料庫查詢都送到資料倉儲去。由於資料倉儲在 schema 、index 上都有許多神奇的最佳化,效能的大躍進滿可以期待的。
  5. 然而,這件事的結尾並不是使用資料倉儲。
    我老闆一眨眼就找出效能低落的關鍵點:N+1 problem 。速度很慢的那一段程式碼,它在迴圈裡做 Query 。如果 Query 是那種極度單純的,完全不需要 scan 資料庫的,老實說還好,畢竟 Datomic 在 peer 端做了大量的 cache ,並不會有很大的 I/O 開銷。 而我遇到的這個案例,迴圈裡的 Query 是有做一些些 unification 的。所以解決之道,是要改變程式碼的寫法,把 Query 移到迴圈外。 修改完之後,就快了 20 倍。

Thursday, February 9, 2023

Clojure syntax error 解決方案

使用 Clojure CLI 來做為啟動程式的話,由於 Clojure CLI 會生成 .cpcache 檔,啟動速度會比較快一點。然而,有的時候,.cpcache 可能有一些 cache 造成程式的載入順序錯誤,就會造成 syntax error 

如果遇到明明沒有寫錯 syntax ,卻一直得到 syntax error 的話,可以考慮將 .cpcache 刪除,就可以解決了。