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

Sao chép MySQL và chuyển đổi dự phòng dựa trên GTID - Đi sâu vào các giao dịch có lỗi

Trong nhiều năm, việc nhân rộng MySQL từng dựa trên các sự kiện nhật ký nhị phân - tất cả những gì một nô lệ biết là sự kiện chính xác và vị trí chính xác mà nó vừa đọc được từ bản chính. Bất kỳ giao dịch đơn lẻ nào từ một tổng thể có thể đã kết thúc trong các nhật ký nhị phân khác nhau và ở các vị trí khác nhau trong các nhật ký này. Đó là một giải pháp đơn giản nhưng có những hạn chế - các thay đổi cấu trúc liên kết phức tạp hơn có thể yêu cầu quản trị viên ngừng sao chép trên các máy chủ có liên quan. Hoặc những thay đổi này có thể gây ra một số vấn đề khác, ví dụ:không thể di chuyển nô lệ xuống chuỗi nhân bản mà không mất thời gian xây dựng lại (chúng tôi không thể dễ dàng thay đổi bản sao từ A -> B -> C thành A -> C -> B mà không ngừng sao chép trên cả B và C). Tất cả chúng tôi đã phải giải quyết những hạn chế này trong khi mơ về một số nhận dạng giao dịch toàn cầu.

GTID đã được giới thiệu cùng với MySQL 5.6 và mang theo một số thay đổi lớn trong cách hoạt động của MySQL. Trước hết, mọi giao dịch đều có một mã định danh duy nhất xác định nó theo cùng một cách trên mọi máy chủ. Giao dịch được ghi lại ở vị trí nhật ký nhị phân nào không còn quan trọng nữa, tất cả những gì bạn cần biết là GTID:‘966073f3-b6a4-11e4-af2c-080027880ca6:4’. GTID được xây dựng từ hai phần - mã định danh duy nhất của máy chủ nơi giao dịch được thực hiện lần đầu tiên và số thứ tự. Trong ví dụ trên, chúng ta có thể thấy rằng giao dịch được thực thi bởi máy chủ có server_uuid là ‘966073f3-b6a4-11e4-af2c-080027880ca6’ và đó là giao dịch thứ 4 được thực hiện ở đó. Thông tin này đủ để thực hiện các thay đổi cấu trúc liên kết phức tạp - MySQL biết giao dịch nào đã được thực hiện và do đó nó biết giao dịch nào cần được thực hiện tiếp theo. Quên nhật ký nhị phân đi, tất cả đều nằm trong GTID.

Vì vậy, bạn có thể tìm thấy GTID ở đâu? Bạn sẽ tìm thấy chúng ở hai nơi. Trên nô lệ, trong "hiển thị trạng thái nô lệ;", bạn sẽ tìm thấy hai cột:Đã truy xuất_Gtid_Set và Thực hiện_Gtid_Set. Cái đầu tiên bao gồm GTID được truy xuất từ ​​cái chính thông qua sao chép, cái thứ hai thông báo về tất cả các giao dịch được thực hiện trên máy chủ nhất định - cả thông qua sao chép hoặc thực thi cục bộ.

Thiết lập một cụm sao một cách dễ dàng

Việc triển khai cụm sao chép MySQL rất dễ dàng trong ClusterControl (bạn có thể dùng thử miễn phí). Điều kiện tiên quyết duy nhất là tất cả các máy chủ, mà bạn sẽ sử dụng để triển khai các nút MySQL, có thể được truy cập từ phiên bản ClusterControl bằng cách sử dụng kết nối SSH không mật khẩu.

Khi có kết nối, bạn có thể triển khai một cụm bằng cách sử dụng tùy chọn “Triển khai”. Khi cửa sổ trình hướng dẫn mở ra, bạn cần đưa ra một số quyết định - bạn muốn làm gì? Triển khai một cụm mới? Triển khai nút Postgresql hoặc nhập cụm hiện có.

Chúng tôi muốn triển khai một cụm mới. Sau đó, chúng ta sẽ thấy màn hình sau đây, trong đó chúng ta cần quyết định loại cụm chúng ta muốn triển khai. Hãy chọn bản sao và sau đó chuyển các chi tiết cần thiết về kết nối ssh.

Khi đã sẵn sàng, hãy nhấp vào Tiếp tục. Lần này, chúng tôi cần quyết định nhà cung cấp MySQL nào chúng tôi muốn sử dụng, phiên bản nào và một số cài đặt cấu hình bao gồm, trong số những cài đặt khác, mật khẩu cho tài khoản gốc trong MySQL.

