Yineleme yeteneği MySQL'in 5.0 sürümünden itibaren sahip olduğu bir yetenektir. 5.6 sürümünde yamaklarda birden fazla iş parçası tanımlamak mümkün olabilmektedir. Böylelikle usta ile aradaki gecikme düşük değerlerde tutulabilinir. 5.6 öncesinde yamaklarda iki adet iş parçacığı vardı:
- G/Ç iş parçası: Ustanın binlog kayıtlarını okumaktan ve yerel diske yazmaktan sorumludur.
- SQL iş parçası: G/Ç iş parçasının yerel diske yazdığı SQL cümlelerini okuyup çalıştırmaktan sorumludur.
Artık SQL cümlelerini çalıştırmak için birden fazla iş parçası tanımlayabiliyoruz. Çok çekirdekli sistemlerde çalışan MySQL sunucusu için başarımın artacağı anlamına gelmektedir. Bunun için iş parçası sayısını slave_parallel_workers değişkenine atamak yeterli olmaktadır. Aksi belirtilmez ise varsayılan değeri sıfırdır. Bu durumda 5.6 öncesinde olduğu gibi birer iş parçası çalışır. Makinadaki çekirdek sayısı kadar değer vermek uygun olur:
mysql> set global slave_parallel_workers=4;
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like 'slave_parallel_workers';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| slave_parallel_workers | 4 |
+------------------------+-------+
1 row in set (0.00 sec)
MySQL'de çok ustalı yineleme yapmak mümkündür. Ancak çok ustalı yineleme ile ilgili birkaç problemin olduğunu bilmenizde fayda var. Öncelikle çok ustalı yinelemenin nasıl kurulacağını göstereceğim. Ardından karşılaşılan problemleri ve olası çözümlerine değineceğim. Çok ustalı yinelemede ikiden fazla düğüm kurmak anlamlı değildir. Bir halka yapısında oluşturulacak bu mimaride düğümlerden herhangi biri erişilemez olursa yineleme kesintiye uğrar.
İki düğümlü çok ustalı yineleme için öncelikli olarak sunucuların yapılandırma dosyalarında bir iki tanımlama yapmak gerekir. IP adresleri 192.168.1.66 (Sunucu 1) ve 192.168.1.67 (Sunucu 2) olan iki makinamız bulunsun. Sunucu 1 için yapılandırma dosyasında aşağıdaki tanımlamalar bulunmalıdır:
İki düğümlü çok ustalı yineleme için öncelikli olarak sunucuların yapılandırma dosyalarında bir iki tanımlama yapmak gerekir. IP adresleri 192.168.1.66 (Sunucu 1) ve 192.168.1.67 (Sunucu 2) olan iki makinamız bulunsun. Sunucu 1 için yapılandırma dosyasında aşağıdaki tanımlamalar bulunmalıdır:
[mysqld]
log_bin=masterlog
log-slave-updates
server_id = 1
...
Sunucu 2 için yapılandırma dosyasında aşağıdaki tanımlamalar bulunmalıdır:
[mysqld]
log_bin=masterlog
log-slave-updates
server_id = 2
...
Bir numaralı sunucuda yinelemede kullanılacak kullanıcı oluşturulur:
mysql> grant replication slave on *.* to 'repuser'@'192.168.1.%' identified by 'secret';
Query OK, 0 rows affected (0.02 sec)
mysql> show global variables like 'server_id';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id | 1 |
+---------------+-------+
1 row in set (0.00 sec)
mysql> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| masterlog.000001 | 473 |
+------------------+-----------+
1 row in set (0.00 sec)
mysql> flush logs;
Query OK, 0 rows affected (0.14 sec)
mysql> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| masterlog.000001 | 520 |
| masterlog.000002 | 120 |
+------------------+-----------+
2 rows in set (0.00 sec)
mysql> change master to
-> master_host='192.168.1.67',
-> master_user='repuser',
-> master_password='secret',
-> master_log_file='masterlog.000002',
-> master_log_pos=120,
-> master_port=3306;
Query OK, 0 rows affected, 2 warnings (0.30 sec)
mysql> start slave;
Query OK, 0 rows affected (0.04 sec)
mysql> show slave status \G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.1.67
Master_User: repuser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: masterlog.000002
Read_Master_Log_Pos: 120
Relay_Log_File: relaylog.000002
Relay_Log_Pos: 283
Relay_Master_Log_File: masterlog.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 120
Relay_Log_Space: 456
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 2
Master_UUID: 55458b84-9063-11e2-ab0e-00ff10207b07
Master_Info_File: C:\opt\mysql-5.6.10\data\master.info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
1 row in set (0.00 sec)
İki numaralı sunucuda (192.168.1.67) yinelemede kullanılacak kullanıcı oluşturulur:
mysql> grant replication slave on *.* to 'repuser'@'192.168.1.%' identified by 'secret';
Query OK, 0 rows affected (0.02 sec)
mysql> show global variables like 'server_id';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id | 2 |
+---------------+-------+
1 row in set (0.00 sec)
mysql> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| masterlog.000001 | 473 |
+------------------+-----------+
1 row in set (0.00 sec)
mysql> flush logs;
Query OK, 0 rows affected (0.14 sec)
mysql> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| masterlog.000001 | 520 |
| masterlog.000002 | 120 |
+------------------+-----------+
2 rows in set (0.00 sec)
mysql> change master to
-> master_host='192.168.1.66',
-> master_user='repuser',
-> master_password='secret',
-> master_port=3306,
-> master_log_file='masterlog.000002',
-> master_log_pos=120;
Query OK, 0 rows affected, 2 warnings (0.30 sec)
mysql> start slave;
Query OK, 0 rows affected (0.05 sec)
mysql> show slave status \G
*************************** 1. row ***************************
Slave_IO_State: Connecting to mastermysql> show slave status \G
*************************** 1. row ***************************
Master_Host: 192.168.1.66
Master_User: repuser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: masterlog.000002
Read_Master_Log_Pos: 120
Relay_Log_File: aa-PC-relay-bin.000001
Relay_Log_Pos: 4
Relay_Master_Log_File: masterlog.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 120
Relay_Log_Space: 120
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: NULL
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 0
Master_UUID:
Master_Info_File: C:\opt\mysql-5.6.10\data\master.info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp: 130319 09:34:00
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
1 row in set (0.00 sec)
Çok ustalı yinelemede temel problem CAP teoremi ile açıklanabilir. Eğer tek başına çalışan bir sunucudaki yazılımı bilgisayar ağı ile biri birine bağlı dağıtılmış bir sisteme dönüştürüyorsanız eskiden olduğu gibi davranmasını beklememelisiniz. Genelde yapılan hatalardan biri de testlerin sadece tek başına bir sistemde yapılmasıdır. Tek başına çalışan sistemde düzgün çalışan bir uygulama dağıtık bir sistemde istenilen biçimde çalışmayabilir. Brewer'in CAP teorimi de bununla ilgilidir. Teorem ile ilgili detayları bu bağlantıdan okuyabilirsiniz. Özetle teorem dağıtık bir sistemde aşağıdaki üç özelliğin tümünün birden sağlanamayacağını söyler:
- Tutarlılık
- Her zaman erişilebilirlik
- Bölünme bağışıklığı
Birinci problem:
Sunucu 1 | Sunucu 2 |
---|---|
mysql> use test; Database changed mysql> create table t1 ( -> id int not null auto_increment, -> value varchar(30), -> primary key(id) -> ) engine=innodb ; Query OK, 0 rows affected (0.44 sec) mysql> set autocommit=0; Query OK, 0 rows affected (0.00 sec) |
mysql> set autocommit=0; Query OK, 0 rows affected (0.00 sec) |
mysql> begin; Query OK, 0 rows affected (0.00 sec) |
mysql> begin; Query OK, 0 rows affected (0.00 sec) |
mysql> insert into t1 values (NULL,'jack'); Query OK, 1 row affected (0.00 sec) |
mysql> insert into t1 values(NULL,'jack'); Query OK, 1 row affected (0.01 sec) |
mysql> commit; Query OK, 0 rows affected (0.03 sec) |
|
mysql> commit; Query OK, 0 rows affected (0.03 sec) |
2013-02-20 13:07:38 1956 [ERROR] Slave SQL: Error 'Duplicate entry '1' for key 'PRIMARY'' on query. Default database: 'test'. Query: 'insert into t1 values(NULL,'jack')', Error_code: 1062
2013-02-20 13:07:38 1956 [Warning] Slave: Duplicate entry '1' for key 'PRIMARY' Error_code: 1062
2013-02-20 13:07:38 1956 [ERROR] Error running query, slave SQL thread aborted. Fix the problem, and restart the slave SQL thread with "SLAVE START". We stopped at log 'masterlog.000003' position 1687973
İkinci problem: Bu problem 'lost update' problemi olarak bilinir. Sunucularda aynı veritabanın tablolarında aynı kimlikli kayıtları üzerinde işlem yapılırken,iki farklı istemci kayıtlarda kilit olmadığı için bu kaydı değiştirmeye çalışabilir. Böyle bir durumunda kaydı en son değiştiren (commit gönderen) kazanır.
Sunucu 1 | Sunucu 2 |
---|---|
mysql> use test; Database changed mysql> create table t2 ( -> id int not null auto_increment, -> value varchar(30), -> unique key(value), -> primary key(id) -> ) engine=innodb ; Query OK, 0 rows affected (0.44 sec) mysql> insert into t2 values (1,'jack'); Query OK, 1 row affected (0.00 sec) mysql> set autocommit=0; Query OK, 0 rows affected (0.00 sec) | mysql> set autocommit=0; Query OK, 0 rows affected (0.00 sec) |
mysql> begin; Query OK, 0 rows affected (0.00 sec) | mysql> begin; Query OK, 0 rows affected (0.00 sec) |
mysql> update t2 set value='jack bauer' where id=1; Query OK, 1 row affected (0.00 sec) | mysql> update t2 set value='jack shephard' where id=1; Query OK, 1 row affected (0.00 sec) |
mysql> commit; Query OK, 0 rows affected (0.03 sec) | |
mysql> commit; Query OK, 0 rows affected (0.03 sec) |
Üçüncü problem:
Sunucu 1 | Sunucu 2 |
---|---|
mysql> use test; Database changed mysql> create table t2 ( -> id int not null auto_increment, -> value varchar(30), -> unique key(value), -> primary key(id) -> ) engine=innodb ; Query OK, 0 rows affected (0.44 sec) mysql> insert into t2 values (1,'jackb'),(2,'jacks'); Query OK, 1 row affected (0.00 sec) mysql> set autocommit=0; Query OK, 0 rows affected (0.00 sec) | mysql> set autocommit=0; Query OK, 0 rows affected (0.00 sec) |
mysql> begin; Query OK, 0 rows affected (0.00 sec) | mysql> begin; Query OK, 0 rows affected (0.00 sec) |
mysql> update t2 set value='jack bauer' where id=1; Query OK, 1 row affected (0.00 sec) | mysql> update t2 set value='jack bauer' where id=2; Query OK, 1 row affected (0.00 sec) |
mysql> commit; Query OK, 0 rows affected (0.03 sec) | |
mysql> commit; Query OK, 0 rows affected (0.03 sec) |
- auto_increment_offset tanımlaması
- Çok Ustalı Yineleme Yöneticisi kullanımı
- MySQL 5.5 ile beraber gelen yarı-eş zamanlı yineleme
- MySQL 5.6 ile gelen atomik yineleme