go-openbbsmiddleware icon indicating copy to clipboard operation
go-openbbsmiddleware copied to clipboard

關於一些記錄的 counter.

Open chhsiao1981 opened this issue 4 years ago • 17 comments

Is your feature request related to a problem? Please describe. 關於一些記錄的 counter.

Describe the solution you'd like 使用 redis 來記錄 counter.

Describe alternatives you've considered

Additional context

chhsiao1981 avatar Jul 29 '21 20:07 chhsiao1981

可以加上 prometheus 的 exporter

https://github.com/prometheus/client_golang

chhsiao1981 avatar Jul 29 '21 20:07 chhsiao1981

請問有哪些資料需要呢?目前有想到的大概有:在線人數,人氣,推文數等,可能會需要把這些數據相關的 api 一起完成或是修改。 這個 issue 要建立 redis 連線的參數,如果要做的話,我會一併把 docker-compose 那邊一起建立起來

tingyuchang avatar Nov 03 '21 13:11 tingyuchang

這個好像有分兩種~ 一種是給 frontend 看到的數字 (在線人數 / 人氣)

"給 frontend 看到的數字" 很 tricky~ by 板的數字目前應該會是每隔一段時間 (10 mins) 讓 mongo aggregate 最近 10 分鐘有摸過板 / 摸過 api 的. 又或者是可能可以想想其他方式拿到數字. 然後就 cache 到 redis 裡.

redis 有類似的 code. docker-compose 裡也已經有 redis 囉~

key 的 convention 是 [prefix]:[key] (lock 的 prefix 是 lock. counter 的 prefix 就 counter 吧~)

https://github.com/Ptt-official-app/go-openbbsmiddleware/blob/main/schema/lock.go

https://github.com/Ptt-official-app/go-openbbsmiddleware/blob/main/schema/init.go#L224

https://github.com/Ptt-official-app/go-openbbsmiddleware/blob/main/docker/docker-compose.yaml#L23

另外一種是偏給系統和後台紀錄. (api 的 count, login fail 的 count, 其他特殊 event 的 count)

最近發現 prometheus 很容易就可以搞定這件事: https://github.com/prometheus/client_golang https://prometheus.io/docs/guides/go-application/

chhsiao1981 avatar Nov 04 '21 09:11 chhsiao1981

ok 我明白了,第一種給 frontend 用的 count-cache 我先想看看生成的機制以及移除(invalidation) ,第二種的話,我對 prometheus 不熟,我先玩看看他是怎麼運作的,再來討論需要觀察的數據是哪些

tingyuchang avatar Nov 04 '21 13:11 tingyuchang

在線人數:key -> [count:active-USERID] value -> [lastAPICallTime] ,需要統計的時候就用 redis 的 key pattern ('keys', 'count:active-*') 這個是 O(N) ,應該不會算慢,不過這樣對 redis 的負擔有點高,也許我們可以再設定一個 Key-Value 定時統計上述的數字,讓 API 直接讀取這個數字就好,每一個 active-user 的 invalidation 可以有兩種做法,一個是設 expried 讓 redis 自動刪除,或是排成定時去掃 lastAPICallTime 已經超過某一個範圍的 active-user,這兩種方法都要能夠更新 active-user 的 lastAPICallTime ,可以在某些常用的 api 加入這個規則,或是給一隻 api 讓 frontend 去呼叫。 另外這邊只有統計 go-openmiddleware 的人數 c-pttbbs 要額外從 go-pttbbs 去拿才行

tingyuchang avatar Nov 05 '21 03:11 tingyuchang

Prometheus 的部分我研究之後,它可以很容易紀錄這些資料

  1. Counter: API 的呼叫數量、錯誤失敗的次數、任務執行的次數,只能增加或歸零
  2. Gauge: 可以增減的數字,拿來紀錄狀態:cpu, memory, go-routine 的數量等等
  3. Histogram & Summary: 可以做為統計數據的資料,像是 avg, mean, mid 等,所以可以拿來計算 request duration, response size 等需要一定數量的資料才有意義的數據

