2015年10月22日 星期四

[JavaScript] 在 for loop 中,使用 var 宣告 object 並在 async function 呼叫該物件時的 scope 問題

之前在寫 javascript 有碰到在 for loop 中,使用 var 宣告 object 並在 async function (例如 event)呼叫該物件時的 scope 問題。最近有空把它整理出來。

以下面這個範例為例,正常預期是依據按鈕是 hello 1、hello 2....點支下去 alert 的分別是 hello 1、hello 2....等,跟按鈕顯二的文字一樣。

在下面的例子中,在 onclick event 中, alert 的都是 hello 5
但在 for loop 中時,console.log(say.hello()); 是符合預期的。
這應該 var scope 範圍,和 var say 物件和 var i 因為 call by reference 的關係,reference 到最後一個實體
(因使用 alert 的關係,要點擊右上角 edit in JSFiddle 才能正確執行)



最簡單的解法是使用 let 來宣告,如下例 (只有 chrome 和 edge 可以用)
只改 var say => let say 來說明

但這個方法最主要問題是目前還有許多瀏覽器未支援,並不適合用在客戶端的產品上
Ref: http://caniuse.com/#search=let



另一個想到解法是使用 array 的 forEach 讓其產生獨立的 scope 空間
沒 forEach 之類的怎麼辦!?只好硬幹建一個 array 塞進入 XD
如下



那還有沒有其他解法?

JavaScript.tw FB社群:施文祥、Yuren Ju 
提供的 babel,compiler 出來的方法
把 loop 內改成 function ,在 loop 中呼叫 function



JavaScript.tw FB社群:Ly Cheng 
提供使用匿名函數 + bind 方式來解



同理可證
直接整個用匿名函數也能解,但效能可能就不怎麼樣

2015年10月20日 星期二

[MongoDB] MongoDB Performance Optimization

曾經碰過 MongoDB 效能問題,資料筆數已達到兆,硬碟也達到 TB,這個問題會造成:

  1. MongoDB 不定時當機,頻率大概一個月一次
  2. 在人多時,某些查詢的 Response time 會很大,最長時可達到 3600s 左右
  3. 以上述的查詢如果一多,會佔住資源,同時也會連帶影響到其他查詢,並拖慢整體速度

大致發生原因如下:

  1. MongoDB 本身是 Document base 資料儲存,適合資料完整儲存,跟 RDBMS 不同的是 RDBMS 會做正規化,之後使用 join 方式 (或多次查詢) 產生 Document。在該系統的 Data Schema 設計上還是使用 RDBMS 的邏輯,故資料需要多次查詢才能產生 Document。
  2. 大部份主要查詢的條件,需要的 index 沒有建立
  3. Page Faults 機率高
  4. 在某些情況下,資料查詢資料數多時很慢
  5. Primary 的 Loading 很重,Secondary 都沒有存取
  6. Database Level lock 會影響到 Read Write Concurrent 的數量

解決的方法也分別如下

  1. 功能 Data Schema 設計上要考量的點。
  2. 建立要用到的 index,使用 Compound Index 來減少所要建立的 index 數量,保持原 specn 不變原則下,同時也要更改程式查詢條件的順序,符合 Compound Index 使用限制。
  3. 提高 memory。
移除用不到的 index,MongoDB會儘力將 index 索引放入 memory,移除用不到的 index 可以讓需要的 index 放入 memory 中。另外依據 index 的 field 有時 index 的資料量會大於真正的實體資料,故也能減少硬碟使用量。
  1. MongoDB 在做分頁就存在的問題,例如 skip or it 在查詢較後面的資料會變慢(跟有無加 limit 沒關係)。所以一般做分頁是直接用條件方式過濾,例如 _id < ‘xxxx’ 會快很多,這可能跟 mongodb 存資料的方式有關。大部份查到的案例是大家在用 remove 有發現這個現象,所以才有 TTL index 的出現吧?所以如果存在一個功能在需要取得全部的資料時,就變的很可怕。跟 PM 商量該業務邏輯是不是可以用其他方式處理,來避開此問題。
  2. 這是程式在建 connection 時並沒有把 Secondary 寫入所致。和 Read Preferences 並沒有設定,修正程式即可。
  3. 當時沒時間做,修完上述五項後,就沒在當過機了。解法有二,更新 3.0,3.0 有 Document Level Lock。另一個是 WhoCall 宋先生在 PHP Conf 2014 分享的一個 Database 一個 Collection,把 Database 當成 Collection 來使用,也是要實驗過才曉得。

處理的方法:

  1. 打開 slow log,整理問題
  2. 學習 MongoDB (大部份資料官網都有寫)
  3. 建立實驗環境
  4. 用 slow log 的 query 在實驗環境上測試,並同時確認使用該查詢的程式碼,可以使用 explain 看查詢狀況 ( status 看 MongoDB 狀況)
  5. 修正問題點,再看實驗結果。不對,就重複步驟 4, 5,直到所有查詢平均能在 1s 左右完成,花最多時間在這裡
  6. 佈署到 Staging,測試系統
  7. 測試沒問題,佈署到 Production

針對優化大致會碰到地方,整理了份心智圖
可以方便去尋找可能的效能問題點






Ref:
https://docs.mongodb.org/manual/core/crud-introduction/
https://docs.google.com/file/d/0B-59_4gDCY8XamJ6X0NySXhZdnM/edit?pli=1