Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Nâng cấp giản đồ trực tuyến trong MySQL Galera Cluster bằng phương pháp RSU

Bài đăng này là phần tiếp theo của bài đăng trước của chúng tôi về Nâng cấp giản đồ trực tuyến trong Galera bằng phương pháp TOI. Bây giờ chúng tôi sẽ chỉ cho bạn cách thực hiện nâng cấp giản đồ bằng phương pháp Nâng cấp giản đồ cuộn (RSU).

RSU và TOI

Như chúng ta đã thảo luận, khi sử dụng TOI, sự thay đổi xảy ra đồng thời trên tất cả các nút. Điều này có thể trở thành một hạn chế nghiêm trọng vì cách thực hiện các thay đổi lược đồ như vậy ngụ ý rằng không có truy vấn nào khác có thể được thực hiện. Đối với các câu lệnh ALTER dài, cụm có thể không có sẵn trong nhiều giờ thậm chí. Rõ ràng, đây không phải là điều bạn có thể chấp nhận trong sản xuất. Phương pháp RSU giải quyết điểm yếu này - các thay đổi xảy ra trên một nút tại một thời điểm trong khi các nút khác không bị ảnh hưởng và có thể phục vụ lưu lượng truy cập. Sau khi ALTER hoàn thành trên một nút, nó sẽ tham gia lại vào cụm và bạn có thể tiếp tục thực hiện thay đổi giản đồ trên nút tiếp theo.

Hành vi như vậy đi kèm với một số giới hạn riêng của nó. Điều chính là thay đổi lược đồ đã lên lịch phải tương thích. Nó có nghĩa là gì? Hãy suy nghĩ về nó một lúc. Trước hết, chúng ta cần lưu ý rằng cụm luôn hoạt động - nút được thay đổi phải có khả năng chấp nhận tất cả lưu lượng truy cập vào các nút còn lại. Nói tóm lại, một DML được thực thi trên lược đồ cũ cũng phải hoạt động trên lược đồ mới (và ngược lại nếu bạn sử dụng một số loại phân phối kết nối giống như vòng lặp trong Cụm Galera của mình). Chúng tôi sẽ tập trung vào khả năng tương thích của MySQL, nhưng bạn cũng phải nhớ rằng ứng dụng của bạn phải hoạt động với cả các nút đã thay đổi và không bị thay đổi - hãy đảm bảo rằng thay đổi của bạn sẽ không phá vỡ logic ứng dụng. Một phương pháp hay là chuyển tên cột cho các truy vấn một cách rõ ràng - đừng dựa vào “CHỌN *” vì bạn không bao giờ biết mình sẽ nhận được bao nhiêu cột.

Galera và định dạng nhật ký nhị phân dựa trên hàng

Được rồi, vì vậy DML phải hoạt động trên các lược đồ cũ và mới. DML được chuyển như thế nào giữa các nút Galera? Nó có ảnh hưởng đến những thay đổi nào tương thích và những gì không? Vâng, thực sự - nó có. Galera không sử dụng bản sao MySQL thông thường nhưng nó vẫn dựa vào nó để chuyển các sự kiện giữa các nút. Nói chính xác, Galera sử dụng định dạng ROW cho các sự kiện. Sự kiện ở định dạng hàng (sau khi giải mã) có thể trông như thế này:

### INSERT INTO `schema`.`table`
### SET
###   @1=1
###   @2=1
###   @3='88764053989'
###   @4='14700597838'

Hoặc:

### UPDATE `schema`.`table`
### WHERE
###   @1=1
###   @2=1
###   @3='88764053989'
###   @4='14700597838'
### SET
###   @1=2
###   @2=2
###   @3='88764053989'
###   @4='81084251066'

Như bạn có thể thấy, có một mô hình dễ thấy:một hàng được xác định bằng nội dung của nó. Không có tên cột, chỉ có thứ tự của chúng. Chỉ điều này sẽ làm bật một số đèn cảnh báo:"điều gì sẽ xảy ra nếu tôi loại bỏ một trong các cột?" Vâng, nếu nó là cột cuối cùng, điều này có thể chấp nhận được. Nếu bạn xóa một cột ở giữa, điều này sẽ làm xáo trộn thứ tự cột và kết quả là quá trình sao chép sẽ bị hỏng. Điều tương tự sẽ xảy ra nếu bạn thêm một số cột ở giữa, thay vì ở cuối. Tuy nhiên, có nhiều ràng buộc hơn. Thay đổi định nghĩa cột sẽ hoạt động miễn là nó có cùng kiểu dữ liệu - bạn có thể thay đổi cột INT để trở thành BIGINT nhưng bạn không thể thay đổi cột INT thành VARCHAR - điều này sẽ phá vỡ sao chép. Bạn có thể tìm thấy mô tả chi tiết về thay đổi nào tương thích và thay đổi nào không trong tài liệu MySQL. Bất kể bạn có thể thấy gì trong tài liệu, để giữ an toàn, tốt hơn hết bạn nên chạy một số thử nghiệm trên một cụm phát triển / dàn dựng riêng biệt. Đảm bảo rằng nó sẽ hoạt động không chỉ theo tài liệu mà còn hoạt động tốt trong thiết lập cụ thể của bạn.