Cuối cùng, chúng ta cần quyết định cấu trúc liên kết sao chép - bạn có thể sử dụng thiết lập chủ - tớ điển hình hoặc tạo cặp chủ - chủ phức tạp hơn, hoạt động - dự phòng (+ nô lệ nếu bạn muốn thêm chúng). Khi đã sẵn sàng, chỉ cần nhấp vào “Triển khai” và trong vài phút, bạn sẽ triển khai cụm của mình.

Sau khi hoàn tất, bạn sẽ thấy cụm của mình trong danh sách cụm của giao diện người dùng của ClusterControl.

Sau khi nhân rộng và chạy, chúng tôi có thể xem xét kỹ hơn cách GTID hoạt động.

Giao dịch sai - vấn đề là gì?

Như chúng tôi đã đề cập ở phần đầu của bài đăng này, GTID’s đã mang lại một sự thay đổi đáng kể trong cách mọi người nên nghĩ về việc nhân rộng MySQL. Đó là tất cả về thói quen. Giả sử, vì một số lý do, một ứng dụng đã thực hiện ghi trên một trong các nô lệ. Điều đó đáng ra không nên xảy ra nhưng thật đáng ngạc nhiên, nó xảy ra mọi lúc. Kết quả là, sao chép dừng lại với lỗi khóa trùng lặp. Có một số cách để đối phó với vấn đề như vậy. Một trong số đó là xóa hàng vi phạm và khởi động lại quá trình sao chép. Cách khác sẽ là bỏ qua sự kiện nhật ký nhị phân và sau đó bắt đầu lại sao chép.

STOP SLAVE SQL_THREAD; SET GLOBAL sql_slave_skip_counter = 1; START SLAVE SQL_THREAD;

Cả hai cách đều sẽ đưa tính năng sao chép trở lại hoạt động, nhưng chúng có thể dẫn đến việc trôi dạt dữ liệu, vì vậy cần nhớ rằng tính nhất quán của nô lệ phải được kiểm tra sau sự kiện như vậy (pt-table-checksum và pt-table-sync hoạt động tốt ở đây).

Nếu sự cố tương tự xảy ra khi sử dụng GTID, bạn sẽ nhận thấy một số khác biệt. Xóa hàng vi phạm dường như có thể khắc phục được sự cố, quá trình nhân rộng sẽ có thể bắt đầu. Phương pháp khác, sử dụng sql_slave_skip_counter sẽ hoàn toàn không hoạt động - nó sẽ trả về một lỗi. Hãy nhớ rằng, bây giờ không phải là về các sự kiện trên binlog, mà là về GTID có được thực thi hay không.

Tại sao chỉ xóa hàng "dường như" để khắc phục sự cố? Một trong những điều quan trọng nhất cần ghi nhớ liên quan đến GTID là một nô lệ, khi kết nối với chủ, sẽ kiểm tra xem nó có thiếu bất kỳ giao dịch nào được thực hiện trên chủ hay không. Đây được gọi là các giao dịch sai lầm. Nếu một nô lệ tìm thấy các giao dịch như vậy, nó sẽ thực hiện chúng. Giả sử chúng ta đã chạy theo SQL để xóa một hàng vi phạm:

DELETE FROM mytable WHERE id=100;

Hãy kiểm tra để hiển thị trạng thái nô lệ:

                  Master_UUID: 966073f3-b6a4-11e4-af2c-080027880ca6
           Retrieved_Gtid_Set: 966073f3-b6a4-11e4-af2c-080027880ca6:1-29
            Executed_Gtid_Set: 84d15910-b6a4-11e4-af2c-080027880ca6:1,
966073f3-b6a4-11e4-af2c-080027880ca6:1-29,

Và xem 84d15910-b6a4-11e4-af2c-080027880ca6:1 đến từ đâu:

mysql> SHOW VARIABLES LIKE 'server_uuid'\G
*************************** 1. row ***************************
Variable_name: server_uuid
        Value: 84d15910-b6a4-11e4-af2c-080027880ca6
1 row in set (0.00 sec)

Như bạn có thể thấy, chúng tôi có 29 giao dịch đến từ chính, UUID của 966073f3-b6a4-11e4-af2c-080027880ca6 và một giao dịch đã được thực thi cục bộ. Giả sử rằng tại một thời điểm nào đó, chúng tôi chuyển đổi dự phòng và chủ (966073f3-b6a4-11e4-af2c-080027880ca6) trở thành nô lệ. Nó sẽ kiểm tra danh sách GTID được thực thi và sẽ không tìm thấy GTID này:84d15910-b6a4-11e4-af2c-080027880ca6:1. Kết quả là, SQL liên quan sẽ được thực thi:

DELETE FROM mytable WHERE id=100;

