在這篇文章中,我們將瞭解如何將 MySQL 8.2 的讀寫分離功能與 MySQL-Connector/Python 一起使用。
作者:Frederic Descamps,MySQL 社區經理
本文和封面來源:https://blogs.oracle.com/,愛可生開源社區翻譯。
本文約 1200 字,預計閱讀需要 4 分鐘。
如您所知,MySQL 8.2 發佈了最令人期待的功能之一:讀寫分離。
在這篇文章中,我們將瞭解如何將它與 MySQL-Connector/Python 一起使用。
架構
爲了使用我們的 Python 程序,我們將使用 InnoDB Cluster。
以下是在 MySQL Shell 中查詢 Cluster 的狀態:
JS > cluster.status()
{
"clusterName": "fred",
"defaultReplicaSet": {
"name": "default",
"primary": "127.0.0.1:3310",
"ssl": "REQUIRED",
"status": "OK",
"statusText": "Cluster is ONLINE and can tolerate up to ONE failure.",
"topology": {
"127.0.0.1:3310": {
"address": "127.0.0.1:3310",
"memberRole": "PRIMARY",
"mode": "R/W",
"readReplicas": {},
"replicationLag": "applier_queue_applied",
"role": "HA",
"status": "ONLINE",
"version": "8.2.0"
},
"127.0.0.1:3320": {
"address": "127.0.0.1:3320",
"memberRole": "SECONDARY",
"mode": "R/O",
"readReplicas": {},
"replicationLag": "applier_queue_applied",
"role": "HA",
"status": "ONLINE",
"version": "8.2.0"
},
"127.0.0.1:3330": {
"address": "127.0.0.1:3330",
"memberRole": "SECONDARY",
"mode": "R/O",
"readReplicas": {},
"replicationLag": "applier_queue_applied",
"role": "HA",
"status": "ONLINE",
"version": "8.2.0"
}
},
"topologyMode": "Single-Primary"
},
"groupInformationSourceMember": "127.0.0.1:3310"
}
JS > cluster.listRouters()
{
"clusterName": "fred",
"routers": {
"dynabook::system": {
"hostname": "dynabook",
"lastCheckIn": "2023-11-09 17:57:59",
"roPort": "6447",
"roXPort": "6449",
"rwPort": "6446",
"rwSplitPort": "6450",
"rwXPort": "6448",
"version": "8.2.0"
}
}
}
MySQL Connector/Python
Python 程序使用 MySQL-Connector/Python 8.2.0。
初始化測試腳本代碼:
import mysql.connector
cnx = mysql.connector.connect(user='python',
passowrd='Passw0rd!Python',
host='127.0.0.1',
port='6450')
cursor = cnx.cursor()
query = ("""select member_role, @@port port
from performance_schema.replication_group_members
where member_id=@@server_uuid""")
for (role, port) in cursor:
print("{} - {}".format(role, port))
cursor.close()
cnx.close()
我們可以測試一下:
$ python test_router.py
PRIMARY - 3310
很好,我們可以使用讀/寫分離端口(6540)連接到集羣並執行查詢……。哦 ?!但爲什麼我們會直達主實例呢?
我們不應該是去訪問只讀實例(副本實例)之一嗎?
autocommit
Connector/Python 默認禁用自動提交(請參閱 MySQLConnection.autocommit 屬性)。並且讀寫分離功能必須啓用自動提交才能正常工作。
在第 8 行上方添加以下代碼:
cnx.autocommit = True
然後我們可以再次運行該程序:
$ python test_router.py
SECONDARY - 3320
$ python test_router.py
SECONDARY - 3330
太棒了,達到預期效果工作!
查詢屬性
現在讓我們看看如何在主節點上強制執行查詢。
MySQL Router 提供了使用查詢屬性來強制執行讀/寫拆分決策的可能性:router.access_mode。
在執行查詢 ( cursor.execute(query) ) 之前添加以下行:
cursor.add_attribute("router.access_mode", "read_write")
讓我們再執行一次:
$ python test_router.py
PRIMARY - 3310
router.access_mode
可接受的值爲:
- auto
- read_only
- read_write
測試 DML 語句
讓我們嘗試一些不同的東西,我們將向表中插入行。
我們將使用下表:
CREATE TABLE `t1` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`port` int DEFAULT NULL,
`role` varchar(15) DEFAULT NULL,
`timestamp` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB ;
我們將使用以下 Python 腳本:
import mysql.connector
cnx = mysql.connector.connect(user='python',
password='Passw0rd!Python',
host='127.0.0.1',
port='6450',
database='test')
cnx.autocommit = True
cursor = cnx.cursor()
for i in range(3):
query = ("""insert into t1 values(0, @@port, (
select member_role
from performance_schema.replication_group_members
where member_id=@@server_uuid), now())""")
cursor.execute(query)
cursor.close()
cnx.close()
for i in range(3):
cnx = mysql.connector.connect(user='python',
password='Passw0rd!Python',
host='127.0.0.1',
port='6450',
database='test')
cnx.autocommit = True
cursor = cnx.cursor()
query = ("""select *, @@port port_read from t1""")
cursor.execute(query)
for (id, port, role, timestamp, port_read) in cursor:
print("{} : {}, {}, {} : read from {}".format(id,
port,
role,
timestamp,
port_read))
cursor.close()
cnx.close()
讓我們執行它:
$ python test_router2.py
1 : 3310, PRIMARY, 2023-11-09 17:44:00 : read from 3330
2 : 3310, PRIMARY, 2023-11-09 17:44:00 : read from 3330
3 : 3310, PRIMARY, 2023-11-09 17:44:00 : read from 3330
1 : 3310, PRIMARY, 2023-11-09 18:44:00 : read from 3320
2 : 3310, PRIMARY, 2023-11-09 18:44:00 : read from 3320
3 : 3310, PRIMARY, 2023-11-09 18:44:00 : read from 3320
1 : 3310, PRIMARY, 2023-11-09 17:44:00 : read from 3330
2 : 3310, PRIMARY, 2023-11-09 17:44:00 : read from 3330
3 : 3310, PRIMARY, 2023-11-09 17:44:00 : read from 3330
我們可以看到沒有錯誤,並且我們寫入了主節點並從所有輔助節點讀取。
請小心,如果在寫入之前將 router.access_mode
的查詢屬性設置爲 read_only
(第 16 行),您將收到錯誤,因爲副本節點上不允許寫入:
_mysql_connector.MySQLInterfaceError: The MySQL server is running with the --super-read-only option so it cannot execute this statement
事務
現在我們要玩一下事務。我們創建一個新腳本來執行多個事務:
- 自動提交中的讀操作
- 事務中的讀操作(默認情況下,這是讀/寫事務)
- 只讀事務中的讀操作
- 具有多次插入和回滾的事務
這是程序的源碼:
import mysql.connector
cnx = mysql.connector.connect(user='python',
password='Passw0rd!Python',
host='127.0.0.1',
port='6450',
database='test')
cnx.autocommit = True
cursor = cnx.cursor()
query = ("""select member_role, @@port port
from performance_schema.replication_group_members
where member_id=@@server_uuid""")
cursor.execute(query)
for (role, port) in cursor:
print("{} - {}".format(role, port))
cnx.start_transaction()
query = ("""select member_role, @@port port
from performance_schema.replication_group_members
where member_id=@@server_uuid""")
cursor.execute(query)
for (role, port) in cursor:
print("{} - {}".format(role, port))
cnx.commit()
cnx.start_transaction(readonly=True)
query = ("""select member_role, @@port port
from performance_schema.replication_group_members
where member_id=@@server_uuid""")
cursor.execute(query)
for (role, port) in cursor:
print("{} - {}".format(role, port))
cnx.commit()
cnx.start_transaction()
for i in range(3):
query = ("""insert into t1 values(0, @@port, (
select member_role
from performance_schema.replication_group_members
where member_id=@@server_uuid), now())""")
cursor.execute(query)
cnx.rollback()
cursor.close()
cnx.close()
讓我們執行腳本:
$ python test_router3.py
SECONDARY - 3320
PRIMARY - 3310
SECONDARY - 3320
我們可以看到,第一個操作到達了副本實例,第二個操作(即事務)到達了主節點。
只讀事務到達副本節點。
對於作爲我們回滾事務一部分的多次寫入,我們沒有收到任何錯誤。
結論
我們已經看到將 MySQL Connector/Python 與 MySQL 8.2 讀寫分離一起用於 InnoDB Cluster 是多麼容易。
享受通過 MySQL Connector / Python 使用 MySQL 讀寫分離!
更多技術文章,請訪問:https://opensource.actionsky.com/
關於 SQLE
SQLE 是一款全方位的 SQL 質量管理平臺,覆蓋開發至生產環境的 SQL 審覈和管理。支持主流的開源、商業、國產數據庫,爲開發和運維提供流程自動化能力,提升上線效率,提高數據質量。