tingyuchang avatar Nov 06 '21 02:11 tingyuchang

  1. 在線人數: 會是固定一段時間 (每分鐘或是每 10 mins) update 一次. update 結果放在 redis 裡. (所以 redis 裡只會有 1 個數字) update 的 source 可以從 mongo 拿到 go-openbbsmiddleware 和 go-pttbbs 拿到 c-pttbbs 的人數.
  2. 我們應該是只需要記我們自己想要用的 counter 就好囉~ prometheus go lib 就內建自動幫我們紀錄 system-level 的數字. histogram / summary 是 prometheus 自己內部的運作結果. 通常會直接用 grafana 呈現出來.

chhsiao1981 avatar Nov 07 '21 16:11 chhsiao1981

在線人數:ok 沒問題,那就改成從 mongo aggregate active api users,以及從 go-pttbbs 拿人數,加總之後寫入 redis ,這一個動作會寫入 cronjob 定期執行。 Prometheus: 目前看起來可以先搜集

  1. api 的呼叫次數
  2. api return error 的次數

使用 gin 的 middleware 應該可以比較簡單解決這個需求,有看到 opensource 或是自己寫應該也不複雜~

tingyuchang avatar Nov 08 '21 08:11 tingyuchang

我先從 active users 開始做,目前看了 db 裡面的 collection ,應該可以用 user_read_article user_read_board 兩個來完成 openbbsmiddle 這一端的上線人數。

btw 水球系統那邊未來應該有打算串 websocket ?也許那時候直接算 connecting client 的數量就好了~

tingyuchang avatar Nov 19 '21 00:11 tingyuchang

剛剛想到是有可能 user_read_articleuser_read_board 重複算到~ 是可以再開一個 collection 是 user_visit. 然後就 Update({UserID}, {UpdateNanoTS, Action})

然後就可以 Count({UpdateNanoTS > now - 10 mins})

chhsiao1981 avatar Nov 19 '21 01:11 chhsiao1981

好,那我再建一個新的 collection: user_visit: user_id, update_nano_ts

tingyuchang avatar Nov 19 '21 06:11 tingyuchang

Screen Shot 2021-11-25 at 2 30 54 PM

  1. action 的部分先用 url 代替
  2. user_visit record 我的想法是一個 user 只會有一筆資料,會透過每一次的 api 呼叫來更新 user_visit 的內容

tingyuchang avatar Nov 25 '21 06:11 tingyuchang

@tingyuchang

非常感謝! 大致上是 userVisit.Update({user_id: "matt"}, {Action: [url], UpdateNanoTS: 1234567890000000000}) 應該就可以囉~ (好像其實 action 還有 POST / GET 的區別~. 看看是否要加上 method)

chhsiao1981 avatar Nov 25 '21 21:11 chhsiao1981

好,我會加上 method,另外我有注意到你的格式是 ({user_id: "matt"}, {Action: [url], UpdateNanoTS: 1234567890000000000}) 請問跟目前 document 的 json format 比 ({user_id: "matt", Action: [url], UpdateNanoTS: 1234567890000000000})

是希望 user 獨立出一個 struct 嗎?

tingyuchang avatar Nov 26 '21 06:11 tingyuchang

@tingyuchang

並不是喔~

Update 包含著 filter 和 update 的部分.

其中 {user_id: "meet"} 是 filter 的部分. {Action: [url], UpdateNanoTS: 1234567890000000000} 是 update 的部分.

https://github.com/Ptt-official-app/go-openbbsmiddleware/blob/main/db/collection.go#L200

chhsiao1981 avatar Nov 26 '21 17:11 chhsiao1981

喔喔,是我誤會了XD

tingyuchang avatar Nov 27 '21 01:11 tingyuchang

目前剩下的部分:

  1. 看板的在線人數
  2. Prometheus
  3. 其他待補充

tingyuchang avatar Dec 05 '21 01:12 tingyuchang