golang 編寫的在線redis 內存分析工具 rma4go

redis 內存分析工具 rma4go

redis是一個很有名的內存型數據庫,這里不做詳細介紹。而rma4go (redis memory analyzer for golang) 是一個redis的內存分析工具,這個工具的主要作用是針對運行時期的redis進行內存的分析,統計redis中key的分布情況, 各種數據類型的使用情況,key的size,大key的數量及分布, key的過期狀況分布等一些有助于定位redis使用問題的工具,希望這能夠給應用開發者提供便利排查生產中所遇到的實際問題。

rma4go的應用場景

redis是目前很流行的一個內存型數據庫,很多企業都在使用。 但由于業界并沒有很多對于redis使用上的規范,或者是有一些規范并沒有被很好的遵循, 存在很多redis使用上的問題,我這邊就列舉一些例子:

  1. redis 存用滿了, 不知道key的分布情況,不知道來源于那個應用
  2. redis 被block了,不知道什么原因導致的block,是哪個應用里的什么key的操作導致的
  3. 想遷移redis數據,或者調整一些設置,但不知道要不要對redis里的數據進行保留,以及不知道什么業務在使用等
  4. redis的key的過期情況不明朗, 不知道哪些東西可以刪除或者調整

其實上面的一些問題是我隨便列舉出來的一些,并不是所有的存在的問題,相信也有很多其他場景同樣會用到這樣的一個redis內存分析工具rma4go

rma4go的具體功能

數據維度

對于key的分析我們這個工具會提供如下幾個維度的數據:

  • key的數量分布維度
  • key的過期分布維度
  • key的類型分布維度
  • key對應的的數據的大小分布維度
  • key的前綴分布維度
  • 慢key與大key的維度

當然以后如果發現有更好的緯度也會添加進去,目前先以這幾個緯度為主

數據類型設計

type RedisStat struct {All     KeyStat `json:"all"`String  KeyStat `json:"string"`Hash    KeyStat `json:"hash"`Set     KeyStat `json:"set"`List    KeyStat `json:"list"`ZSet    KeyStat `json:"zset"`Other   KeyStat `json:"other"`BigKeys KeyStat `json:"bigKeys"`
}// distributions of keys of all prefixes
type Distribution struct {KeyPattern string `json:"pattern"`Metrics
}// basic metrics of a group of key
type Metrics struct {KeyCount       int64 `json:"keyCount"`KeySize        int64 `json:"keySize"`DataSize       int64 `json:"dataSize"`KeyNeverExpire int64 `json:"neverExpire"`ExpireInHour   int64 `json:"expireInHour"`  // >= 0h < 1hExpireInDay    int64 `json:"expireInDay"`   // >= 1h < 24hExpireInWeek   int64 `json:"expireInWeek"`  // >= 1d < 7dExpireOutWeek  int64 `json:"expireOutWeek"` // >= 7d
}

實現細節

key元信息

type KeyMeta struct {Key      stringKeySize  int64DataSize int64Ttl      int64Type     string
}

眾所周知, redis里的所有的數據基本都是由key的, 也是根據key進行操作的,那么對redis里的key進行分析我們必須要記錄下來這個key的信息才可以做到, 我們能記錄的信息正如以上結構中的一樣, key本身, key的大小, 數據的大小, 過期時間以及key的類型。這些信息是我們對key進行分析的一個基礎信息,都可以通過一些簡單的redis命令就可以取到。

遍歷redis所有key

要對一個redis進行完整的key分析, 我們就需要有辦法能夠訪問到所有key的源信息, 所幸redis提供了 scan這么一種方式可以比較輕量的遍歷所有的key,訪問到相應的key的元信息。
這樣對于redis而言, 進行在線key分析的時候造成的壓力也不會非常大,當然key分析不能再QPS高峰期進行, 需要在redis資源余量允許的情況下進行分析。

另外由于redis本身的一個內存清理機制,有25%的過期占用可以在分析key的時候被清理掉, 因此這個分析工具同時兼具了清理一部分內存的作用, 如果redis里面存在過期的而且存在于內存里面的key的話。

對記錄的信息進行分析與匯總

