今天開發同學提了一個需求,是希望對某一個時間範圍的表做DDL操作,看起來好像複雜度也不高。
但是我一看開發同學提供的資訊時就有點猶豫了,因為埠是8066,也就意味著使用了中介軟體。這是一套MyCAT的環境,一共有4個節點,每個節點拆分成了4個邏輯節點,所以有16個sharding分片,正是應了那句話:百庫十表。雖然目前看起來節點數也不多,但是看看這個表hisrecord的分片邏輯就會發現,遠遠比我們想的要更豐富一些。
這個表是按照日期來儲存資料的,即資料的儲存單位是日。表名類似於rec20180301,rec20180302這種。所以按照這種增長的趨勢,可以根據時間維度不斷擴充套件,同時又對每天的表做了細粒度的拆分,每個日表會有16個分片做hashl路由。
開發同學的需求是對某一天之後的日表新增欄位,變更第一天的資料需要對該欄位新增預設值,之後的就不需要預設值了,這個從業務的角度來說,是因為應用層升級,需要這個屬性,如果有些業務暫時還沒有遷移過來,有一天的時間來緩衝調整修復。所以目前的需求的福利就是我們要修改的表目前沒有寫入,做變更不用考慮線上業務的寫入影響。
我簡單算了下,按照目前的修改幅度,影響的日表有177個。
mysql> select datediff('2018-11-01','2018-05-08');
+-------------------------------------+
| datediff('2018-11-01','2018-05-08') |
+-------------------------------------+
| 177 |
+-------------------------------------+
1 row in set (0.00 sec)
按照16個分片來算,這個數量就相當大了,有2800多張表。
mysql> select 177*16;
+--------+
| 177*16 |
+--------+
| 2832 |
+--------+
1 row in set (0.00 sec)
涉及的DDL表有2個,即2個DDL語句,所以算下來就是5600多張表了。所以你看一張表就能拆分成2000多張表,一年有差不多5800張相關的表。
如果在這個基礎上考慮當天的表結構變更,那就更復雜了。
我們來簡單看下MyCAT裡面的schema.xml配置。
裡面配置了16個分片,即dn50-dn65,database是histrecord01-histrecord16
<dataNode name="dn50" dataHost="localhost1" database="hisrecord01" />
<dataNode name="dn51" dataHost="localhost1" database="hisrecord02" />
。。。
<dataNode name="dn65" dataHost="localhost4" database="hisrecord16" />
對錶的分片規則是按照hash取模來計算的。
<table name="rec20180301" dataNode="dn$50-65" rule="mod-long-16-pid" />
<table name="rec20180302" dataNode="dn$50-65" rule="mod-long-16-pid" />。。。
<table name="rec20180307" dataNode="dn$50-65" rule="mod-long-16-pid" />
要做這個工作,手工完成的可能性太低,所以準備瞭如下的指令碼,借鑑了之前同事的一些思路。
我們輸入兩個時間,即起始時間,終止時間。app_sql/create_sql.sql是表結構的定義檔案。這個指令碼的意義在於不斷的處理表結構資訊,打上時間戳,寫入另外一個指令碼檔案,按照日期迴圈100天,就寫入100次。
startdate=`date -d "20180508" +%Y%m%d`
enddate=`date -d "20181101" +%Y%m%d`
#定義迴圈主函式
function main(){
while [[ ${startdate} < ${enddate} ]]
do
echo ${startdate}
cat /home/mysql/app_sql/create_sql.sql >> /home/mysql/app_sql/alter_his_record.sql
sed -i "s/20180508/${startdate}/g" /home/mysql/app_sql/alter_his_record.sql
echo "" >> /home/mysql/app_sql/alter_his_record.sql
echo
startdate=`date -d "+1 day ${startdate}" +%Y%m%d`
done
}
#執行主函式
main
所以很快就完成了上述的基本操作。當然MyCAT端是不支援DDL語句的。所以我們需要在每個節點上單獨去執行相應的變更DDL。
根據得到的指令碼略作改動,就可以分發到不同的sharding節點側了。整個過程持續了不到半個小時,很多時間都是在不斷的確認中,因為這個變更的影響範圍確實有點大。
當然這個問題的前提是我們已經建立好了日表,如果沒有日表的話,我們還是需要重新配置一下,然後在MyCAT端reload一些配置。
把這個任務擴充套件一下,就會發現,中介軟體層面的資料處理更側重於TP業務,而且是插入密集型的業務,如果是節點間的互動分散式,那這個方案就不大適合了。同時不斷的拆分從業務的角度來說,歷史資料的歸檔保留和資料的聚合需求還是有的。可能在這個時候中介軟體層面的支援就很有限了,我們在一定程度上可能需要其他的解決方案。