繼國慶節 SmartCode 正式版(SmartCode.Generator)發佈之後,SmartCode 迎來了新的能力 SmartCode.ETL ! SmartCode 正式版從開始發佈就從未說過自己僅僅是個代碼生成器,這點上從我第一次宣佈SmartCode正式開源的文章就可以說明: "《Sm ...
繼國慶節 SmartCode 正式版(SmartCode.Generator)發佈之後,SmartCode 迎來了新的能力 SmartCode.ETL !
SmartCode 正式版從開始發佈就從未說過自己僅僅是個代碼生成器,這點上從我第一次宣佈SmartCode正式開源的文章就可以說明:《SmartCode 不只是代碼生成器》,這不僅僅是一句推廣語!
SmartCode.Generator
相信不少同學都用過各種代碼生成器,這裡我就不做詳細介紹了,如果想體驗 SmartCode.Generator 請至 https://www.cnblogs.com/Ahoo-Wang/p/SmartCode-intro.html 配置好資料庫連接,一鍵生成解決方案。
Why SmartCode.ETL
相信不少已經落地微服務架構方案的同學都會遇到同樣的問題:
- 業務方的查詢需求似乎總是跨微服務DB的
- 領導層需要查看的報表數據總是全局的(需要聚合跨微服務DB的)
So SmartCode.ETL
- 從多個微服務DB 同步業務聚合查詢數據到 all_biz DB (解決:微服務架構一定會遇到的業務方需要跨微服務DB查詢的問題)
- 從 all_biz DB 同步聚合分析數據到 report DB (解決:領導層查看的報表數據聚合問題)
How SmartCode.ETL
安裝 SmartCode from dotnet-cli
dotnet tool install --global SmartCode.CLI
- 使用 SmartCode.Generator 生成 同步Sql表結構腳本,以及 SmartCode.ETL 構建配置
- 執行Sql同步腳本初始化表結構
- 使用任務調度(crontab) + SmartCode.ETL 同步分析數據
通過持久化 etl_task 監控 etl執行情況(目前支持PostgreSql)
簡單來說就是SmartCode生成SmartCode,任務調度執行SmartCode命令行。(這真的不是先有雞還是蛋的問題.....)
SmartCode 插件概覽
{
"SmartCode": {
"Version": "v1.16.15",
"Plugins": [
{
"Type": "SmartCode.IDataSource,SmartCode",
"ImplType": "SmartCode.NoneDataSource,SmartCode"
},
{
"Type": "SmartCode.IBuildTask,SmartCode",
"ImplType": "SmartCode.App.BuildTasks.ClearBuildTask,SmartCode.App"
},
{
"Type": "SmartCode.IBuildTask,SmartCode",
"ImplType": "SmartCode.App.BuildTasks.ProjectBuildTask,SmartCode.App"
},
{
"Type": "SmartCode.IBuildTask,SmartCode",
"ImplType": "SmartCode.App.BuildTasks.MultiTemplateBuildTask,SmartCode.App"
},
{
"Type": "SmartCode.IBuildTask,SmartCode",
"ImplType": "SmartCode.App.BuildTasks.ProcessBuildTask,SmartCode.App"
},
{
"Type": "SmartCode.IOutput,SmartCode",
"ImplType": "SmartCode.App.Outputs.FileOutput,SmartCode.App"
},
{
"Type": "SmartCode.IDataSource,SmartCode",
"ImplType": "SmartCode.Generator.DbTableSource,SmartCode.Generator"
},
{
"Type": "SmartCode.IBuildTask,SmartCode",
"ImplType": "SmartCode.Generator.BuildTasks.TableBuildTask,SmartCode.Generator"
},
{
"Type": "SmartCode.IBuildTask,SmartCode",
"ImplType": "SmartCode.Generator.BuildTasks.SingleBuildTask,SmartCode.Generator"
},
{
"Type": "SmartCode.INamingConverter,SmartCode",
"ImplType": "SmartCode.Generator.TableNamingConverter,SmartCode.Generator"
},
{
"Type": "SmartCode.TemplateEngine.ITemplateEngine,SmartCode.TemplateEngine",
"ImplType": "SmartCode.TemplateEngine.Impl.HandlebarsTemplateEngine,SmartCode.TemplateEngine"
},
{
"Type": "SmartCode.TemplateEngine.ITemplateEngine,SmartCode.TemplateEngine",
"ImplType": "SmartCode.TemplateEngine.Impl.OfficialRazorTemplateEngine,SmartCode.TemplateEngine"
},
{
"Type": "SmartCode.Generator.IDbTypeConverter,SmartCode.Generator",
"ImplType": "SmartCode.Generator.DbTypeConverter.DefaultDbTypeConverter,SmartCode.Generator"
},
{
"Type": "SmartCode.IDataSource,SmartCode",
"ImplType": "SmartCode.ETL.ExtractDataSource,SmartCode.ETL"
},
{
"Type": "SmartCode.IBuildTask,SmartCode",
"ImplType": "SmartCode.ETL.BuildTasks.TransformBuildTask,SmartCode.ETL"
},
{
"Type": "SmartCode.ETL.ITransformEngine,SmartCode.ETL",
"ImplType": "SmartCode.ETL.TransformEngine.RazorTransformEngine,SmartCode.ETL"
},
{
"Type": "SmartCode.IBuildTask,SmartCode",
"ImplType": "SmartCode.ETL.BuildTasks.LoadBuildTask,SmartCode.ETL"
},
{
"Type": "SmartCode.ETL.IETLRepository,SmartCode.ETL",
"ImplType": "SmartCode.ETL.NoneETLRepository,SmartCode.ETL"
},
{
"Type": "SmartCode.ETL.IETLRepository,SmartCode.ETL",
"ImplType": "SmartCode.ETL.PostgreSql.PGETLRepository,SmartCode.ETL.PostgreSql",
"Paramters": {
"ConnectionString": "Server=localhost;Port=5432;User Id=postgres;Password=SmartSql; Database=smartcode_etl;"
}
}
]
}
}
ETL 構建配置
Author: Ahoo Wang
DataSource:
Name: Extract
Paramters:
DbProvider: SqlServer
ConnectionString: Data Source=.;Initial Catalog=SmartSqlDB;Integrated Security=True
Query: SELECT [Id],[UserName],[Status],[LastLoginTime],[CreationTime],[ModifyTime],[Deleted] FROM [T_User] With(NoLock) Where ModifyTime>@LastMaxModifyTime
PKColumn: Id
AutoIncrement: true
ModifyTime: ModifyTime
Paramters:
ETLCode: SmartCode.ETL.Test
ETLRepository: PG
Build:
Transform:
Type: Transform
Paramters:
Script:
Load2PostgreSql:
Type: Load
Paramters:
DbProvider: PostgreSql
ConnectionString: Server=localhost;Port=5432;User Id=postgres;Password=SmartSql; Database=smartsql_db;
Table: t_user__temp
PreCommand: CREATE TABLE t_user__temp( LIKE t_user );
PostCommand: "Delete From t_user as source Where EXISTS(select * from t_user__temp temp where temp.id=source.id);
Insert Into t_user SELECT * From t_user__temp;
Drop Table t_user__temp;
"
ColumnMapping: [{Column: Id,Mapping: id}
,{Column: UserName,Mapping: user_name}
,{Column: Status,Mapping: status}
,{Column: LastLoginTime,Mapping: last_login_time}
,{Column: CreationTime,Mapping: creation_time}
,{Column: ModifyTime,Mapping: modify_time}
,{Column: Deleted,Mapping: deleted}]
根 Paramters
參數名 | 說明 |
---|---|
ETLCode | ETL任務Code,區分任務類型,唯一 |
ETLRepository | ETL任務持久化倉儲,None/PG |
DataSource 參數說明
屬性 Name:Extract,使用 ExtractDataSource 插件作為數據源
ExtractDataSource.Paramters
參數名 | 說明 |
---|---|
DbProvider | 數據驅動提供者:MySql,MariaDB,PostgreSql,SqlServer,Oracle,SQLite |
ConnectionString | 連接字元串 |
Query | 查詢命令,需要抽取的數據。預設會自動註入三個參數 LastMaxId,LastMaxModifyTime,LastQueryTime 作為查詢條件 |
PKColumn | 主鍵列名 |
AutoIncrement | 是否為自增主鍵,true 自動計算抽取的最大主鍵值(MaxId) |
ModifyTime | 最近一次修改時間列名,設置後自定計算抽取的最大修改時間列(MaxModifyTime) |
Build.Load 參數說明
屬性 Type:Load,使用 LoadBuildTask 插件作為構建任務
Build.Load.Paramters
參數名 | 說明 |
---|---|
DbProvider | 數據驅動提供者:MySql,MariaDB,PostgreSql,SqlServer,Oracle,SQLite |
ConnectionString | 連接字元串 |
Table | 目標表名 |
PreCommand | 執行批量插入任務之前執行的命令 |
PostCommand | 執行批量插入任務之後執行的命令 |
ColumnMapping | 列映射 |
同步策略
LastMaxId
LastMaxId 即上一次抽取的數據最大Id值(第一次抽取時LastMaxId為-1),該模式使用於數據插入後不再變更的數據表。
LastMaxModifyTime
LastMaxModifyTime 即上一次抽取的數據最大ModifyTime值(第一次抽取時LastMaxModifyTime為1970-01-01 08:00:00),適用於插入數據後還會變更的數據表。
併發任務同步
- 對 Id 取模,分拆不同任務,同時併發執行
大數據量同步
- 使用 Top/Limit 限制數據抽取數量,分多次同步執行完成整個數據同步。
ETL_Task 任務監控
性能監控
運行環境
- 源抽取庫:Windows Server 2012 , 8 vCPU 16 GB + SSD + SqlServer-2014
- 目標分析庫:CentOS-7 , 8 vCPU 16 GB + SSD + PostgreSql-11 + SmartCode
ETL_Task.Extract
以下是數據抽取性能,抽取數量為 1434678,耗時 41267 毫秒。
{
"MaxId": 1755822,
"PKColumn": "Id",
"QuerySize": 1434678,
"QueryTime": "2018-11-01T11:31:53.6191084+08:00",
"QueryCommand": {
"Taken": 41267,
"Command": "Select * From T_ProductSearchLog With(NoLock) Where Id>@LastMaxId",
"Paramters": {
"LastMaxId": -1,
"LastQueryTime": "1970-01-01T08:00:00"
}
}
}
ETL_Task.Load
以下是數據載入性能,批量插入數據量為 1434678,耗時 21817 毫秒,平均每秒插入 65759.6 條數據。
{
"Size": 1434678,
"Table": "t_product_search_log",
"Taken": 21817,
"PreCommand": null,
"PostCommand": null
}
目前 SmartCode.ETL 已經落地到我們的生產環境了(11-01上線截至目前執行了 26069 次同步任務,暫無error日誌拋出)
PS: 雖然 SmartCode.ETL 只花了周末倆天時間完成擴展,但已經可以滿足我們至少90%的應用場景。這足以見得 SmartCode 擴展能力是多麼令人意外了。當然SmartCode的其他能力還得後續等各位一起發掘!!!