有了遍歷所有key的方法, 又有了元數據, 剩下的事情就是把這些數據進行聚合匯總, 這個主要是一個算法上的工作,
最難的部分要數這個key聚合的部分了, 這里面有很多取舍, 由于作者我本人不是專攻算法的, 而且沒有找到合適的庫, 因此只能動手自己想了一種方式。 基本的思路是:

壓縮的算法
  1. 對于每個新的key的元信息, 添加到老的key分析對象里去
  2. 對這個key從后往前縮短, 去除尾部,看是否已經包含這個key的統計信息,如果包含, 則把key的信息累加上去, 如果不包含則創建一個新的紀錄。
  3. 當記錄的個數添加到一定數量的時候, 對對象的個數進行一次壓縮

    • 壓縮的算法也是從字符串的末尾往字符串首部進行壓縮
    • 當壓縮不能增加這個pattern 的key的個數的時候使用原來的key(壓縮前的key)
    • 當壓縮可以增加這個pattern的key的個數的時候,進行key的合并,把pattern設置成壓縮后的pattern
    • 當記錄的條數超過指定的條數就循環往復,直到壓縮到小于指定的條數為止
    • 如果對于key的最小長度(就算再壓縮也要保留一兩位)有要求, 有一些壓縮到字符串的最小長度的參數可以進行調整與設置, 進行一定的取舍。
  4. 直到scan完畢