Nhìn chung, như bạn có thể thấy rõ, thực hiện RSU theo cách an toàn phức tạp hơn nhiều so với việc chỉ chạy một vài lệnh. Tuy nhiên, vì các lệnh rất quan trọng, chúng ta hãy xem ví dụ về cách bạn có thể thực hiện RSU và những gì có thể xảy ra sai sót trong quá trình này.

Ví dụ RSU

Thiết lập ban đầu

Hãy tưởng tượng một ví dụ khá đơn giản về một ứng dụng. Chúng tôi sẽ sử dụng một công cụ bechmark, Sysbench, để tạo nội dung và lưu lượng truy cập, nhưng quy trình sẽ giống nhau đối với hầu hết mọi ứng dụng - bạn đặt tên cho nó là Wordpress, Joomla, Drupal. Chúng tôi sẽ sử dụng HAProxy được kết hợp với ứng dụng của mình để phân chia các lần đọc và ghi giữa các nút Galera theo kiểu vòng tròn. Bạn có thể kiểm tra bên dưới cách HAProxy nhìn thấy cụm Galera.

Toàn bộ cấu trúc liên kết trông giống như bên dưới:

Lưu lượng truy cập được tạo bằng lệnh sau:

while true ; do sysbench /root/sysbench/src/lua/oltp_read_write.lua --threads=4 --max-requests=0 --time=3600 --mysql-host=10.0.0.100 --mysql-user=sbtest --mysql-password=sbtest --mysql-port=3307 --tables=32 --report-interval=1 --skip-trx=on --table-size=100000 --db-ps-mode=disable run ; done

Lược đồ trông giống như bên dưới:

mysql> SHOW CREATE TABLE sbtest1.sbtest1\G
*************************** 1. row ***************************
       Table: sbtest1
Create Table: CREATE TABLE `sbtest1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `k` int(11) NOT NULL DEFAULT '0',
  `c` char(120) NOT NULL DEFAULT '',
  `pad` char(60) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  KEY `k_1` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=29986632 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

Trước tiên, hãy xem cách chúng ta có thể thêm chỉ mục vào bảng này. Thêm chỉ mục là một thay đổi tương thích có thể dễ dàng thực hiện bằng RSU.

mysql> SET SESSION wsrep_OSU_method=RSU;
Query OK, 0 rows affected (0.00 sec)
mysql> ALTER TABLE sbtest1.sbtest1 ADD INDEX idx_new (k, c); 
Query OK, 0 rows affected (5 min 19.59 sec)

Như bạn có thể thấy trong tab Node, máy chủ mà chúng tôi thực hiện thay đổi đã tự động chuyển sang trạng thái Donor / Desynced, đảm bảo rằng máy chủ này sẽ không ảnh hưởng đến phần còn lại của cụm nếu nó bị ALTER làm chậm.

Bây giờ hãy kiểm tra xem giản đồ của chúng ta trông như thế nào:

mysql> SHOW CREATE TABLE sbtest1.sbtest1\G
*************************** 1. row ***************************
       Table: sbtest1
Create Table: CREATE TABLE `sbtest1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `k` int(11) NOT NULL DEFAULT '0',
  `c` char(120) NOT NULL DEFAULT '',
  `pad` char(60) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  KEY `k_1` (`k`),
  KEY `idx_new` (`k`,`c`)
) ENGINE=InnoDB AUTO_INCREMENT=29986632 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

Như bạn có thể thấy, chỉ mục đã được thêm vào. Xin lưu ý, tuy nhiên, điều này chỉ xảy ra trên nút cụ thể đó. Để thực hiện thay đổi toàn bộ giản đồ, bạn phải thực hiện theo quy trình này trên các nút còn lại của Cụm Galera. Để kết thúc với nút đầu tiên, chúng ta có thể chuyển wsrep_OSU_method trở lại TOI:

SET SESSION wsrep_OSU_method=TOI;
Query OK, 0 rows affected (0.00 sec)