Đây không phải là điều chúng tôi mong đợi… Nếu trong thời gian chờ đợi, binlog chứa giao dịch này bị xóa trên nô lệ cũ, thì nô lệ mới sẽ khiếu nại sau khi chuyển đổi dự phòng:

                Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.'

Làm cách nào để phát hiện các giao dịch sai sót?

MySQL cung cấp hai hàm rất hữu ích khi bạn muốn so sánh các bộ GTID trên các máy chủ khác nhau.

GTID_SUBSET () nhận hai bộ GTID và kiểm tra xem bộ đầu tiên có phải là tập con của bộ thứ hai hay không.

Giả sử chúng ta có trạng thái sau.

Thạc sĩ:

mysql> show master status\G
*************************** 1. row ***************************
             File: binlog.000002
         Position: 160205927
     Binlog_Do_DB:
 Binlog_Ignore_DB:
Executed_Gtid_Set: 8a6962d2-b907-11e4-bebc-080027880ca6:1-153,
9b09b44a-b907-11e4-bebd-080027880ca6:1,
ab8f5793-b907-11e4-bebd-080027880ca6:1-2
1 row in set (0.00 sec)

Nô lệ:

mysql> show slave status\G
[...]
           Retrieved_Gtid_Set: 8a6962d2-b907-11e4-bebc-080027880ca6:1-153,
9b09b44a-b907-11e4-bebd-080027880ca6:1
            Executed_Gtid_Set: 8a6962d2-b907-11e4-bebc-080027880ca6:1-153,
9b09b44a-b907-11e4-bebd-080027880ca6:1,
ab8f5793-b907-11e4-bebd-080027880ca6:1-4

Chúng tôi có thể kiểm tra xem nô lệ có bất kỳ giao dịch sai sót nào hay không bằng cách thực thi SQL sau:

mysql> SELECT GTID_SUBSET('8a6962d2-b907-11e4-bebc-080027880ca6:1-153,ab8f5793-b907-11e4-bebd-080027880ca6:1-4', '8a6962d2-b907-11e4-bebc-080027880ca6:1-153, 9b09b44a-b907-11e4-bebd-080027880ca6:1, ab8f5793-b907-11e4-bebd-080027880ca6:1-2') as is_subset\G
*************************** 1. row ***************************
is_subset: 0
1 row in set (0.00 sec)

Có vẻ như có những giao dịch sai lầm. Làm thế nào để chúng tôi xác định chúng? Chúng ta có thể sử dụng một hàm khác, GTID_SUBTRACT ()

mysql> SELECT GTID_SUBTRACT('8a6962d2-b907-11e4-bebc-080027880ca6:1-153,ab8f5793-b907-11e4-bebd-080027880ca6:1-4', '8a6962d2-b907-11e4-bebc-080027880ca6:1-153, 9b09b44a-b907-11e4-bebd-080027880ca6:1, ab8f5793-b907-11e4-bebd-080027880ca6:1-2') as mising\G
*************************** 1. row ***************************
mising: ab8f5793-b907-11e4-bebd-080027880ca6:3-4
1 row in set (0.01 sec)

GTID bị thiếu của chúng tôi là ab8f5793-b907-11e4-bebd-080027880ca6:3-4 - các giao dịch đó được thực hiện trên máy chủ nhưng không được thực hiện trên máy chủ.

Làm cách nào để giải quyết các vấn đề do giao dịch sai gây ra?

Có hai cách - chèn các giao dịch trống hoặc loại trừ các giao dịch khỏi lịch sử GTID.

Để chèn các giao dịch trống, chúng ta có thể sử dụng SQL sau:

mysql> SET gtid_next='ab8f5793-b907-11e4-bebd-080027880ca6:3';
Query OK, 0 rows affected (0.01 sec)
mysql> begin ; commit;
Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.01 sec)
mysql> SET gtid_next='ab8f5793-b907-11e4-bebd-080027880ca6:4';
Query OK, 0 rows affected (0.00 sec)
mysql> begin ; commit;
Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.01 sec)
mysql> SET gtid_next=automatic;
Query OK, 0 rows affected (0.00 sec)

Điều này phải được thực thi trên mọi máy chủ lưu trữ trong cấu trúc liên kết sao chép không có các GTID đó được thực thi. Nếu bản chính có sẵn, bạn có thể đưa các giao dịch đó vào đó và để chúng tái tạo trong chuỗi. Nếu cái chủ không có sẵn (ví dụ:nó bị lỗi), thì những giao dịch trống đó phải được thực hiện trên mọi nô lệ. Oracle đã phát triển một công cụ có tên là mysqlslavetrx được thiết kế để tự động hóa quá trình này.

Một cách tiếp cận khác là xóa GTID khỏi lịch sử:

Dừng nô lệ:

