ClickHouse?是 Yandex 公司于2016年開源的 OLAP 列式數據庫管理系統,主要用于 WEB 流量分析。憑借面向列式存儲、支持數據壓縮、完備的 DBMS 功能、多核心并行處理的特點,ClickHouse 被廣泛應用于廣告流量、移動分析、網站分析等領域。
DolphinDB?是一款國產高性能分布式時序數據庫,擁有圖靈完備性的編程語言 DolphinDB Script 和高性能低延時的流計算框架,為海量結構化數據的快速存儲、檢索、分析及計算提供一站式解決方案,適用于量化金融及工業物聯網等領域。自發布以來,DolphinDB 憑借卓越的性能、低維護成本、操作簡單、可擴展性高等優勢,吸引了大量的國內外用戶。
本教程旨在為 ClickHouse 使用者提供一份遷移數據至 DolphinDB 的簡明參考。
1. DolphinDB vs ClickHouse
1.1 DolphinDB 與 ClickHouse 的相同點
- 分布式存儲和分析:DolphinDB 和 ClickHouse 都設計為支持大規模數據的分布式存儲和分析。它們可以處理海量數據,并提供快速的查詢和分析能力。
- 列式存儲:兩者都采用了列式存儲結構,更適合海量大數據場景中的寫入和讀取。這種存儲方式在分析型數據庫中通常能夠提供更高的性能,特別是對于聚合和分析查詢。
- 支持分布式計算:兩者都支持分布式計算,可以橫向擴展以處理大規模數據集。
- 支持復雜的數據類型:兩者都支持處理復雜的數據類型,包括數組、嵌套結構等,使其適用于各種數據分析場景。
1.2 DolphiDB 與 ClickHouse 的區別
- 分布式能力:DolphinDB 分布式更強,支持事務和冪等性導數,查詢自動路由,全面元數據管理。
- 腳本語言:兩者都支持 SQL 查詢,ClickHouse 僅支持 SQL 語言,而 DolphinDB 開發了圖靈完備的腳本語言,具備更強的數據處理能力。
- 存儲引擎:DolphinDB 自研的 TSDB 存儲引擎將分區內的多列數據 (以 blocks 為存儲形式,block 是 DolphinDB 中最小的存儲單位) 順序存為一個文件,解決了數據分析中寬表查詢和點查詢性能上的痛點。
- 壓縮算法:DolphinDB 當前僅支持 LZ4、Delta 和枚舉類型的壓縮,而 ClickHouse 不僅支持 LZ4、ZSTD等通用壓縮算法,還針對不同的數據類型開發了不同的編碼方法,如 Delta、Gorilla、T64 等。
- 生態支持:ClickHouse 是一個開源項目,擁有活躍的開源社區,與各種第三方工具能很好的兼容整合,生態支持完善。而 DolphinDB 是企業級方案,在金融行業和物聯網領域有更多的實際業務積累,有專業的技術支持團隊,可以及時響應、解決客戶在使用 DolphinDB 中遇到的各類問題。
1.3 為什么選擇 DolphinDB?
- 運維成本:ClickHouse 在設計之初沒有考慮集群版本,所以現在方案都是改良版。ClickHouse 的 shard 及replica 配置、擴縮容異常繁瑣,運維成本高。相比而言,DolphinDB 設計并引入了 DFS 這一抽象文件系統,使得 shard,replica,負載均衡,Failover 均交由 DFS 來實現,用戶無需關心,基本沒有運維成本。
- 數據一致性:ClickHouse 副本一致性通過 ZooKeeper 同步分布式日志(Replicated Log)來實現最終一致性,即同步期間副本的數據是不一致的。而 DolphinDB 通過兩階段提交協議來保證副本一致性,副本之間是強一致性。
- 開發成本:DolphinDB 提供了豐富的計算函數支持,并內置了流數據處理框架,僅需投入少量研發資源即可實現復雜業務場景。
2. 應用需求
對于有將數據由 ClickHouse 遷移到 DolphinDB 需求的客戶而言,其常規遷移方案通常基于 CSV 文件的導入導出實現。具體步驟是先將數據從 ClickHouse 中以 CSV 格式導出,再使用 DolphinDB 導入 CSV 文件,從而實現數據的遷移需求。但是這一方案有以下幾點不足之處:
- 數據量較大時,需要較大的磁盤空間存儲 CSV 文件
- 實現增量同步困難
- 數據遷移效率低
DolphinDB 提供了多種靈活的數據同步方法,來幫助用戶方便地把海量數據從多個數據源進行全量同步或增量同步。本文的實踐案例基于這一需求,根據 2021.01.04 一天的逐筆成交數據,數據量約 2721 萬,提供將數據從 ClickHouse 遷移到 DolphinDB 的高性能解決方案。
3. 實現方法
由 ClickHouse 遷移到 DolphinDB 的方案主要有:ODBC 插件、DataX、CSV 文件導入、HTTP Client + zmq 插件等。本文選擇使用 ODBC 插件、DataX 進行數據遷移,主要基于以下幾點原因:
- 二者實現簡單、數據流轉鏈路短,遷移效率更高
- 無需額外空間存儲中間文件
- 增量同步方案實現簡單
本文數據遷移的具體實現框架如下:
- ODBC 插件
ODBC(Open Database Connectivity) 插件是 DolphinDB 提供的通過 ODBC 接口訪問 Oracle 的開源產品。使用插件配合 DolphinDB 腳本使用,與服務器在同一個進程空間內運行,能高效地完成 Oracle 數據到 DolphinDB 的數據寫入。
ODBC 提供如下函數,函數的具體使用請參考?ODBC 插件。
odbc::connect(connStr, [dataBaseType])
odbc::close(conn)
odbc::query(connHandle or connStr, querySql, [t], [batchSize], [tranform])
odbc::execute(connHandle or connStr, SQLstatements)
odbc::append(connHandle, tableData, tablename, [createTableIfNotExist], [insertIgnore])
- DataX 驅動
DataX 是可擴展的數據同步框架,將不同數據源的同步抽象為從源頭數據源讀取數據的 Reader 插件,以及向目標端寫入數據的 Writer 插件,理論上 DataX 框架可以支持任意數據源類型的數據同步工作。
DolphinDB 提供基于 DataXReader 和 DataXWriter 的開源驅動。DolphinDBWriter 插件實現了向 DolphinDB 寫入數據,使用 DataX 的現有 reader 插件結合 DolphinDBWriter 插件,即可實現從不同數據源向 DolphinDB 同步數據。用戶可以在 Java 項目中包含 DataX 的驅動包,開發從 ClickHouse 數據源到 DolphinDB 的數據遷移軟件。
4. 遷移案例與操作步驟
4.1 環境配置
本次案例中使用了以下數據庫及插件,各版本型號如下:
ClickHouse 版本:23.8.2.7
unixODBC?版本:2.3.7
DolphinDB Server?版本:2.00.10.1
DolphinDB GUI?版本:1.30.21.4
2.00.10.1 版本 Server 自帶 ODBC 插件,位于 Server 的?<HomeDir>/plugins?目錄,可直接加載使用。如果?<HomeDir>/plugins?目錄下不存在 ODBC 文件夾,則通過如下鏈接下載:
DolphinDBPlugin?分支:release200.10
請注意,DolphinDB ODBC 插件版本號必須與 Server 版本號一致,否則可能出現報錯。例如,DolphinDB Server 版本號為 2.00.10.X,則必須使用 release200.10 分支的 ODBC 插件。
如果想自行編譯,請參考:?ODBC 插件?文章中的第2章。
4.2 建庫建表
針對上面的測試數據,我們需要在 DolphinDB 里創建對應的庫表,用于存儲遷移過來的數據。對于實際的數據,需要綜合考慮被遷移數據的字段、類型、數據量,在 DolphinDB 是否需要分區,分區方案,使用 OLAP還是 TSDB 引擎等情況,去設計建庫建表方案。一些數據存儲庫表設計實踐,可以參考?DolphinDB 數據庫分區教程
本例建表文件 createTable.dos 內容如下:
create database "dfs://TSDB_tick" partitioned by VALUE([2023.02.01,2023.02.02]),HASH([SYMBOL,10]),engine=`TSDB
create table 'dfs://TSDB_tick'.'tick'(SecurityID SYMBOL,TradeTime TIMESTAMP [compress='delta'],TradePrice DOUBLE,TradeQty INT,TradeAmount DOUBLE,BuyNo INT,SellNo INT,ChannelNo INT,TradeIndex INT,TradeBSFlag SYMBOL,BizIndex INT
)
partitioned by TradeTime,SecurityID,
sortColumns=`SecurityID`TradeTime
從 ClickHouse 遷移到 DolphinDB 的數據字段映射關系如下表:
ClickHouse 字段含義 | ClickHouse 字段 | ClickHouse 數據類型 | DolphinDB 字段含義 | DolphinDB 字段 | DolphinDB 數據類型 |
---|---|---|---|---|---|
證券代碼 | SecurityID | String | 證券代碼 | SecurityID | SYMBOL |
交易時間 | TradeTime | DateTime64 | 交易時間 | TradeTime | TIMESTAMP |
交易價格 | TradePrice | DOUBLE | 交易價格 | TradePrice | DOUBLE |
交易數量 | TradeQty | Int32 | 交易數量 | TradeQty | INT |
交易金額 | TradeAmount | DOUBLE | 交易金額 | TradeAmount | DOUBLE |
買方委托索引 | BuyNo | Int32 | 買方委托索引 | BuyNo | INT |
賣方委托索引 | SellNo | Int32 | 賣方委托索引 | SellNo | INT |
成交編號 | TradeIndex | Int32 | 成交編號 | TradeIndex | INT |
頻道代碼 | ChannelNo | Int32 | 頻道代碼 | ChannelNo | INT |
成交方向 | TradeBSFlag | String | 成交方向 | TradeBSFlag | SYMBOL |
業務序列號 | BizIndex | Int64 | 業務序列號 | BizIndex | INT |
其部分數據示例如下:
SecurityID | TradeTime | TradePrice | TradeQty | TradeAmount | BuyNo | SellNo | TradeIndex | ChannelNo | TradeBSFlag | BizIndex |
---|---|---|---|---|---|---|---|---|---|---|
600020 | 2021.01.04T09:25:00.630 | 3.39 | 2100 | 7,119. | 85961 | 78316 | 19719 | 1 | N | 123713 |
600020 | 2021.01.04T09:25:00.630 | 3.39 | 1000 | 3,390. | 129945 | 78316 | 19720 | 1 | N | 123714 |
600020 | 2021.01.04T09:25:00.630 | 3.39 | 900 | 3,051. | 158039 | 78316 | 19721 | 1 | N | 123715 |
4.3 通過 ODBC 插件遷移
本例中部署 DolphinDB 的服務器操作系統為 Centos。
4.3.1 安裝 unixODBC 庫
Centos 系統:
# 安裝 unixODBC 庫
yum install unixODBC unixODBC-devel
如果是 Ubuntu 系統,使用以下命令安裝:
# 安裝 unixODBC 庫
apt-get install unixodbc unixodbc-dev
4.3.2 下載 ClickHouse 的 ODBC 驅動并安裝
第一步,下載?clickhouse-odbc?并解壓至自定義目錄中,假設安裝目錄為 <savedir>。
mkdir <savedir>
cd <savedir>
wget https://github.com/ClickHouse/clickhouse-odbc/releases/download/v1.2.1.20220905/clickhouse-odbc-linux.zip
unzip clickhouse-odbc-linux.zip
第二步,在?/etc/odbcinst.ini?文件中,添加以下內容:
注意:需要替換 <savedir> 為實際的安裝目錄。
[ODBC Drivers]
ClickHouse ODBC Driver (ANSI) = Installed
ClickHouse ODBC Driver (Unicode) = Installed [ClickHouse ODBC Driver (ANSI)]
Description = ODBC Driver (ANSI) for ClickHouse
Driver = <savedir>/clickhouse-odbc-1.2.1-Linux/lib64/libclickhouseodbc.so
Setup = <savedir>/clickhouse-odbc-1.2.1-Linux/lib64/libclickhouseodbc.so
UsageCount = 1 [ClickHouse ODBC Driver (Unicode)]
Description = ODBC Driver (Unicode) for ClickHouse
Driver =<savedir>/clickhouse-odbc-1.2.1-Linux/lib64/libclickhouseodbcw.so
Setup =<savedir>/clickhouse-odbc-1.2.1-Linux/lib64/libclickhouseodbcw.so
UsageCount = 1
第三步,在?/etc/odbc.ini?文件中,添加以下內容:
注意:若不存在該文件可自行創建。
[ODBC Data Sources]
ClickHouse DSN (ANSI)=ClickHouse ODBC Driver (ANSI)
ClickHouse DSN (Unicode)=ClickHouse ODBC Driver (Unicode) [ClickHouseAnsi]
Driver=ClickHouse ODBC Driver (ANSI)
Description=DSN (localhost) for ClickHouse ODBC Driver (ANSI)
Server = localhost
Database = default
UID = default
PWD = 123456
Port = 8123
Proto = http[ClickHouseUni]
Driver=ClickHouse ODBC Driver (Unicode)
Description=DSN (localhost) for ClickHouse ODBC Driver (Unicode)
Server = localhost
Database = default
UID = default
PWD = 123456
Port = 8123
Proto = http
4.3.3 同步數據
- 運行以下命令加載 ODBC 插件(?
ServerPath
?請自行修改)
loadPlugin("ServerPath/plugins/odbc/PluginODBC.txt")
2. 運行以下命令建立與 ClickHouse 的連接( Dsn 的名稱請自行修改)
conn = odbc::connect("Dsn=ClickHouseAnsi", `ClickHouse)
3. 運行以下命令開始同步數據
def syncData(conn, dbName, tbName, dt){sql = "select SecurityID, TradeTime, TradePrice, TradeQty, TradeAmount, BuyNo, SellNo, ChannelNo, TradeIndex, TradeBSFlag, BizIndex from migrate.ticksh"if(!isNull(dt)) {sql = sql + " WHERE toDate(TradeTime) = '"+temporalFormat(dt,'yyyy-MM-dd')+"'"}odbc::query(conn,sql, loadTable(dbName,tbName), 100000)
}
dbName="dfs://TSDB_tick"
tbName="tick"
syncData(conn, dbName, tbName, NULL)
數據共 27211975 條,同步數據耗時約158秒。
4. 同步增量數據
def scheduleLoad(conn,dbName,tbName){sqlQuery = "select SecurityID, TradeTime, TradePrice, TradeQty, TradeAmount, BuyNo, SellNo, ChannelNo, TradeIndex, TradeBSFlag, BizIndex from migrate.ticksh"sql = sqlQuery + " WHERE toDate(TradeTime) = '"+temporalFormat(today()-1,'yyyy-MM-dd')+"'"odbc::query(conn,sql, loadTable(dbName,tbName), 100000)
}
scheduleJob(jobId=`test, jobDesc="test",jobFunc=scheduleLoad{conn,dbName,tbName},scheduleTime=00:05m,startDate=2023.11.03, endDate=2024.11.03, frequency='D')
4.4 通過 DataX 遷移
4.4.1 部署DataX
從?DataX 下載地址?下載 DataX 壓縮包后,解壓至自定義目錄。
注意:2023年9月后發布的 datax 中才有 clickhousereader 插件, 如已安裝老版本 datax,則只需下載安裝包中的 clickhousereader 復制到?DataX/plugin/reader?目錄下,即可使用。
4.4.2 部署 DataX-DolphinDBWriter 插件
將?DataX-DolphinDBWriter?中源碼的?./dist/dolphindbwriter?目錄下所有內容拷貝到?DataX/plugin/writer?目錄下,即可使用。
4.4.3 執行 DataX 任務
- 配置 json 文件
配置文件?ClickHouseToDDB.json?的具體內容如下,并將 json 文件置于自定義目錄下,本教程中方放置于?datax-writer-master/ddb_script/?目錄下。
{"job": {"content": [{"writer": {"parameter": {"dbPath": "dfs://TSDB_tick","userId": "admin","tableName": "tick","host": "127.0.0.1","pwd": "123456","table": [{"type": "DT_SYMBOL","name": "SecurityID"},{"type": "DT_TIMESTAMP","name": "TradeTime"},{"type": "DT_DOUBLE","name": "TradePrice"},{"type": "DT_INT","name": "TradeQty"},{"type": "DT_DOUBLE","name": "TradeAmount"},{"type": "DT_INT","name": "BuyNo"},{"type": "DT_INT","name": "SellNo"},{"type": "DT_INT","name": "TradeIndex"},{"type": "DT_INT","name": "ChannelNo"},{"type": "DT_SYMBOL","name": "TradeBSFlag"},{"type": "DT_INT","name": "BizIndex"}],"port": 10001},"name": "dolphindbwriter"},"reader": {"parameter": {"username": "default","column": ["SecurityID", "toString(TradeTime)", "TradePrice", "TradeQty", "TradeAmount", "BuyNo", "SellNo", "ChannelNo", "TradeIndex", "TradeBSFlag", "BizIndex"],"connection": [{"table": ["ticksh"],"jdbcUrl": ["jdbc:clickhouse://127.0.0.1:8123/migrate"]}],"password": "123456","where": ""},"name": "clickhousereader"}}],"setting": {"speed": {"channel": 1}}}
}
注:當前 clickhousereader 無法識別 DateTime64 類型,故需轉為字符串("toString(TradeTime)"
)取數。
2. Linux 終端中執行以下命令以執行 DataX 任務
python datax.py ../../datax-writer-master/ddb_script/ClickHouseToDDB.json
3. 查看 DataX 同步結果
任務啟動時刻 : 2023-11-03 17:11:26
任務結束時刻 : 2023-11-03 17:14:57
任務總計耗時 : 210s
任務平均流量 : 8.93MB/s
記錄寫入速度 : 129580rec/s
讀出記錄總數 : 27211975
讀寫失敗總數 : 0
4. 同步增量數據
使用 DataX 同步增量數據,可在?ClickHouseToDDB.json
?的 ”reader“ 中增加 "where" 條件對數據日期進行篩選,如此每次執行同步任務時至同步 where 條件過濾后的數據,以同步前一天的數據為例,示例如下:
"reader": {"parameter": {"username": "default","column": ["SecurityID", "toString(TradeTime)", "TradePrice", "TradeQty", "TradeAmount", "BuyNo", "SellNo", "ChannelNo", "TradeIndex", "TradeBSFlag", "BizIndex"],"connection": [{"table": ["ticksh"],"jdbcUrl": ["jdbc:clickhouse://127.0.0.1:8123/migrate"]}],"password": "123456","where": "toDate(TradeTime) = date_sub(day,1,today())"},"name": "clickhousereader",
}
5. 基準性能
分別使用 ODBC 插件和 DataX 驅動進行數據遷移, 數據量 2721 萬條,遷移耗時對比如下表所示:
ODBC插件 | DataX |
---|---|
158s | 210s |
綜上,ODBC 插件與 DataX 均能實現將 Oracle 中數據遷移到 DolphinDB 中,但是各有優缺點:
- ODBC 使用簡單,適合靈活導入數據,但是運維管理不便。
- DataX 需要編寫復雜的導入配置,但是其擴展靈活,方便監控,社區支持豐富。
用戶可以根據需要自行選擇合適的導入方式。
附錄
DataX DolphinDB-Writer 配置項
配置項 | 是否必須 | 數據類型 | 默認值 | 描述 |
---|---|---|---|---|
host | 是 | string | 無 | Server Host |
port | 是 | int | 無 | Server Port |
userId | 是 | string | 無 | DolphinDB 用戶名導入分布式庫時,必須要有權限的用戶才能操作,否則會返回 |
pwd | 是 | string | 無 | DolphinDB 用戶密碼 |
dbPath | 是 | string | 無 | 需要寫入的目標分布式庫名稱,比如"dfs://MYDB"。 |
tableName | 是 | string | 無 | 目標數據表名稱 |
batchSize | 否 | int | 10000000 | datax每次寫入dolphindb的批次記錄數 |
table | 是 | 寫入表的字段集合,具體參考后續table項配置詳解 | ||
saveFunctionName | 否 | string | 無 | 自定義數據處理函數。若未指定此配置,插件在接收到reader的數據后,會將數據提交到DolphinDB并通過tableInsert函數寫入指定庫表;如果定義此參數,則會用指定函數替換tableInsert函數。 |
saveFunctionDef | 否 | string | 無 | 數據入庫自定義函數。此函數指 用dolphindb 腳本來實現的數據入庫過程。 此函數必須接受三個參數:dfsPath(分布式庫路徑), tbName(數據表名), data(從datax導入的數據,table格式) |
table 配置詳解
table 用于配置寫入表的字段集合。內部結構為
{"name": "columnName", "type": "DT_STRING", "isKeyField":true}
請注意此處列定義的順序,需要與原表提取的列順序完全一致。
- name :字段名稱。
- isKeyField:是否唯一鍵值,可以允許組合唯一鍵。本屬性用于數據更新場景,用于確認更新數據的主鍵,若無更新數據的場景,無需設置。
- type 枚舉值以及對應 DolphinDB 數據類型如下
DolphinDB 類型 | 配置值 |
---|---|
DOUBLE | DT_DOUBLE |
FLOAT | DT_FLOAT |
BOOL | DT_BOOL |
DATE | DT_DATE |
MONTH | DT_MONTH |
DATETIME | DT_DATETIME |
TIME | DT_TIME |
SECOND | DT_SECOND |
TIMESTAMP | DT_TIMESTAMP |
NANOTIME | DT_NANOTIME |
NANOTIMETAMP | DT_NANOTIMETAMP |
INT | DT_INT |
LONG | DT_LONG |
UUID | DT_UUID |
SHORT | DT_SHORT |
STRING | DT_STRING |
SYMBOL | DT_SYMBOL |
完整代碼及測試數據
ClickHouseToDDB.zip?附件中包含以下腳本及測試數據:
- DataX:?ClickHouseToDDB.json
- DolphinDB:?createTable.dos、ClickHouseToDDB_ODBC.dos
-
模擬數據:gendata.dos