Chúng tôi sẽ không hiển thị phần còn lại của quá trình, vì nó giống nhau - bật RSU ở cấp phiên, chạy ALTER, bật TOI. Điều thú vị hơn là điều gì sẽ xảy ra nếu thay đổi không tương thích. Chúng ta hãy xem nhanh lại giản đồ:

mysql> SHOW CREATE TABLE sbtest1.sbtest1\G
*************************** 1. row ***************************
       Table: sbtest1
Create Table: CREATE TABLE `sbtest1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `k` int(11) NOT NULL DEFAULT '0',
  `c` char(120) NOT NULL DEFAULT '',
  `pad` char(60) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  KEY `k_1` (`k`),
  KEY `idx_new` (`k`,`c`)
) ENGINE=InnoDB AUTO_INCREMENT=29986632 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

Giả sử chúng tôi muốn thay đổi loại cột ‘k’ từ INT thành VARCHAR (30) trên một nút.

mysql> SET SESSION wsrep_OSU_method=RSU;
Query OK, 0 rows affected (0.00 sec)
mysql> ALTER TABLE sbtest1.sbtest1 MODIFY COLUMN k VARCHAR(30) NOT NULL DEFAULT '';
Query OK, 10004785 rows affected (1 hour 14 min 51.89 sec)
Records: 10004785  Duplicates: 0  Warnings: 0

Bây giờ, chúng ta hãy xem lược đồ:

mysql> SHOW CREATE TABLE sbtest1.sbtest1\G
*************************** 1. row ***************************
       Table: sbtest1
Create Table: CREATE TABLE `sbtest1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `k` varchar(30) NOT NULL DEFAULT '',
  `c` char(120) NOT NULL DEFAULT '',
  `pad` char(60) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  KEY `k_1` (`k`),
  KEY `idx_new` (`k`,`c`)
) ENGINE=InnoDB AUTO_INCREMENT=29986632 DEFAULT CHARSET=latin1
1 row in set (0.02 sec)

Mọi thứ đều như chúng tôi mong đợi - cột ‘k’ đã được thay đổi thành VARCHAR. Bây giờ chúng ta có thể kiểm tra xem thay đổi này có được chấp nhận hay không đối với Cụm Galera. Để kiểm tra nó, chúng tôi sẽ sử dụng một trong các nút còn lại, không thay đổi để thực hiện truy vấn sau:

mysql> INSERT INTO sbtest1.sbtest1 (k, c, pad) VALUES (123, 'test', 'test');
Query OK, 1 row affected (0.19 sec)
Hãy xem những gì đã xảy ra.

Nó chắc chắn trông không đẹp - nút của chúng tôi không hoạt động. Nhật ký sẽ cung cấp cho bạn thêm chi tiết:

2017-04-07T10:51:14.873524Z 5 [ERROR] Slave SQL: Column 1 of table 'sbtest1.sbtest1' cannot be converted from type 'int' to type 'varchar(30)', Error_code: 1677
2017-04-07T10:51:14.873560Z 5 [Warning] WSREP: RBR event 3 Write_rows apply warning: 3, 982675
2017-04-07T10:51:14.879120Z 5 [Warning] WSREP: Failed to apply app buffer: seqno: 982675, status: 1
         at galera/src/trx_handle.cpp:apply():351
Retrying 2th time
2017-04-07T10:51:14.879272Z 5 [ERROR] Slave SQL: Column 1 of table 'sbtest1.sbtest1' cannot be converted from type 'int' to type 'varchar(30)', Error_code: 1677
2017-04-07T10:51:14.879287Z 5 [Warning] WSREP: RBR event 3 Write_rows apply warning: 3, 982675
2017-04-07T10:51:14.879399Z 5 [Warning] WSREP: Failed to apply app buffer: seqno: 982675, status: 1
         at galera/src/trx_handle.cpp:apply():351
Retrying 3th time
2017-04-07T10:51:14.879618Z 5 [ERROR] Slave SQL: Column 1 of table 'sbtest1.sbtest1' cannot be converted from type 'int' to type 'varchar(30)', Error_code: 1677
2017-04-07T10:51:14.879633Z 5 [Warning] WSREP: RBR event 3 Write_rows apply warning: 3, 982675
2017-04-07T10:51:14.879730Z 5 [Warning] WSREP: Failed to apply app buffer: seqno: 982675, status: 1
         at galera/src/trx_handle.cpp:apply():351
