背景
在服務高度拆分,數據庫不斷細化切分的情況下,我們經常有連接多台數據庫查詢的需求,如果不斷的把數據庫連接的邏輯添加在代碼中,那么這種耦合會越來越嚴重,這會給程序的拓展和維護帶來很大的麻煩。
mysql的federated引擎,可以在本地創建遠程數據庫的映射表,創建完后,拓撲如下:
如此,我們可以在本地構建多個遠程數據庫庫的統一入口,這樣可以極大的簡化在分布式環境中,跨服務器數據庫的交互查詢問題。
1.開啟引擎
查詢數據庫是否支持
SHOW ENGINES;
有,說明支持,但是沒有開啟,開啟一下:
配置文件添加:federated
,如下:
[mysqld]
federated
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
然后重啟mysql,再次查詢,發現已經開啟:
2.場景
數據庫1:阿里雲 java4all,表product_stock;
數據庫2:華為雲 wangtest1,表user;
user表中有一個product_stock_id。
需求:需要跨庫查詢。
3.創建數據庫表映射
在華為雲的wangtest1數據庫中,創建一個阿里雲的java4all庫的product_stock表的映射表。
CREATE TABLE `product_stock` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`stock` int(11) DEFAULT NULL COMMENT '庫存',
PRIMARY KEY (`id`)
) ENGINE=FEDERATED DEFAULT CHARSET=utf8 COMMENT='庫存表,來自阿里雲映射'
CONNECTION='mysql://username:password@ip:port/java4all/product_stock';
這里需要注意,數據庫引擎的選擇,要明確指定引擎ENGINE=FEDERATED
,
創建完后,會發現,在wangtest1庫中,也有了product_stock表:
此時,其實在華為雲的wangtest1庫中,就有了阿里雲的java4all庫中的product_stock這張表的映射了。我們可以看到,這張表外觀看起來和正常的表是一樣的,但是其實華為雲這邊這是存儲了表結構,數據還是從阿里雲拉取的。
我們嘗試在阿里雲修改數據,在華為雲這邊刷新,也會看到變化。反之也是可以的。在使用層面看來,這個product_stock和本地原本就創建了的效果是一樣的,各種查詢都是支持的,但是不建議給映射表寫的權限。
查詢測試:
SELECT * from user a ,product_stock ps
WHERE a.product_stock_id = ps.id
and ps.`name` LIKE CONCAT('%','香','%')
and a.user_type = 1;
4.注意事項
1.映射表的字段,要少於等於原表(遠程表)字段。
2.遠程表的數據庫據密碼,不能含有@字符,因為在創建映射表時,CONNECTION='mysql://root:1xxx@1xx.xx.xx.xx:3306/java4all/product_stock'
,這里用戶名密碼,和數據庫地址之間的分隔符是@,如果你的密碼含有@,會導致解析出錯。
3.修改本地表結構,是不允許的,因為你這個表是映射遠程表的,遠程表沒改,你改了,可能會映射不上一些字段。如果遠程表修改了,這個表需要重新映射。所有,理論上,為了防止不必要的麻煩,本地的映射表禁止任何結構性修改,如果遠程表結構修改了,本地的刪掉重新映射即可。
4.刪除本地映射表,對遠程表無負作用。
5.本地數據庫服務必須支持federated引擎,遠程服務器可以不支持。
6.數據庫版本需要在5.0以上。
7.federated引擎是基於表級別的,無法實現基於庫級別的整體映射。
8.如果遠程表添加了索引,及時同步更新到本地映射表中。
9.limit是個比較慢的操作,引擎會將所有滿足條件的數據讀取到本地,再limit處理。
10.顯然,看起來,你可能會覺得,那我把各個相關微服務的表全部映射過來,那連分布式事務的問題都一並解決了,因為本地看起來就擁有所有的表,那分布式事務的各種解決方案都不需要存在了。這里,由於沒有這么大規模生產壓測過,不好定論,不好反駁。但是既然微服務拆分了,解耦了應用,那庫顯然也是解耦的,mysql只是提供了這種功能,讓你在某些特殊需求場景下,來連接和簡化多數據源數據的交互問題。而不是讓你里用這個,將原本做好了解耦和合理拆分的東西,再重新糅合一團。
11.Pay attention to the border!
5.關於連接的問題
1.本地虛擬表與遠程實體表之間是 TCP 長連接,並且是多個客戶端利用的。所以不用擔心因頻繁建立連接帶來的網絡開銷。
2.本虛擬表表與遠程實體表之間的網絡連接斷開后,當對虛擬表發起查詢時,它會嘗試重新連接遠程實體表,所以我們不用擔心網絡連接斷開造成的永久中斷問題。
3.如果長時間未對本地虛擬表作任何操作,虛擬表與實體表之間的連接將在遠程主機的 wait_timeout 秒后自動斷開,當對虛擬表發起查詢時,連接又會重新建立。
6.性能
由於少見有大廠專門對此進行過性能測試,網上資料也比較少,目前未見到什么明顯的性能短板,但沒有大規模生產使用,應該還是有短板的(待我去官網翻譯一波文檔)。打算踩坑的可以一起組團踩坑。直接上生產的,注意風險把控。
起碼是個跨服務查詢,數據量大的時候,網絡和傳輸應該是個起碼的瓶頸。
原文地址:https://blog.csdn.net/weixin_39800144/article/details/88684475 </div>