Showing posts with label Replication. Show all posts
Showing posts with label Replication. Show all posts

Tuesday, April 16, 2013

Çok Sunuculu MySQL Mimarilerinde Yük Dengeleme Çözümleri

Giriş

Kurumsal uygulamaların her zaman erişilebilir ve ölçeklenebilir olmasını istiyoruz. Bunun için bilişim sistemini oluşturan her katmanda bu özellikleri sağlamamız gerekir. Bu katmanlardan biri de verileri kalıcı olarak saklamamızı ve gerektiğinde olabildiğince hızlı bir şekilde erişmemizi sağlayan ilişkisel veri tabanı sistemleridir. MySQL açık kaynak kodlu, (Oracle, MariaDB, Percona gibi) firmalardan desteğini alabileceğiniz, yaygın ve çok ölçekli kullanımı olan (Facebook gibi) bir çözüm olarak öne çıkmaktadır. MySQL'de çok sunuculu sistemler kurmak mümkündür. Çok sunuculu sistemler, yineleme (=replication) ya da MySQL kümesi (=cluster) ile kurulabilinir. Her birinin kendine göre kazanımları ve yitimleri bulunmaktadır. Bu yazının konusu, bu tür çok sunuculu MySQL sistemlerine istemcilerden ya da uygulamalardan erişimin yükü dengeleyecek şekilde nasıl sağlanabileceğidir. Bunu temel olarak iki şekilde sağlıyoruz:
  1. MySQL Proxy sunucusunu kullanmak
  2. Eğer uygulamalar Java uygulaması ise Connector/J JDBC sürücüsü kullanmak 
Birinci bölümde MySQL Proxy ve ikinci bölümde ise Connector/J çözümlerini sırayla inceleyeceğiz.

I. MySQL Proxy Kullanımı

İlk çözüm, MySQL sunucularına erişimde, istemci ile sunucu arasında vekil sunucu olarak adlandırdığımız MySQL Proxy sunucusu kullanmaktır. Vekil sunucuya çoğunlukla uygulamaların veritabanına erişiminin günlüğünü tutmak, istemcilerin yaptığı işlemlerin güvenlik amacıyla kaydını tutumak, uygulamanın başarımını ölçmek gibi görevler yükleriz. Asıl işi MySQL sunucusu yapmaktadır. Vekil sunucusu temel olarak istemcilerden gelen istekleri sunucuya yönlendirir. Bunu yaparken kendisine yüklenen sorumluluğu da yerine getirir. Vekile yük dengeleme görevi de verilebilinir. MySQL Proxy'nin en güncel sürümü 0.8.3 alpha'dır ve bu bağlantıdan indirebilirsiniz. Bu sürüm MySQL 5.0 ve sonrasındaki tüm sunucularla çalışmaktadır. 
MySQL Proxy içinden hazır olarak yük dengeleme betiği çıkmaktadır. MySQL Proxy programlama dili olarak lua'yı kullanır. Dolayısı ile yeni görevler vermek isterseniz lua dilini kullanarak kod yazmanız gerekir.
Kurulumu yaptığımızda kurulum dizininde aşağıdaki dizinler yer almaktadır:

01/15/2013  03:19 PM    <DIR>          bin
08/06/2012  01:42 PM            18,092 COPYING.txt
01/15/2013  03:19 PM    <DIR>          include
01/15/2013  03:19 PM    <DIR>          lib
01/15/2013  03:19 PM    <DIR>          licenses
08/06/2012  01:42 PM            75,713 README.txt
01/15/2013  03:19 PM    <DIR>          share
Burada bin dizininde vekil sunucusunu çalıştırmamızı sağlayacak uygulama yer alır: mysql-proxy. share\doc\mysql-proxy dizininde ise hazır kullabileceğimiz lua betikleri yer alıyor:

Directory of c:\opt32\mysql-proxy-0.8.3\share\doc\mysql-proxy

active-queries.lua        active-transactions.lua   admin-sql.lua
analyze-query.lua         auditing.lua              commit-obfuscator.lua
histogram.lua             load-multi.lua            ro-balance.lua
ro-pooling.lua            rw-splitting.lua          tutorial-basic.lua
tutorial-constants.lua    tutorial-inject.lua       tutorial-keepalive.lua
tutorial-monitor.lua      tutorial-packets.lua      tutorial-prep-stmts.lua
tutorial-query-time.lua   tutorial-resultset.lua    tutorial-rewrite.lua
tutorial-routing.lua      tutorial-scramble.lua     tutorial-states.lua
tutorial-tokenize.lua     tutorial-union.lua        tutorial-warnings.lua
xtab.lua

Proxy sunucusunu başlatmak için mysql-proxy.exe uygulamasını başlatmak gerekiyor:

cmd> mysql-proxy.exe --daemon --proxy-backend-addresses=192.168.1.1:3306 --proxy-read-only-backend-addresses=192.168.1.2:3306 --proxy-read-only-backend-addresses=192.168.1.3:3306 --proxy-lua-
script=c:\opt32\mysql-proxy-0.8.3\share\doc\mysql-proxy\rw-splitting.lua
2012-04-15 15:47:40: (critical) plugin proxy 0.8.3 started

