發表文章

關於RCA

圖片
markdown # 關於RCA * RCA : 根本原因分析 ## 結論 * RCA是一種通用報告的格式,提供了一些通用的方法與計巧,讓問題可以從根本上被解決,可以參考[Here](https://asq.org/quality-resources/root-cause-analysis#resources) ## 我們小組上使用的簡易格式 * I. Problem Statement -> 定義/描述問題 * II. Cause & Effect -> 分析原因/造成影響 * III. Solution & Evaluation -> 提出解決方案/評估可行性 * IV. Topics behind the scenario -> 延伸討論 (如果還有的話) ### 節錄部份壓測的RCA報告 ```markdown ## I. Problem Statement * 接入平台需要能承受較大量的用戶。 * 壓測試後發現承載人數低下。 * 測試行為,登入 + 打訊息 + 圖片上傳 & 只打訊息,以不同的人數成增長與訊息數量測試。 ## II. Cause & Effect ### 登入導至OOM * 登入API 密碼加密每次使用64MB空間加密 -> 過多記憶體導至系統崩潰。 ### 併發下物件過多導至GC壓力 * 部份API在高併發下產生大量的物件建立與釋放 -> 使CPU 70%以上的時間花費在GC回收上 ### 編解碼使用的方式不適合高併發場景 * 通訊server的編解碼使用`map[string]interface` -> CPU效能 + GC壓力 ... ... ## III. Solution & Evaluation ### 登入導至OOM * 將密碼加密使用的空間降低 * 需注意玩家的token失效問題 * 要編寫過渡的程式才能無感更換 ### 併發下物件過多導至GC壓力 * 對於重覆使用的物件,在高併發下應使用sync.Pool池來減少GC壓力 ### 編解碼使用的方式不適合高併發場景 * 通訊server的CPU壓力可以透過多台機器分擔壓力(目前的做法) * 或調整編解碼方式減少物件壓力 * 由於MQ訊息沒分離,解決

Slice沒照預期的切片

圖片
markdown ## 結論 在使用make初始化slice的時候,要考慮初始的長度,若是只用兩個參數會使長度等於容量,也就是已經初始化過了,這時再用append的話就不會如想像那樣從頭開始新增資料了! ## 環境 go v1.19.6 ```go type Card struct { Word string Explain string } ``` ## 預期的對照組 * 這是正常運行的 ```go stackB := []Card{ { Word: "test", Explain: "test", }, { Word: "test2", Explain: "test2", }, { Word: "test3", Explain: "test3", }, } fmt.Println(stackB) // worked stackB = stackB[:2] fmt.Println(stackB) // worked ``` ## 非預期的狀況 ```go stack, _ := GetCardMap() fmt.Println(stack) // worked stack = stack[:2] fmt.Println(stack) // only 2 empty element func GetCardMap() (m []Card, err error) { file, err := os.Open("frequecydic.txt") if err != nil { return nil, err } defer file.Close() totalCount, err := VerifyDic(file) if err != nil { return nil, err } // move file pointer to the beginning of file _, err = file.Seek(0, io.SeekStart) if err != nil { return nil, err

睡覺使你更有效率

圖片
markdown # 睡覺使你更有效率 ## 自我對話 我們都知道,所以我有個想法,因為我總是讓自己睡的很少,我想是因為我認為我的時間變少了,我要讓自己知道充足的睡眠->更有效率的做事->更多的時間。 我要讓自己認為睡覺是很重要的,其實我原本就知道睡覺是很重要的,但我還是睡的很少。 我要讓這個想法更具體一點,我覺的睡滿八小時是很重要的,所以我要在`起床前九小時入睡,睡到自然醒即可`,這件事情很重很重要! ## 助眠的建議 * 低溫 * 規律的起床時間與睡眠時間 * 冥想 * 起床之後馬上接觸太陽光或任何足夠強的光線 5~10 分鐘 * 在睡覺前都做一樣的事情 (儀式)

非同步資料落地對於IM的重要性

圖片
markdown # 非同步資料落地對於IM的重要性 ## 結論 今天我在將建立訊息的API,從先在MySQL落地,改由直接送給Client並另外起一個Cron做異步落資料落地之後,效能從`每秒20人送訊息200人收訊息(4000封/s)`提升至`每秒60人發訊息600人收(36000封/s)`,實屬相當大的進步。 ## 原因 我想是MySQL對於多次連接+小資料的更新與新增很不拿手,因為MySQL每次都是要碰Disk的,而且資料不是連續的導致I/O的時間會很長。 在調整成異步落地之後資料不會經過Disk,而是從API->MQ->Websockt->Client,所以快很多。 並且在異步的資料落地時,採用的是批次插入資料,這可以讓MySQL只需要少量I/O就可以完成大筆資料插入。 ## 應注意的部分 ### 不適合的場景 * 100%訊息都無法遺失,只要預到停電,OOM等事故,Mem是會消失的。 * 資料有立即提取的需求,既然是異步,就無法保證在加入一筆資料之後馬上查詢可以查到資料。 ## 適合的部份 * 資料不是那麼重要的,可以接收遺失,策略可以是幾分鐘內的可能會遺失,

