問題描述:https://my.oschina.net/xiaominmin/blog/10111950
OriginalConfPretreatmentUtil - 您的配置有誤. 由於您讀取數據庫表採用了querySql的方式, 所以您不需要再配置 splitPk. 如果您不想看到這條提醒,請移除您源頭表中配置中的 splitPk. datax爲什麼使用了querySql就不需要配置splitPk?
在 DataX 中,當您使用 querySql 的方式讀取數據庫表時,並不需要配置 splitPk 參數。這是因爲 splitPk 是用於基於主鍵的分片導入/導出數據的一種方式。
通常情況下,DataX 中的數據庫讀寫任務會通過設置 splitPk 參數來將源表的數據進行水平切分,以提高讀寫的效率。默認情況下,DataX 會基於源表的主鍵字段進行數據分片,並將數據分片均勻地分發給不同的讀寫任務。
然而,當您使用 querySql 的方式讀取數據庫表時,由於 querySql 已經定義了具體的查詢語句,可能涉及多個表或複雜的邏輯,因此僅通過主鍵字段進行分片可能無法滿足實際需求。因此,在這種情況下,DataX 不再需要配置 splitPk 參數,而是直接使用 querySql 中指定的查詢語句來獲取數據。
通過使用 querySql 方式,您可以根據具體的查詢需求,編寫更加靈活和複雜的 SQL 查詢語句,使得 DataX 可以更好地滿足您的數據讀取需求。
那麼querySql 方式還能夠併發讀寫嗎
在 DataX 中,querySql 方式可以實現併發讀取數據,但並不支持併發寫入。
當您使用 querySql 方式讀取數據時,DataX 會將查詢語句發送給數據庫,並行執行查詢操作。通過適當地配置任務的併發數,可以實現多個讀取任務同時從數據庫中讀取數據。這樣可以提高數據讀取的效率,尤其是在大型數據集的情況下。
然而,對於寫入操作,querySql 並不支持併發寫入。因爲寫入操作通常需要保證數據的一致性和完整性,同時還需要考慮事務處理等問題。如果多個寫入任務同時操作同一個目標表,可能會導致數據衝突、重複或其他異常情況。爲了避免這種問題,DataX 不支持併發寫入操作。
如果您需要在 DataX 中進行併發寫入操作,可以考慮使用其他方式,如分片導出或者使用其他工具或框架來實現併發寫入。
總結:使用querySql 能併發讀,單線程寫。splitPk可以支持併發讀寫。最好單線程寫可以避免主鍵重複問題。
案例:
一:splitPk可以支持併發讀寫
{
"job": {
"setting": {
"speed": {
"channel": 5,
"byte": 1048576
},
"errorLimit": {
"records": 1,
"percentage": 0
}
},
"content": [
{
"reader": {
"name": "mysqlreader",
"parameter": {
"username": "uname",
"password": "adf",
"dateFormat": "YYYY-MM-dd hh:mm:ss",
"column": [
"id",
"user_id",
"flag",
"remark",
"create_time",
"modify_time"
],
"connection": [
{
"table": ["db_user.as_personalized_status_info"],
"jdbcUrl": [
"jdbc:mysql://ip:3306/db_user?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai"
]
}
],
"maxRetries": 3,
"splitPk": "id"
}
},
"writer": {
"name": "sqlserverwriter",
"parameter": {
"username": "uname",
"password": "asdaf",
"dateFormat": "YYYY-MM-dd hh:mm:ss",
"column": [
"id",
"user_id",
"flag",
"remark"
"create_time",
"modify_time"
],
"preSql": [
"truncate table CRMDB_Read.dbo.as_personalized_status_info"
],
"connection": [
{
"jdbcUrl": "jdbc:sqlserver://ip:1433;DatabaseName=Read",
"table": [
"CRMDB_Read.dbo.as_personalized_status_info"
]
}
]
}
}
}
]
}
}
二:querySql 支持併發讀單線程寫。
{
"job": {
"setting": {
"speed": {
"channel": 5,
"byte": 1048576
},
"errorLimit": {
"records": 1,
"percentage": 0
}
},
"content": [
{
"reader": {
"name": "mysqlreader",
"parameter": {
"username": "uname",
"password": "gadsfr!",
"dateFormat": "YYYY-MM-dd hh:mm:ss",
"connection": [
{
"querySql": [
"
SELECT id, user_id, flag, remark, create_time, modify_time
FROM db_user.as_personalized_status_info
where id <=
(SELECT max(id) from db_user.as_personalized_status_info )
"
],
"jdbcUrl": [
"jdbc:mysql://ip:3306/db_user?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai"
]
}
],
"maxRetries": 3,
"splitPk": "id"
}
},
"writer": {
"name": "sqlserverwriter",
"parameter": {
"username": "uname",
"password": "asdfa",
"dateFormat": "YYYY-MM-dd hh:mm:ss",
"column": [
"id",
"user_id",
"flag",
"remark",
"create_time",
"modify_time"
],
"preSql": [
"truncate table PosData.dbo.as_personalized_status_info"
],
"connection": [
{
"jdbcUrl": "jdbc:sqlserver://ip:1433;DatabaseName=PosData",
"table": [
"PosData.dbo.as_personalized_status_info"
]
}
]
}
}
}
]
}
}
spark 的讀寫:也是併發寫,可能會有問題
%spark_delivery_report.pyspark
import os
import sys
import logging
import time
from pyspark.sql import SparkSession
from pyspark import SparkConf
from pyspark.sql import functions as F
reload(sys)
sys.setdefaultencoding('utf-8')
# 配置日誌記錄器
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
conf = SparkConf().setAppName('dataSyn.CRM').set("spark.yarn.queue", "Q1")
spark = SparkSession.builder.config(conf=conf).enableHiveSupport().config("spark.sql.parquet.writeLegacyFormat", "true").getOrCreate()
properties = {"driver": "com.mysql.jdbc.Driver",
"socket_timeout": "300000",
"rewriteBatchedStatements": "true",
"batchsize": "1000000",
"numPartitions": "8",
'user': 'uname',
'password': 'asdf'}
dburl = """jdbc:mysql://ip:3306/db_user?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai"""
#--------------------user.db_user.as_personalized_status_info--------------------------------------------------
dbtable1 = """(SELECT id, user_id, flag, remark, create_time, modify_time
FROM db_user.as_personalized_status_info ) tmp"""
start_time = time.time()
df = spark.read.jdbc(url=dburl,table=dbtable1, properties=properties)
df.write.format("jdbc").option("url", """jdbc:sqlserver://ip:1433;DatabaseName=PosData""").option("dbtable","PosData.dbo.as_personalized_status_info").option("user", """uname""").option("password", """adsf""").option("truncate","true").mode("overwrite").save()
# 結束計時
end_time = time.time()
execution_time = end_time - start_time
# 記錄日誌和運行時間
logging.info('as_personalized_status_info 總運行時間: {}秒'.format(execution_time))
logging.info("Table as_personalized_status_info has {} rows.".format(df.collect()[0][0]))
四:把並行改成1:
datax 這個配置是什麼意思: "job": {
"setting": {
"speed": {
"channel": 5,
"byte": 1048576
},
"errorLimit": {
"records": 1,
"percentage": 0
}
這段配置是 DataX 作業的一些基本設置,具體表示如下:
speed:指定了作業執行的速度參數,包括 channel 和 byte。其中,channel 表示通道數,即數據讀寫任務並行數量;byte 表示每個通道在內存中緩衝的字節數。通過合理的配置 speed 參數,可以調整作業的執行效率和吞吐量,提高數據傳輸的性能。
errorLimit:指定了作業的錯誤處理策略,包括 records 和 percentage。其中,records 表示允許作業出現的錯誤記錄數的最大值,例如設置爲 1,則意味着在運行過程中最多允許 1 條記錄出錯,否則作業將終止執行;percentage 表示允許錯誤記錄佔總記錄數的百分比最大值,例如設置爲 0.01,則意味着在運行過程中最多允許錯誤記錄佔總記錄數的 1%,否則作業將終止執行。
通過合理的配置 errorLimit 參數,可以保證數據傳輸的準確性和穩定性,避免運行過程中因爲錯誤導致的異常情況。
總之,這段配置主要用於控制 DataX 作業的執行速度和錯誤處理策略,幫助用戶更好地管理和控制數據傳輸過程中的性能和穩定性。如果您需要進一步瞭解 DataX 的配置和使用方法,可以參考 DataX 官方文檔,或者諮詢相關技術人員。
結果還是不行:把主鍵索引去掉之後發現一下情況:
[job-0] INFO JobContainer - PerfTrace not enable!
[job-0] INFO StandAloneJobContainerCommunicator - Total 30986769 records, 1651218096 bytes | Speed 1.92MB/s, 37788 records/s | Error 0 records, 0 bytes | All Task WaitWriterTime 758.765s | All Task WaitReaderTime 41.816s | Percentage 100.00%
[job-0] INFO JobContainer -
任務啓動時刻 : 2023-09-20 14:14:49
任務結束時刻 : 2023-09-20 14:28:30
任務總計耗時 : 820s
任務平均流量 : 1.92MB/s
記錄寫入速度 : 37788rec/s
讀出記錄總數 : 30986769
讀寫失敗總數 : 0
這是datax執行任務正常的輸出日誌,日誌中顯示讀取:30986769 但是 目標數據庫插入的數位卻是33182711,這是怎麼回事?
根據你提供的日誌信息,可以看出 DataX 執行任務期間讀取了 30,986,769 條記錄。然而,目標數據庫插入的記錄數卻爲 33,182,711 條,可能存在幾種原因導致記錄數差異:
數據重複:在數據同步過程中,源數據中可能存在重複記錄。如果目標數據庫沒有設置合適的去重策略,導致插入的記錄數比實際讀取的記錄數多。
事務回滾:在某些情況下,目標數據庫的插入操作可能發生了部分失敗,並觸發了事務回滾。這會導致一部分已讀取的數據無法成功插入,但日誌中並未顯示錯誤記錄。此時,目標數據庫的插入記錄數可能會超過實際讀取的記錄數。
數據同步延遲:如果數據同步過程中存在較大的延遲,即使 DataX 已經完成了對源數據的讀取操作,但目標數據庫的插入操作仍在進行中。這可能會導致目標數據庫的插入記錄數比實際讀取的記錄數多。
針對以上情況,你可以考慮進行以下操作:
檢查源數據是否存在重複記錄,並使用合適的去重策略。
檢查目標數據庫的插入操作是否有錯誤或失敗的記錄。可以查看數據同步過程中的詳細日誌或錯誤日誌。
確保數據同步過程中沒有較大的延遲。你可以對數據同步任務進行性能優化,以減少延遲。
大概是事務回滾重拾導致:把 "maxRetries": 1 測試兩次,沒有問題!(在沒有唯一索引下)
在有唯一索引的表裏面,還是會出問題,大概原因應該是這樣的:truncate table表之後,唯一索引是異步刪除的,再新增的時候,索引還沒刪掉,所以導致報唯一索引衝突!
主鍵有唯一索引!!