Bu örnekte bir usta ve iki yamak MySQL sunucusunun olduğu yineleme mimarisi kullanılmıştır. Usta 192.168.1.1 nolu IP adresini, yamaklar ise 192.168.1.2 ve 192.168.1.3 nolu IP adreslerini dinlemektedir. İstemcilerinden gelen SELECT cümlelerini yamaklara ve INSERT/UPDATE/DELETE isteklerini ise ustaya yönlendiren betik rw-splitting.lua isimli dosyada yer almaktadır. Ustanın IP adresini proxy-backend-addresses parametresi ile yamakların IP adresini ise proxy-read-only-backend-addresses parametresi ile veriyoruz. MySQL Proxy 4400 numaralı portta çalışmaktadır. Şimdi sunucuya MySQL istemcisi üzerinden erişebiliriz:

cmd> mysql -uroot -proot --port 4040
Warning: Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.6.10-log MySQL Community Server (GPL)
Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> status
--------------
mysql  Ver 14.14 Distrib 5.6.10, for Win32 (x86)
Connection id:          3
Current database:       world
Current user:           root@localhost
SSL:                    Not in use
Using delimiter:        ;
Server version:         5.6.10-log MySQL Community Server (GPL)
Protocol version:       10
Connection:             localhost via TCP/IP
Server characterset:    latin1
Db     characterset:    latin1
Client characterset:    cp850
Conn.  characterset:    cp850
TCP port:               4040
Uptime:                 9 min 24 sec
Threads: 3  Questions: 18  Slow queries: 0  Opens: 70  Flush tables: 1  Open tab
les: 63  Queries per second avg: 0.031
--------------

Proxy sunucusunun SELECT cümlelerini gerçekten yamaklara gönderdiğini test etmek için Sorgu cebini açıp izleyebilirsiniz:

mysql> show status like 'Qcac%';
+-------------------------+---------+
| Variable_name           | Value   |
+-------------------------+---------+
| Qcache_free_blocks      | 1       |
| Qcache_free_memory      | 1031288 |
| Qcache_hits             | 14      |
| Qcache_inserts          | 5       |
| Qcache_lowmem_prunes    | 0       |
| Qcache_not_cached       | 11      |
| Qcache_queries_in_cache | 4       |
| Qcache_total_blocks     | 10      |
+-------------------------+---------+
8 rows in set (0.00 sec)

II. Connector/J Kullanımı

MySQL sunucuna Java uygulamasından bağlanabilmek için JDBC sürücüsü kullanıyoruz. MySQL bize Connector/J ile bu sürücüyü sağlıyor. Bu sürücünün yeteneklerinden biri de yük dengeleme yapabilmesidir. Üstelik sunucuları dinamik olarak eklemek çıkarılabilmek mümkündür. Sunucuların listesini, JDBC URL tanımında virgüllerle ayırarak veriyoruz:
jdbc:mysql:loadbalance://192.168.1.1:3306,192.168.1.2:3306,192.168.1.3:3306/world
Bu özelliğin kullanıldığı örnek uygulama kodunu aşağıda bulabilirsiniz:
1:  package com.example.test;  
2:  import java.sql.*;  
3:  /**  
4:   *  
5:   * @author Binnur Kurt  
6:   */  
7:  public class TestConnector {  
8:   public static void main(String[] args)   
9:      throws ClassNotFoundException,SQLException,InterruptedException {  
10:    Class.forName("com.mysql.jdbc.Driver");  
11:    int i = 0;  
12:    while (i < 1000) {  
13:     Connection connection = DriverManager.getConnection(  
14:      "jdbc:mysql:loadbalance://192.168.1.1:3306,192.168.1.2:3306, "+  
15:      "192.168.1.3:3306/world?"+  
16:       "loadBalanceConnectionGroup=first&loadBalanceEnableJMX=true",  
17:      "root", "root");  
18:    Statement statement = connection.createStatement();  
19:    ResultSet rs = statement.executeQuery("SELECT * FROM Country limit 10");  
20:    while (rs.next()) {  
21:      String code = rs.getString("Code");  
22:      String name = rs.getString("Name");  
23:      long population = rs.getLong("Population");  
24:      System.err.println(name + "\t" + code + "\t" + population);  
25:    }  
26:    rs.close();  
27:    connection.close();  
28:    Thread.sleep(5000);  
29:    ++i;  
30:   }  
31:   }  
32:  }  
jconsole ile uygulamaya bağlanıp com.mysql.jdbc.jmx'de tanımlı MBean'leri kullanarak yürütme zamanında yeni sunucular eklemek veya sunucu çıkarmak mümkün olabilmektedir:

Tuesday, March 19, 2013

MySQL 5.6'da Çok Ustalı Yineleme (=Multi-Master Replication)

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ı:
  1. G/Ç iş parçası: Ustanın binlog kayıtlarını okumaktan ve yerel diske yazmaktan sorumludur.
  2. 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:
[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 master
                  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: 
  1. Tutarlılık
  2. Her zaman erişilebilirlik
  3. Bölünme bağışıklığı
Bu özelliklerden birinden ödün vermeniz gerekir. Değişik veritabanı ürünleri için CAP teoremine uygun olarak bir sınıflandırma yapan çalışmaya bakmanızda bir fayda var. MySQL çok ustalı yineleme tutarlıktan ödün veriyor. Şimdi tutarlık ile ilgili oluşabilecek problemlere bir kaç tane örnek vereceğim:

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 1Sunucu 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 1Sunucu 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)
Olası çözümler

  1. auto_increment_offset tanımlaması
  2. Çok Ustalı Yineleme Yöneticisi kullanımı
  3. MySQL 5.5 ile beraber gelen yarı-eş zamanlı yineleme 
  4. MySQL 5.6 ile gelen atomik yineleme