gojmapr 我的第一個開源項目

圖片
gojmapr 在README中放入blog連結 Hi 各位,我做了一個Golang開源項目! → gojmapr 介紹 GO JSON MAPPER 簡稱 gojmapr 。 這是一個可以從一坨JSON中只取一些值並Map到的套件。 你有遇到第三方傳來的JSON很復雜,但是你只需要其中幾個屬性而不得不宣告一個超大還層層嵌套的結構嗎? 你在讀取外部JSON的資料時必需要 account.user.cart.order... ? 這就是你要找的套件了!:) 套件的誕生 起初我是在寫後端API,我在接從前端來的呼叫時發現我花了很長的時間寫好對應的struct,每次使用時候還必需寫超級長,就產生了 為什麼不能用簡單的struct直接讀取我要的值就好了 ,這樣不僅不用寫一大堆struct嵌套,也不怕之後維護的人把整個struct傳來傳去很難維護。 用法 先來一個復雜的JSON結構 jsonString :=`{ "cart" : { "items" : [ { "product" : { "id" : "123" , "name" : "Product A" , "description" : "Product A description" , "price" : 10.99 }, "quantity" : 2 }, { "product" : { "id" : "456&

Docker 筆記 連環境也一起打包工具

圖片
將環境打包成image並直接運行,由於打包的關係,所以互不影響 image是打包好的映象檔 container是映像檔被執行後產稱的一堆檔案 基本套路: 寫好Dockerfile然後build,他就會照你的Dockerfile建立出image檔 docker run 執行 from imageI docker exec 執行 from container docker logs <container ID> 查log --rm 當container變成Exited時,自動移除container -d 背景執行 docker rm -f 強制移除container,可省略stop -p port映射 -e key=value 設定到環境變數 $pwd 神奇變數: 當下的目錄 -w 進入container後預設在哪個目錄下執行指令 volume 倉庫 原本container玩自己的,但是你指定他的一些玩具只能在倉庫(volume)中玩,於是你就可以透過存取倉庫,在container以外的地方備份或存取資料了 參考 -v [/host]:[/container][param] 將volume掛載到container上(將/host目錄 Mapping到 /container目錄),param可以設定讀寫權限 --volumes-from [container] 直接使用某個container現在的volume Network 網路 讓很多container加入倒network裡面,就可以利用container name來互相呼叫與使用 (像是-link) $docker netowrk create my-net 建立network $docker run --network my-net 加入倒my-net的network Dockerfile $docker build . 拆解Dockerfile並一一執行 -t=[image]:[version] 指定tag,使用的image與產出image的版本號 --no-cache 不快取 檔案 .dockerignore 像是.gitignore,用來避開在build的時候不要的檔案 FROM

怎麼樣做一個可以被Import的Go包

圖片
在這裡我將嘗試怎麼做一個最小的Go,放在github給別人引用 結論&要點 go.mod 中 module 應該為你的github路徑,這樣可以避免引用名稱不同的問題 小版本更新使用 tag 來上傳,破壞性更新再modle 最後方加上/v2, v3等字樣 檔名不要使用main.go 其餘應該都可以 package會是別人取用工具包的名稱 已完成的github包 github.com/limiu82214/GoHellowWorldForImport 過程 初始化 go mod init GoHellowWorldForImport 並上傳至github 寫main.go,並在另一個地方使用 go get ... 看到錯誤訊息 import "github.com/limiu82214/GoHellowWorldForImport" is a program, not an importable package (compile) ,因此猜測不能用main.go 更名為 GoHellowWorldForImport 在試一次 (包含package與函式) 由於快取的關係,新增tag代表新的版本號並上傳再試一次 拿到錯誤訊息,推測module名必須是 github.com/limiu82214/GoHellowWorldForImport 以符合import格式 go : github.com/limiu82214/GoHellowWorldForImport @v0 . 0.2 : parsing go. mod : module declares its path as : GoHellowWorldForImport but was required as : github.com/limiu82215/GoHellowWorldForImport" 測試成功,更改參數並記錄要點