Retrying 4th time
2017-04-07T10:51:14.879911Z 5 [ERROR] Slave SQL: Column 1 of table 'sbtest1.sbtest1' cannot be converted from type 'int' to type 'varchar(30)', Error_code: 1677
2017-04-07T10:51:14.879924Z 5 [Warning] WSREP: RBR event 3 Write_rows apply warning: 3, 982675
2017-04-07T10:51:14.885255Z 5 [ERROR] WSREP: Failed to apply trx: source: 938415a6-1aab-11e7-ac29-0a69a4a1dafe version: 3 local: 0 state: APPLYING flags: 1 conn_id: 125559 trx_id: 2856843 seqnos (l: 392283, g: 9
82675, s: 982674, d: 982563, ts: 146831275805149)
2017-04-07T10:51:14.885271Z 5 [ERROR] WSREP: Failed to apply trx 982675 4 times
2017-04-07T10:51:14.885281Z 5 [ERROR] WSREP: Node consistency compromized, aborting…

Có thể thấy, Galera đã phàn nàn về việc không thể chuyển đổi cột từ INT sang VARCHAR (30). Nó đã cố gắng thực hiện lại bộ ghi bốn lần nhưng không thành công, không có gì đáng ngạc nhiên. Do đó, Galera xác định rằng tính nhất quán của nút bị xâm phạm và nút bị loại khỏi cụm. Nội dung còn lại của nhật ký cho thấy quá trình này:

2017-04-07T10:51:14.885560Z 5 [Note] WSREP: Closing send monitor...
2017-04-07T10:51:14.885630Z 5 [Note] WSREP: Closed send monitor.
2017-04-07T10:51:14.885644Z 5 [Note] WSREP: gcomm: terminating thread
2017-04-07T10:51:14.885828Z 5 [Note] WSREP: gcomm: joining thread
2017-04-07T10:51:14.885842Z 5 [Note] WSREP: gcomm: closing backend
2017-04-07T10:51:14.896654Z 5 [Note] WSREP: view(view_id(NON_PRIM,6fcd492a,37) memb {
        b13499a8,0
} joined {
} left {
} partitioned {
        6fcd492a,0
        938415a6,0
})
2017-04-07T10:51:14.896746Z 5 [Note] WSREP: view((empty))
2017-04-07T10:51:14.901477Z 5 [Note] WSREP: gcomm: closed
2017-04-07T10:51:14.901512Z 0 [Note] WSREP: New COMPONENT: primary = no, bootstrap = no, my_idx = 0, memb_num = 1
2017-04-07T10:51:14.901531Z 0 [Note] WSREP: Flow-control interval: [16, 16]
2017-04-07T10:51:14.901541Z 0 [Note] WSREP: Received NON-PRIMARY.
2017-04-07T10:51:14.901550Z 0 [Note] WSREP: Shifting SYNCED -> OPEN (TO: 982675)
2017-04-07T10:51:14.901563Z 0 [Note] WSREP: Received self-leave message.
2017-04-07T10:51:14.901573Z 0 [Note] WSREP: Flow-control interval: [0, 0]
2017-04-07T10:51:14.901581Z 0 [Note] WSREP: Received SELF-LEAVE. Closing connection.
2017-04-07T10:51:14.901589Z 0 [Note] WSREP: Shifting OPEN -> CLOSED (TO: 982675)
2017-04-07T10:51:14.901602Z 0 [Note] WSREP: RECV thread exiting 0: Success
2017-04-07T10:51:14.902701Z 5 [Note] WSREP: recv_thread() joined.
2017-04-07T10:51:14.902720Z 5 [Note] WSREP: Closing replication queue.
2017-04-07T10:51:14.902730Z 5 [Note] WSREP: Closing slave action queue.
2017-04-07T10:51:14.902742Z 5 [Note] WSREP: /usr/sbin/mysqld: Terminated.

Tất nhiên, ClusterControl sẽ cố gắng khôi phục nút như vậy - quá trình khôi phục liên quan đến việc chạy SST, vì vậy các thay đổi giản đồ không tương thích sẽ bị xóa, nhưng chúng tôi sẽ trở lại bình phương - thay đổi giản đồ của chúng tôi sẽ bị đảo ngược.

Như bạn có thể thấy, trong khi chạy RSU là một quá trình rất đơn giản, bên dưới nó có thể khá phức tạp. Nó yêu cầu một số thử nghiệm và chuẩn bị để đảm bảo rằng bạn sẽ không mất một nút chỉ vì thay đổi giản đồ không tương thích.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Làm thế nào để thay đổi đối chiếu của cơ sở dữ liệu, bảng, cột?

  2. Mẹo để chuyển từ Cơ sở dữ liệu độc quyền sang nguồn mở

  3. MySQL # 1140 - Kết hợp các cột NHÓM

  4. Lưu trữ MySQL trên Azure, Dịch vụ cơ sở dữ liệu đám mây được quản lý hoàn toàn ra mắt tại ScaleGrid

  5. mySQL chuyển đổi varchar thành ngày tháng