代碼如下
const (defaultSize = 128compactNum  = 30maxLeftNum =  150minKeyLenLower = 2minKeyLen   = 5
)func (stat *KeyStat) compact() {distMap := stat.DistributiontmpMap := make(map[string][]string, defaultSize)shrinkTo := compactNumfor k := range distMap {compactedKey := kif orgks, ok := tmpMap[compactedKey]; ok {orgks = append(orgks, k)tmpMap[compactedKey] = orgks} else {ks := make([]string, 0, defaultSize)ks = append(ks, k)tmpMap[compactedKey] = ks}}shrinkTo--for (len(tmpMap) > compactNum && shrinkTo >= minKeyLen) || (len(tmpMap) > maxLeftNum && shrinkTo >= minKeyLenLower) {tnMap := make(map[string][]string, defaultSize)for k := range tmpMap {// shrinkif len(k) > shrinkTo {compactedKey := k[0:shrinkTo]if oik, ok := tnMap[compactedKey]; ok {oik = append(oik, tmpMap[k]...)tnMap[compactedKey] = oik} else {ks := make([]string, 0, defaultSize)ks = append(ks, tmpMap[k]...)tnMap[compactedKey] = ks}} else {tnMap[k] = tmpMap[k]}}// 如果此次shrink 沒有使得這個集合的元素數量增加, 就使用原來的keyfor k := range tmpMap {if len(k) > shrinkTo {ck := k[0:shrinkTo]if len(tnMap[ck]) == len(tmpMap[k]) && len(tnMap[ck]) > 1 {x := make([]string, 0, defaultSize)tnMap[k] = append(x, tnMap[ck]...)delete(tnMap, ck)}}}tmpMap = tnMapshrinkTo --}dists := make(map[string]Distribution, defaultSize)for k, v := range tmpMap {if len(v) > 1 {var nd Distributionfor _, dk := range v {d := distMap[dk]nd.KeyPattern = k + "*"nd.KeyCount += d.KeyCountnd.KeySize += d.KeySizend.DataSize += d.DataSizend.ExpireInHour += d.ExpireInHournd.ExpireInWeek += d.ExpireInWeeknd.ExpireInDay += d.ExpireInDaynd.ExpireOutWeek += d.ExpireOutWeeknd.KeyNeverExpire += d.KeyNeverExpire}dists[k] = nd} else {for _, dk := range v {nd := distMap[dk]nd.KeyPattern = dk + "*"dists[dk] = nd}}}stat.Distribution = dists
}

在線key分析的github項目

rma4go
這是一個我已經寫好的項目, 它使用起來非常簡單

構建方法

  1. 構建之前請確保golang sdk 已經安裝, 并且版本 >=1.11.0
  2. 請確保已經具備翻墻的環境, 因為它要下載一些依賴,可能來自墻外

翻墻方法如下

// linux/osx
export http_proxy=somehost:port
export https_proxy=somehost:port
// windows
set http_proxy=somehost:port
set https_proxy=somehost:port
  1. 構建
git clone git@github.com:winjeg/rma4go.git
cd rma4go
go build .

使用方法

用法如下:rma4go -h

rma4go usage:
rma4go -r some_host -p 6379 -a password -d 0
======================================================-H stringaddress of a redis (default "localhost")-a stringpassword/auth of the redis-d intdb of the redis to analyze-h    help content-p intport of the redis (default 6379)-r stringaddress of a redis (default "localhost")

示例輸出

all keys statistics| PATTERN | KEY NUM | KEY SIZE | DATA SIZE | EXPIRE IN HOUR | EXPIRE IN DAY | EXPIRE IN WEEK | EXPIRE OUT WEEK | NEVER EXPIRE |
|---------|---------|----------|-----------|----------------|---------------|----------------|-----------------|--------------|
| total   |       0 |        0 |         0 |              0 |             0 |              0 |               0 |            0 |
string keys statistics| PATTERN | KEY NUM | KEY SIZE | DATA SIZE | EXPIRE IN HOUR | EXPIRE IN DAY | EXPIRE IN WEEK | EXPIRE OUT WEEK | NEVER EXPIRE |
|---------|---------|----------|-----------|----------------|---------------|----------------|-----------------|--------------|
| total   |       0 |        0 |         0 |              0 |             0 |              0 |               0 |            0 |
list keys statistics| PATTERN | KEY NUM | KEY SIZE | DATA SIZE | EXPIRE IN HOUR | EXPIRE IN DAY | EXPIRE IN WEEK | EXPIRE OUT WEEK | NEVER EXPIRE |
|---------|---------|----------|-----------|----------------|---------------|----------------|-----------------|--------------|
| total   |       0 |        0 |         0 |              0 |             0 |              0 |               0 |            0 |
hash keys statistics| PATTERN | KEY NUM | KEY SIZE | DATA SIZE | EXPIRE IN HOUR | EXPIRE IN DAY | EXPIRE IN WEEK | EXPIRE OUT WEEK | NEVER EXPIRE |
|---------|---------|----------|-----------|----------------|---------------|----------------|-----------------|--------------|
| total   |       0 |        0 |         0 |              0 |             0 |              0 |               0 |            0 |
set keys statistics| PATTERN | KEY NUM | KEY SIZE | DATA SIZE | EXPIRE IN HOUR | EXPIRE IN DAY | EXPIRE IN WEEK | EXPIRE OUT WEEK | NEVER EXPIRE |
|---------|---------|----------|-----------|----------------|---------------|----------------|-----------------|--------------|
| total   |       0 |        0 |         0 |              0 |             0 |              0 |               0 |            0 |
zset keys statistics| PATTERN | KEY NUM | KEY SIZE | DATA SIZE | EXPIRE IN HOUR | EXPIRE IN DAY | EXPIRE IN WEEK | EXPIRE OUT WEEK | NEVER EXPIRE |
|---------|---------|----------|-----------|----------------|---------------|----------------|-----------------|--------------|
| total   |       0 |        0 |         0 |              0 |             0 |              0 |               0 |            0 |
other keys statistics| PATTERN | KEY NUM | KEY SIZE | DATA SIZE | EXPIRE IN HOUR | EXPIRE IN DAY | EXPIRE IN WEEK | EXPIRE OUT WEEK | NEVER EXPIRE |
|---------|---------|----------|-----------|----------------|---------------|----------------|-----------------|--------------|
| total   |       0 |        0 |         0 |              0 |             0 |              0 |               0 |            0 |
big keys statistics| PATTERN | KEY NUM | KEY SIZE | DATA SIZE | EXPIRE IN HOUR | EXPIRE IN DAY | EXPIRE IN WEEK | EXPIRE OUT WEEK | NEVER EXPIRE |
|---------|---------|----------|-----------|----------------|---------------|----------------|-----------------|--------------|
| total   |       0 |        0 |         0 |              0 |             0 |              0 |               0 |            0 |

rendered by markdown
total count 4004

all keys statistics

PATTERNKEY NUMKEY SIZEDATA SIZEEXPIRE IN HOUREXPIRE IN DAYEXPIRE IN WEEKEXPIRE OUT WEEKNEVER EXPIRE
TOP_TEN_NEW_XXXXXXXX*120152900001
XXXXXXXXXXXXXX_STATISTICS_MIGRATION_LIST*140769283200001
time-root:*23272299000023
DS_AXXXXXXXX_CORRECT*2454600002
time-2*761752898930000761
time-level:*537846169810000537
time-9*10290113260000102
time-7*153137219890000153
DS_MAGIC_SUCC_2017-06-22*12441500001
tersssss*5124000005
appoint_abcdefg_msgid*121000001
BUSSINESSXXXXXXX_STATISTICS_NEED_CALC_RECENT*144100001
switch_abcd_abcde*369300003
abcdeferCounter_201*378000003
diy1234567flag*114100001
DS_PRXXBCD_LIST*1151720800001
time-4*133119417290000133
datastatistics_switch_version0*130100001
register_count_2_201*592159846400000592
canVisitNewabcdef1234PageLevels*131000001
YOUR_WEEK_VITALITY_INFO*1237578200001
time-8*10189413130000101
EXPERTS_APPOINT_INFO_MAP*124000001
time-3*130121516900000130
time-1*9439456122590000943
time-64*877811131000087
time-5*168151621840000168
total400453422783249000004004

string keys statistics

PATTERNKEY NUMKEY SIZEDATA SIZEEXPIRE IN HOUREXPIRE IN DAYEXPIRE IN WEEKEXPIRE OUT WEEKNEVER EXPIRE
BUSSINESSXXXXXXX_STATISTICS_NEED_CALC_RECENT*144100001
time-5*130117416900000130
datastatistics_switch_version0*130100001
time-7*39348507000039
time-level:*567893973710000567
diy1234567flag*114100001
switch_abcd_abcde*369300003
time-2*598591877740000598
time-6*125111816250000125
time-4*136122517680000136
time-8*72636936000072
time-1*1176118141528800001176
time-9*10088013000000100
time-root:*23272299000023
register_count_2_201*592159846400000592
DS_AXXXXXXXX_CORRECT*1202000001
TOP_TEN_NEW_tersssss*120152900001
time-3*202192526260000202
total3989530424625300003989

list keys statistics

PATTERNKEY NUMKEY SIZEDATA SIZEEXPIRE IN HOUREXPIRE IN DAYEXPIRE IN WEEKEXPIRE OUT WEEKNEVER EXPIRE
XXXXXXXXXXXXXX_STATISTICS_MIGRATION_LIST*140769283200001
DS_MAGIC_SUCC_2017-06-22*12441500001
DS_PRXXBCD_LIST*1151720800001
total379771045500003

hash keys statistics

PATTERNKEY NUMKEY SIZEDATA SIZEEXPIRE IN HOUREXPIRE IN DAYEXPIRE IN WEEKEXPIRE OUT WEEKNEVER EXPIRE
tersssss_action_prepage_new*127000001
YOUR_WEEK_VITALITY_INFO*1237578200001
EXPERTS_APPOINT_INFO_MAP*124000001
abcdeferCounter_2017-06-11*126000001
tersssssHardTaskCounter*123000001
abcdeferCounter_2018-04-27*126000001
abcdeferCounter_2017-09-01*126000001
tersssssEasyTaskCounter*123000001
total81987578200008

set keys statistics

PATTERNKEY NUMKEY SIZEDATA SIZEEXPIRE IN HOUREXPIRE IN DAYEXPIRE IN WEEKEXPIRE OUT WEEKNEVER EXPIRE
tersssss_bind_phone_phone*125000001
appoint_abcdefg_msgid*121000001
canVisitNewabcdef1234PageLevels*131000001
tersssss_bind_phone_userid*126000001
total4103000004

zset keys statistics

PATTERNKEY NUMKEY SIZEDATA SIZEEXPIRE IN HOUREXPIRE IN DAYEXPIRE IN WEEKEXPIRE OUT WEEKNEVER EXPIRE
total00000000

other keys statistics

PATTERNKEY NUMKEY SIZEDATA SIZEEXPIRE IN HOUREXPIRE IN DAYEXPIRE IN WEEKEXPIRE OUT WEEKNEVER EXPIRE
total00000000

big keys statistics

PATTERNKEY NUMKEY SIZEDATA SIZEEXPIRE IN HOUREXPIRE IN DAYEXPIRE IN WEEKEXPIRE OUT WEEKNEVER EXPIRE
XXXXXXXXXXXXXX_STATISTICS_MIGRATION_LIST*140769283200001
total140769283200001

作為依賴使用

獲取方法如下:

go get github.com/winjeg/rma4go

使用方法如下:

func testFunc() {h := "localhost"a := ""p := 6379cli := client.BuildRedisClient(client.ConnInfo{Host: h,Auth: a,Port: p,}, cmder.GetDb())stat := analyzer.ScanAllKeys(cli)// print in command linestat.Print()// the object is ready to use
}

github 維護(主要陣地)

  1. 歡迎其他開發者加入
  2. 歡迎提issue 反饋問題
  3. 歡迎任何有意義的建議
  4. 另外歡迎star,不建議fork,建議直接提交PR ; )

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/388878.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/388878.shtml
英文地址,請注明出處:http://en.pswp.cn/news/388878.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

從Jupyter Notebook到腳本

16 Aug: My second article: From Scripts To Prediction API8月16日&#xff1a;我的第二篇文章&#xff1a; 從腳本到預測API As advanced beginners, we know quite a lot: EDA, ML concepts, model architectures etc…… We can write a big Jupyter Notebook, click “Re…

【EasyNetQ】- 使用Future Publish調度事件

許多業務流程要求在將來某個日期安排事件。例如&#xff0c;在與客戶進行初次銷售聯系后&#xff0c;我們可能希望在將來的某個時間安排跟進電話。EasyNetQ可以通過其Future Publish功能幫助您實現此功能。例如&#xff0c;這里我們使用FuturePublish擴展方法來安排未來一個月的…

Java這些多線程基礎知識你會嗎?

0、并發和并行、進程核線程、多進程和多線程的區別&#xff1a; &#xff08;這里的時間和時刻上的概念同物理上的一樣&#xff09; 并發&#xff1a;在一段時間內多個任務同時執行&#xff0c;或者說是在一段很短的時間內可以執行多條程序指令&#xff0c;微觀上看起來好像是可…

MySQL set names 命令_mysql set names 命令和 mysql 字符編碼問題

先看下面的執行結果&#xff1a;(rootlocalhost)[(none)]mysql>show variables like character%;---------------------------------------------------------------------------------------| Variable_name | Value |---------------------------------------------------…

設置Proxy Server和SQL Server實現數據庫安全

首先&#xff0c;我們需要了解一下SQL Server在WinSock上定義協議的步驟&#xff1a; 1. 在”啟動”菜單上&#xff0c;指向”程序/Microsoft Proxy Server”&#xff0c;然后點擊”Microsoft Management Console”。 2. 展開”Internet Information Service”,再展開運行Proxy…

Python django解決跨域請求的問題

解決方案 1.安裝django-cors-headers pip3 install django-cors-headers 2.配置settings.py文件 INSTALLED_APPS [...corsheaders&#xff0c;...] MIDDLEWARE_CLASSES (...corsheaders.middleware.CorsMiddleware,django.middleware.common.CommonMiddleware, # 注意順序...…

加勒比海兔_加勒比海海洋物種趨勢

加勒比海兔Ok, here’s a million dollar question: is the Caribbean really dying? Or, more specifically, are marine species found on Caribbean reefs becoming less abundant?好吧&#xff0c;這是一個百萬美元的問題&#xff1a;加勒比海真的死了嗎&#xff1f; 或者…

mysql 查出相差年數_MySQL計算兩個日期相差的天數、月數、年數

MySQL自帶的日期函數TIMESTAMPDIFF計算兩個日期相差的秒數、分鐘數、小時數、天數、周數、季度數、月數、年數&#xff0c;當前日期增加或者減少一天、一周等等。SELECT TIMESTAMPDIFF(類型,開始時間,結束時間)相差的秒數&#xff1a;SELECT TIMESTAMPDIFF(SECOND,1993-03-23 0…

tornado 簡易教程

引言 回想Django的部署方式 以Django為代表的python web應用部署時采用wsgi協議與服務器對接&#xff08;被服務器托管&#xff09;&#xff0c;而這類服務器通常都是基于多線程的&#xff0c;也就是說每一個網絡請求服務器都會有一個對應的線程來用web應用&#xff08;如Djang…

如果你的電腦是通過代理上網的.就要用端口映射

由于公網IP地址有限&#xff0c;不少ISP都采用多個內網用戶通過代理和網關路由共用一個公網IP上INTERNET的方法&#xff0c; 這樣就限制了這些用戶在自己計算機上架設個人網站&#xff0c;要實現在這些用戶端架設網站&#xff0c;最關鍵的一點是&#xff0c; 怎樣把多用戶的內網…

人口密度可視化_使用GeoPandas可視化菲律賓的人口密度

人口密度可視化GeoVisualization /菲律賓。 (GeoVisualization /Philippines.) Population density is a crucial concept in urban planning. Theories on how it affects economic growth are divided. Some claim, as Rappaport does, that an economy is a form of “spati…

Unity - Humanoid設置Bip骨骼導入報錯

報錯如下&#xff1a; 解決&#xff1a; 原因是biped骨骼必須按照Unity humanoid的要求設置&#xff0c;在max中設置如下&#xff1a; 轉載于:https://www.cnblogs.com/CloudLiu/p/10746052.html

python3openpyxl無法打開文件_Python3 處理excel文件(openpyxl庫)

openpyxl 介紹openpyxl是一個用于讀/寫 XLSX/XLSM/XLTX/XLTM文件的python庫。openpyxl(可讀寫excel表)專門處理Excel2007及以上版本產生的xlsx文件&#xff1b;2007一下的版本為xls后綴的文件&#xff0c;需要使用 xlrd和xlwt庫進行操作。雖然xlrd和xlwt也可以進行文件讀寫&…

Kubernetes - - k8s - v1.12.3 OpenLDAP統一認證

1&#xff0c;基本概念 為了方便管理和集成jenkins&#xff0c;k8s、harbor、jenkins均使用openLDAP統一認證。2&#xff0c;部署openLDAP 根據之前的文檔&#xff0c;openLDAP使用GFS進行數據持久化。下載對應的openLDAP文件git clone https://github.com/xiaoqshuo/k8s-clust…

給程序加殼

在內存中運行可執行程序&#xff0c;好處是可以給程序加殼&#xff0c;加密源程序&#xff0c;靜態反匯編無法獲得PE輸入節&#xff0c;但是因為運行后仍然是獨立的進程&#xff0c;所以沒辦法防止遠程線程注入&#xff0c;掛接API鉤子。 typedef IMAGE_SECTION_HEADER ( * PIM…

srpg 勝利條件設定_英雄聯盟獲勝條件

srpg 勝利條件設定介紹 (Introduction) The e-sports community has been growing rapidly in the past few years, and what used to be a casual pastime has morphed into an industry projected to generate $1.8 B in revenue by 2022. While there are many video games …

[Egret][文檔]遮罩

——遮罩的作用是指定一個顯示對象的可見區域&#xff0c;即這個顯示對象只在這個區域可見。 一、矩形遮罩 將一個矩形對象賦值給顯示對象的 mask 屬性。 shp.mask new egret.Rectangle(20,20,30,50); 【注】&#xff1a;這個矩形的坐標(20,20)和(30,50)是相對于被遮罩對象shp…

clob類型字段最大存儲長度_請教oracle的CLOB字段的最大長度?

CLOB和BLOB都是4G&#xff0c;而LONG ,LONG raw是舊時代的oracle二進制和長文本表示&#xff0c;將來會被廢棄。最長長度是2G.單位是Byte表中單個 LOB 字段 在 9i 版本中可保存 4GB 數據, 在 10g 版本中可保存多達 128TB 的數據.所以理論上是沒限制的ORACLE的數據類型-- ORAC…

JdbcUtil

轉自&#xff1a;https://github.com/ghyg525/util_java_jdbc JdbcUtil.java import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; …

機器學習 綜合評價_PyCaret:機器學習綜合

機器學習 綜合評價Any Machine Learning project journey starts with loading the dataset and ends (continues ?!) with the finalization of the optimum model or ensemble of models for predictions on unseen data and production deployment.任何機器學習項目的旅程都…