mysql> STOP SLAVE;

In Executed_Gtid_Set trên nô lệ:

mysql> SHOW MASTER STATUS\G

Đặt lại thông tin GTID:

RESET MASTER;

Đặt GTID_PURGED thành một bộ GTID chính xác. dựa trên dữ liệu từ SHOW MASTER STATUS. Bạn nên loại trừ các giao dịch sai sót khỏi tập hợp.

SET GLOBAL GTID_PURGED='8a6962d2-b907-11e4-bebc-080027880ca6:1-153, 9b09b44a-b907-11e4-bebd-080027880ca6:1, ab8f5793-b907-11e4-bebd-080027880ca6:1-2';

Bắt đầu nô lệ.

mysql> START SLAVE\G

Trong mọi trường hợp, bạn nên xác minh tính nhất quán của các nô lệ của mình bằng cách sử dụng pt-table-checksum và pt-table-sync (nếu cần) - giao dịch sai có thể dẫn đến sai lệch dữ liệu.

Chuyển đổi dự phòng trong ClusterControl

Bắt đầu từ phiên bản 1.4, ClusterControl đã nâng cao các quy trình xử lý chuyển đổi dự phòng cho MySQL Replication. Bạn vẫn có thể thực hiện chuyển đổi chính thủ công bằng cách thúc đẩy một trong các nô lệ để làm chủ. Những nô lệ còn lại sau đó sẽ thất bại trước chủ nhân mới. Từ phiên bản 1.4, ClusterControl cũng có khả năng thực hiện chuyển đổi dự phòng hoàn toàn tự động nếu bản chính bị lỗi. Chúng tôi đã trình bày sâu về vấn đề này trong một bài đăng trên blog mô tả về ClusterControl và chuyển đổi dự phòng tự động. Chúng tôi vẫn muốn đề cập đến một tính năng, liên quan trực tiếp đến chủ đề của bài đăng này.

Theo mặc định, ClusterControl thực hiện chuyển đổi dự phòng theo “cách an toàn” - tại thời điểm chuyển đổi dự phòng (hoặc chuyển đổi, nếu đó là người dùng thực hiện chuyển đổi chính), ClusterControl chọn một ứng cử viên chính và sau đó xác minh rằng nút này không có bất kỳ giao dịch sai sót nào điều này sẽ tác động đến việc nhân rộng một khi nó được thăng cấp lên thành master. Nếu một giao dịch sai được phát hiện, ClusterControl sẽ dừng quá trình chuyển đổi dự phòng và ứng viên chính sẽ không được thăng cấp để trở thành chủ mới.

Nếu bạn muốn chắc chắn 100% rằng ClusterControl sẽ quảng bá một cái chính mới ngay cả khi một số vấn đề (như giao dịch sai) được phát hiện, bạn có thể làm điều đó bằng cách sử dụng cài đặt replication_stop_on_error =0 trong cấu hình cmon. Tất nhiên, như chúng ta đã thảo luận, nó có thể dẫn đến các vấn đề với sao chép - các nô lệ có thể bắt đầu yêu cầu sự kiện nhật ký nhị phân không còn khả dụng nữa.

Để xử lý những trường hợp như vậy, chúng tôi đã thêm hỗ trợ thử nghiệm cho việc xây dựng lại nô lệ. Nếu bạn đặt replication_auto_rebuild_slave =1 trong cấu hình cmon và máy chủ của bạn bị đánh dấu là không hoạt động với lỗi sau trong MySQL, ClusterControl sẽ cố gắng xây dựng lại máy phụ bằng cách sử dụng dữ liệu từ máy chủ:

Đã xảy ra lỗi nghiêm trọng 1236 từ chính khi đọc dữ liệu từ nhật ký nhị phân:'Máy phụ đang kết nối bằng CHANGE MASTER TO MASTER_AUTO_POSITION =1, nhưng máy chủ đã xóa nhật ký nhị phân chứa GTID mà máy phụ yêu cầu.'

Cài đặt như vậy có thể không phải lúc nào cũng phù hợp vì quá trình xây dựng lại sẽ tạo ra tải trọng tăng lên đối với bản chính. Cũng có thể do tập dữ liệu của bạn rất lớn và việc xây dựng lại thông thường không phải là một tùy chọn - đó là lý do tại sao hành vi này bị tắt theo mặc định.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Ví dụ về UTC_TIME - MySQL

  2. Cách hàm OCT () hoạt động trong MySQL

  3. Cách lấy row_number trong MySQL

  4. MySQLSyntaxErrorException gần? khi cố gắng thực thi PreparedStatement

  5. Cách sao lưu cơ sở dữ liệu được mã hóa với máy chủ Percona cho MySQL 8.0