SymmetricDS文檔翻譯--【Chapter 3. 詳細配置(Configuration)[section C]】,
3.6. Routers
目前的實現中提供的Route實現包含:
1. Default Router:這個Router發送所有的資料到Router中定義的目標節點所屬的組中的所有的節點。
2. Column Match Router:這個Router可以將一個列的舊值(資料來源表中此列的值)或者新值(將要在目標節點設定的值)與一個常量值或者節點的external_id和node_id的值比較。
3. Lookup Router:這個Router可以被配置,在路由資料時,基於已經存在的表或者從屬表,確定是否執行路由操作。
4. Subselect Router:這個Router對資料庫執行一個SQL運算式來選擇要路由到的節點。這個SQL運算式可以被傳入某個列的舊值(資料變化之前的值)或者新值(資料變化之後的值)。
5. Scripted Router:這個Router執行一個Bean指令碼運算式以選出要路由到的節點。這個指令碼可以使用某個列的舊值或者新值。
6. XML Publishing Router:這個Router直接發布資料的變化到一個訊息解決方案,而不是傳送這些變化給一個已經註冊的節點。這個Router必須被手工配置為以XML格式作為擴充點。(可以跟kafka結合,然後資料就可以進入hadoop生態系統了)
7. Audit Table Router:這個Router將資料插入到一個自動建立的審計表中。這個Router記錄捕獲到的資料變化到與其關聯的表中。
Trigger和Router是多對多的關係。這意味著,一個觸發器可以捕獲資料變化然後路由這些變化到多個位置。也意味著一個Router可以與過個不同的觸發器相聯絡。
3.6.1. Default Router
最簡單的Router,這是一個發送所有相關的觸發器捕獲到的資料到所有router中定義的目標節點所屬的組中所有節點的Router。一個Router以ROUTER表中的一行資料代表。然後串連到TRIGGER_ROUTER表。
下面這個SQL語句定義了一個Router,這個Router將從“corp”組發送資料到“store“組。
insert into SYM_ROUTER (router_id, source_node_group_id, target_node_group_id, create_time, last_update_time) values ('corp-2-store','corp', 'store', current_timestamp, current_timestamp);
下面的SQL語句建立上邊的Router與item觸發器的映射。
insert into SYM_TRIGGER_ROUTER (trigger_id, router_id, initial_load_order, create_time, last_update_time) values ('item', 'corp-2-store', 1, current_timestamp, current_timestamp);
3.6.2. Column Match Router
有時可能會有這樣的需求,資料需要根據資料的當前值(資料變化發生之後)或者某個列的先前的值(資料變化發生之前)來決定是否需要被路由。在插入ROUTER系統資料表時設定router_type為column可以配置一個Column Router,然後在設定router_expression列為一個等式,這個等式代表了某個列的期望值。
運算式的第一部分總是一個列名。這個列名應該總是用大寫字母定義。大寫的列名以OLD_作為首碼可以用來比較這個列的舊值。運算式的第二個部分可以使一個常量,一個可以代表另一個列的符號或者可以代表其他的SymmetricDS概念的符號。符號的值總是以冒號(:)開始。
當一個表的狀態列被設定為“READY TO SEND”的時候,資料變化才被路由到目標節點群組的所有節點。下面的SQL語句將在ROUTER表中插入一個column router來完成這個需求。
insert into SYM_ROUTER (router_id, source_node_group_id, target_node_group_id,router_type, router_expression,create_time, last_update_time) values ('corp-2-store-ok','corp','store', 'column', 'STATUS=READY TO SEND', current_timestamp,current_timestamp);
當一個表的狀態列的值被修改時,變化的資料才被路由到目標組的所有節點。下面的SQL語句將在ROUTER表中插入一個column router來完成這個需求。注意OLD_STATUS的使用,OLD_首碼可以訪問這個列的舊值。
insert into SYM_ROUTER (router_id, source_node_group_id,target_node_group_id, router_type, router_expression,create_time, last_update_time) values ('corp-2-store-status','corp','store', 'column', 'STATUS!=:OLD_STATUS', current_timestamp,current_timestamp);
一個表的資料變化發送到目標節點群組中一個節點的external id與此表的STORE_ID列的值匹配的節點。下面的SQL語句將插入ROUTER表中一個column router來實現這個需求。
insert into SYM_ROUTER (router_id, source_node_group_id,target_node_group_id, router_type, router_expression,create_time, last_update_time) values ('corp-2-store-id','corp','store', 'column', 'STORE_ID=:EXTERNAL_ID', current_timestamp,current_timestamp);
一個節點的下面3個屬性可以被引用:
1. :NODE_ID
2. :EXTERNAL_ID
3. :NODE_GROUP_ID
在route過程中,總是可以捕獲EXTERNAL_DATA的值作為一個虛擬列。
一個表的資料變化需要被路由到一個重新導向節點,這個節點的external id在REGISTRATION_REDIRECT表中定義。下面的SQL語句將在ROUTER表中插入一個column router來實現這個需求。
insert into SYM_ROUTER (router_id, source_node_group_id,target_node_group_id, router_type, router_expression, create_time,last_update_time) values ('corp-2-store-redirect','corp','store', 'column', 'STORE_ID=:REDIRECT_NODE',current_timestamp, current_timestamp);
在router_expression中可以配置多個列。當配置超過一個列時,所有的匹配成功的節點都會被加到要被路由的節點列表中。下面是一個簡單的例子,一個表中,STORE_ID列的值需要等於一個節點的EXTERNAL_ID或者是ALL常量,等於ALL常量意味著所有的節點都會收到資料更新。
insert into SYM_ROUTER (router_id, source_node_group_id,target_node_group_id, router_type, router_expression,create_time, last_update_time) values ('corp-2-store-multiple-matches','corp','store', 'column', 'STORE_ID=ALL orSTORE_ID=:EXTERNAL_ID', current_timestamp, current_timestamp);
NULL關鍵字可以被用來檢查一個列是否為空白。如果列為空白,資料將被路由到所有的節點。下面的例子中,當STORE_ID列被用來路由到節點EXTERNAL_ID等於STORE_ID的節點,如果STORE_ID是空,就路由的所有的節點。
insert into SYM_ROUTER (router_id, source_node_group_id,target_node_group_id, router_type, router_expression,create_time, last_update_time) values ('corp-2-store-multiple-matches','corp','store', 'column', 'STORE_ID=NULL orSTORE_ID=:EXTERNAL_ID', current_timestamp, current_timestamp);
3.6.3. Lookup Table Router
一個lookup表可能包含資料要被路由的節點的ID。這可能是個已經存在的表或者一個特地為了路由資料被增加的附屬的表。Lookup Table Router通過在往ROUTER插入一個router時指定router_type的值為lookuptable來配置,可以再router_expression列中設定多個配置參數。
下面的每一個配置參數都是必須的。
LOOKUP_TABLE
Lookup table的名字。
KEY_COLUMN
將要被router的表中的列的名字。這將作為主鍵插入到lookup表中。
LOOKUP_KEY_COLUMN
Lookup表中的主鍵的列的名字。
EXTERNAL_ID_COLUMN
這是一個列的名字,這個列包含了lookup表中要被路由的節點的external_id。
注意,lookup表將被讀到記憶體中緩衝起來,以備資料在route到一個channel期間使用。
考慮到一個表可能被路由到某個特定的store,但是變化的表的資料只包含品牌資訊。在這個例子中,STORE表可以被用作lookup表。
insert into SYM_ROUTER (router_id, source_node_group_id,target_node_group_id, router_type, router_expression,create_time, last_update_time) values ('corp-2-store-ok','corp','store', 'lookuptable', 'LOOKUP_TABLE=STORE KEY_COLUMN=BRAND_IDLOOKUP_KEY_COLUMN=BRAND_ID EXTERNAL_ID_COLUMN=STORE_ID',current_timestamp, current_timestamp);
3.6.4. Subselect Router
有時候,需要基於當前沒有正在同步的資料來判斷是否需要路由當前的資料。Subselect Router可以在這種情況下使用。Subselect Router的router_expression列要配置一個SQL查詢語句,這個SQL語句返回需要被路由的節點的ID的列表。Column符號可以用在SQL運算式中,這些符號可以被一行資料中的指定的列替換。使用這種Router有很高的開銷,因為Subselect語句將會為每一個要路由的行運行一次。這不應該用在有很多行需要更新的表中。這種Router也有一個缺點,如果用來決定要路由的節點的ID的資料已經被刪除,SQL語句將不會返回結果,路由操作將不會發生。
你指定的Router_expression可以加到下面的SQL語句中,以選擇節點的ID:
select c.node_id from sym_node c where c.node_group_id=:NODE_GROUP_IDand c.sync_enabled=1 and ...
正如你看到的,你可以用別名“c”來訪問當前正在處理的節點的資訊,例如c.external_id。有兩個節點相關的符號你可以用在你的運算式中:
1. :NODE_GROUP_ID
2. :EXTERNAL_DATA
代表你的資料的列明需要有冒號首碼,例如”:EMPLOY_ID”,或者”:OLD_EMPLOYEE_ID”。在這裡,“OLD_”首碼表明這個值是發生資料變化之前的值。
例如,考慮下面的情況,一個“Order”表和一個“OrderLineItem”表需要被路由到某個特定的store。“Order“表有一個名叫”order_id“和”STORE_ID“的表。一個store節點有一個與“Order“表的STORE_ID相等的external_id。但是,”OrderLineItem“表,只有一個外鍵到”Order“表的”order_id“。為了路由”OrderLineItem“的資料到”Order“表要路由到的節點,我們需要引用“Order“表的記錄。
在SymmetricDS中,有兩種可能的方式來解決這個問題。一個是配置一個“Subselect“類型的Router,如下(另一種方式是使用external_select通過觸發器捕獲資料,然後在column router中使用這個資料匹配,詳細的描述在Section3.6.7 ,”Utilizing External Select when Routing“)。
我們的解決方案是利用Subselect比較當前節點的external id和Order表中的STORE_ID列的值,當order_id等於當前行的order id時就路由這個資料:
insert into SYM_ROUTER (router_id, source_node_group_id,target_node_group_id, router_type, router_expression,create_time, last_update_time) values ('corp-2-store','corp','store', 'subselect', 'c.external_id in (select STORE_ID from order whereorder_id=:ORDER_ID)', current_timestamp, current_timestamp);
最後,請注意在這個例子中,Order表中行在路由OrderLineItem表中相關聯的行時必須存在,因為當路由發生的時候,select語句正在運行,select語句的運行不是在資料變化第一次被捕獲的時候啟動並執行。
3.6.5. Scripted Router
當你需要更靈活的選擇要路由的節點的邏輯時,scripted router可能會用到。目前可用的指令碼語言是Bean Shell。BeanShell是一種類Java的指令碼語言。Bean Shell指令碼語言的文檔可以在http://www.beanshell.org中查看。
Bean Shell類型的Router的router_type是”bsh“。Route_expression是一個有效BeanShell 指令碼:
1. 增加一個節點的ID到目標節點的集合中
2. 返回一個包含多個節點ID的新的集合
3. 返回一個節點的ID
4. 如果目標組中所有的節點都要被路由就返回true,相反返回false。
指令碼返回的是節點的列表。這些節點都是合法的org.jumpmind.symmetric.model.Node對象。資料列當前值和舊值可以再指令碼中使用,使用一個Java對象代表一個列的資料。列明需要使用大寫。舊的值的引用需要使用”OLD_“首碼。
如果你需要訪問SymmetricDS服務,可以使用engine變數訪問一個org.jumpmind.symmetric.ISymmetricEngine介面的執行個體。
在下面的例子中,node_id是STORE_ID和WORKSTATION_NUMBER的組合,這兩個都是要被路由的表中的列:
insert into SYM_ROUTER (router_id, source_node_group_id,target_node_group_id, router_type, router_expression,create_time, last_update_time) values ('corp-2-store-bsh','corp','store', 'bsh', 'targetNodes.add(STORE_ID + "-" +WORKSTATION_NUMBER);', current_timestamp, current_timestamp);
同樣的功能可以簡單地返回Node ID來完成。Bah指令碼的最後一行總司返回這個值。
insert into SYM_ROUTER (router_id, source_node_group_id,target_node_group_id, router_type, router_expression,create_time, last_update_time) values ('corp-2-store-bsh','corp','store', 'bsh', 'STORE_ID + "-" + WORKSTATION_NUMBER',current_timestamp, current_timestamp);
下面的例子中,如果FLAG列被改變的化,資料會被同步到所有的節點,FLAG沒有被改變的話,將不會同步到任何節點。注意,這裡我們使用”OLD_“首碼,來訪問列的舊值。
insert into SYM_ROUTER (router_id, source_node_group_id,target_node_group_id, router_type, router_expression,create_time, last_update_time) values ('corp-2-store-flag-changed','corp','store', 'bsh', 'FLAG != null &&!FLAG.equals(OLD_FLAG)', current_timestamp, current_timestamp);
下面的例子中,這個指令碼遍曆每一個合法的節點,檢查是否名為STATION的列去掉兩端的空格後是否等於external_id的值。
insert into SYM_ROUTER (router_id, source_node_group_id,target_node_group_id, router_type, router_expression,create_time, last_update_time) values ('corp-2-store-trimmed-station','corp','store', 'bsh', 'for (org.jumpmind.symmetric.model.Nodenode : nodes) { if (STATION != null &&node.getExternalId().equals(STATION.trim())) { targetNodes.add(node.getNodeId());} }', current_timestamp, current_timestamp);
3.6.6. Audit Table Router
Audit Router通過記錄一個router建立和更新的審計表中資料變化捕獲資料變化(只要auto.config.database被設定為true)。Router建立一個表,表的名字是要捕獲的資料的表名加上”_AUDIT“尾碼。這個表將擁有與原始表相同的結構,還有3個附加的列。
表中增加了三個額外的審計列:
1. AUDIT_ID:表的主鍵
2. AUDIT_TIME:資料變化發生的時間
3. AUDIT_EVENT:發生在這行資料的DML類型
下面是建立一個audit router的例子:
insert into SYM_ROUTER (router_id, source_node_group_id,target_node_group_id, router_type, create_time, last_update_time)values ('audit_at_corp','corp', 'local', 'audit', current_timestamp,current_timestamp);
Audit Router為一個組串連捕獲資料。為了使上面的AuditRoute能夠工作,它必須使用”R“action類型,聯絡到一個node_group_link上。”R“代表”Only Route To“。在上面的例子中,我們關聯到一個local 組。這裡,local組是為audit router新建立的。沒有節點資料local節點群組。如果corp節點上,一個聯絡到audit Router觸發,一個新的audit表將會在corp節點建立,新變化的資料也會被插入到audit表中。