Implementação em PHP puro do protocolo de replicação MySQL. Isso permite que você receba eventos como inserir, atualizar, excluir com seus dados e consultas SQL brutas.
Baseado em um excelente trabalho de criadores: https://github.com/noplay/python-mysql-replication e https://github.com/fengxiangyun/mysql-replication
Em seu projeto
composer require krowinski/php-mysql-replication
ou autônomo
git clone https://github.com/krowinski/php-mysql-replication.git
composer install -o
PHP
MySQL
No arquivo de configuração do servidor MySQL você precisa habilitar a replicação:
[mysqld]
server-id = 1
log_bin = /var/log/mysql/mysql-bin.log
expire_logs_days = 10
max_binlog_size = 100M
binlog-format = row #Very important if you want to receive write, update and delete row events
Eventos de replicação Mysql explicados https://dev.mysql.com/doc/internals/en/event-meanings.html
Privilégios de usuário MySQL:
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'user'@'host';
GRANT SELECT ON `dbName`.* TO 'user'@'host';
Use ConfigBuilder ou ConfigFactory para criar configuração. Opções disponíveis:
'user' - seu usuário mysql (obrigatório)
'ip' ou 'host' - seu host/ip mysql (obrigatório)
'password' - sua senha mysql (obrigatório)
'porta' - sua porta de host mysql (padrão 3306)
'charset' - charset de conexão db (padrão utf8)
'gtid' - marcador(es) GTID para começar (formato 9b1c8d18-2a76-11e5-a26b-000c2976f3f3:1-177592)
'mariaDbGtid' - marcador(es) MariaDB GTID para começar (formato 1-1-3,0-1-88)
'slaveId' - script escravo id para identificação (padrão: 666) (SHOW SLAVE HOSTS)
'binLogFileName' - nome do arquivo de log bin para começar
'binLogPosition' - posição do log bin para começar
'eventsOnly' - array para escutar eventos (lista completa no arquivo ConstEventType.php)
'eventsIgnore' - array para ignorar eventos (lista completa no arquivo ConstEventType.php)
'tablesOnly' - array para escutar apenas em determinadas tabelas (padrão todas as tabelas)
'databasesOnly' - array para escutar apenas em determinados bancos de dados (padrão todos os bancos de dados)
'tableCacheSize' - alguns dados são coletados do esquema de informações, esses dados são armazenados em cache.
'custom' - se alguns parâmetros devem ser definidos em classes próprias estendidas/implementadas
'heartbeatPeriod' - define o intervalo em segundos entre as pulsações de replicação. Sempre que o log binário do mestre é atualizado com um evento, o período de espera para a próxima pulsação é redefinido. intervalo é um valor decimal com intervalo de 0 a 4294967 segundos e resolução em milissegundos; o menor valor diferente de zero é 0,001. As pulsações são enviadas pelo mestre somente se não houver eventos não enviados no arquivo de log binário por um período maior que o intervalo.
'saveUuid' - define o uuid escravo para identificação (padrão: 0015d2b6-8a06-4e5e-8c07-206ef3fbd274)
Rubi: https://github.com/y310/kodama
Java: https://github.com/shyiko/mysql-binlog-connector-java
ACESSE: https://github.com/siddontang/go-mysql
Python: https://github.com/noplay/python-mysql-replication
.NET: https://github.com/rusuly/MySqlCdc
Todos os exemplos estão disponíveis no diretório de exemplos
Este exemplo irá despejar todos os eventos de replicação no console:
Lembre-se de alterar a configuração do seu usuário, host e senha.
O usuário deve ter privilégios de replicação [REPLICATION CLIENT, SELECT]
php example/dump_events.php
Para eventos SQL de teste:
CREATE DATABASE php_mysql_replication ;
use php_mysql_replication;
CREATE TABLE test4 (id int NOT NULL AUTO_INCREMENT, data VARCHAR ( 255 ), data2 VARCHAR ( 255 ), PRIMARY KEY (id));
INSERT INTO test4 (data,data2) VALUES ( " Hello " , " World " );
UPDATE test4 SET data = " World " , data2 = " Hello " WHERE id = 1 ;
DELETE FROM test4 WHERE id = 1 ;
A saída será semelhante a esta (depende da configuração, por exemplo, GTID ativado/desativado):
=== Event format description ===
Date: 2017-07-06T13:31:11+00:00
Log position: 0
Event size: 116
Memory usage 2.4 MB
=== Event gtid ===
Date: 2017-07-06T15:23:44+00:00
Log position: 57803092
Event size: 48
Commit: true
GTID NEXT: 3403c535-624f-11e7-9940-0800275713ee:13675
Memory usage 2.42 MB
=== Event query ===
Date: 2017-07-06T15:23:44+00:00
Log position: 57803237
Event size: 145
Database: php_mysql_replication
Execution time: 0
Query: CREATE DATABASE php_mysql_replication
Memory usage 2.45 MB
=== Event gtid ===
Date: 2017-07-06T15:23:44+00:00
Log position: 57803285
Event size: 48
Commit: true
GTID NEXT: 3403c535-624f-11e7-9940-0800275713ee:13676
Memory usage 2.45 MB
=== Event query ===
Date: 2017-07-06T15:23:44+00:00
Log position: 57803500
Event size: 215
Database: php_mysql_replication
Execution time: 0
Query: CREATE TABLE test4 (id int NOT NULL AUTO_INCREMENT, data VARCHAR(255), data2 VARCHAR(255), PRIMARY KEY(id))
Memory usage 2.45 MB
=== Event gtid ===
Date: 2017-07-06T15:23:44+00:00
Log position: 57803548
Event size: 48
Commit: true
GTID NEXT: 3403c535-624f-11e7-9940-0800275713ee:13677
Memory usage 2.45 MB
=== Event query ===
Date: 2017-07-06T15:23:44+00:00
Log position: 57803637
Event size: 89
Database: php_mysql_replication
Execution time: 0
Query: BEGIN
Memory usage 2.45 MB
=== Event tableMap ===
Date: 2017-07-06T15:23:44+00:00
Log position: 57803708
Event size: 71
Table: test4
Database: php_mysql_replication
Table Id: 866
Columns amount: 3
Memory usage 2.71 MB
=== Event write ===
Date: 2017-07-06T15:23:44+00:00
Log position: 57803762
Event size: 54
Table: test4
Affected columns: 3
Changed rows: 1
Values: Array
(
[0] => Array
(
[id] => 1
[data] => Hello
[data2] => World
)
)
Memory usage 2.74 MB
=== Event xid ===
Date: 2017-07-06T15:23:44+00:00
Log position: 57803793
Event size: 31
Transaction ID: 662802
Memory usage 2.75 MB
=== Event gtid ===
Date: 2017-07-06T15:23:44+00:00
Log position: 57803841
Event size: 48
Commit: true
GTID NEXT: 3403c535-624f-11e7-9940-0800275713ee:13678
Memory usage 2.75 MB
=== Event query ===
Date: 2017-07-06T15:23:44+00:00
Log position: 57803930
Event size: 89
Database: php_mysql_replication
Execution time: 0
Query: BEGIN
Memory usage 2.76 MB
=== Event tableMap ===
Date: 2017-07-06T15:23:44+00:00
Log position: 57804001
Event size: 71
Table: test4
Database: php_mysql_replication
Table Id: 866
Columns amount: 3
Memory usage 2.75 MB
=== Event update ===
Date: 2017-07-06T15:23:44+00:00
Log position: 57804075
Event size: 74
Table: test4
Affected columns: 3
Changed rows: 1
Values: Array
(
[0] => Array
(
[before] => Array
(
[id] => 1
[data] => Hello
[data2] => World
)
[after] => Array
(
[id] => 1
[data] => World
[data2] => Hello
)
)
)
Memory usage 2.76 MB
=== Event xid ===
Date: 2017-07-06T15:23:44+00:00
Log position: 57804106
Event size: 31
Transaction ID: 662803
Memory usage 2.76 MB
=== Event gtid ===
Date: 2017-07-06T15:23:44+00:00
Log position: 57804154
Event size: 48
Commit: true
GTID NEXT: 3403c535-624f-11e7-9940-0800275713ee:13679
Memory usage 2.76 MB
=== Event query ===
Date: 2017-07-06T15:23:44+00:00
Log position: 57804243
Event size: 89
Database: php_mysql_replication
Execution time: 0
Query: BEGIN
Memory usage 2.76 MB
=== Event tableMap ===
Date: 2017-07-06T15:23:44+00:00
Log position: 57804314
Event size: 71
Table: test4
Database: php_mysql_replication
Table Id: 866
Columns amount: 3
Memory usage 2.76 MB
=== Event delete ===
Date: 2017-07-06T15:23:44+00:00
Log position: 57804368
Event size: 54
Table: test4
Affected columns: 3
Changed rows: 1
Values: Array
(
[0] => Array
(
[id] => 1
[data] => World
[data2] => Hello
)
)
Memory usage 2.77 MB
=== Event xid ===
Date: 2017-07-06T15:23:44+00:00
Log position: 57804399
Event size: 31
Transaction ID: 662804
Memory usage 2.77 MB
Testado em VM
Debian 8.7
PHP 5.6.30
Percona 5.6.35
inxi
CPU(s)~4 Single core Intel Core i5-2500Ks (-SMP-) clocked at 5901 Mhz Kernel~3.16.0-4-amd64 x86_64 Up~1 day Mem~1340.3/1996.9MB HDD~41.9GB(27.7% used) Procs~122 Client~Shell inxi~2.1.28
php example/benchmark.php
Start insert data
7442 event by seconds (1000 total)
7679 event by seconds (2000 total)
7914 event by seconds (3000 total)
7904 event by seconds (4000 total)
7965 event by seconds (5000 total)
8006 event by seconds (6000 total)
8048 event by seconds (7000 total)
8038 event by seconds (8000 total)
8040 event by seconds (9000 total)
8055 event by seconds (10000 total)
8058 event by seconds (11000 total)
8071 event by seconds (12000 total)
Bem, antes de mais nada, o MYSQL não oferece chamadas assíncronas. Você geralmente precisa programar isso em seu aplicativo (despachando eventos e adicionando a algum sistema de filas e se seu banco de dados tiver muitos pontos de entrada como web, back-end de outros microsserviços nem sempre é barato adicionar processamento a todos eles. Mas usando a replicação mysql protocolo, você pode ouvir eventos de gravação e processá-los de forma assíncrona (a melhor combinação é adicionar itens a algum sistema de filas como RabbitMQ, Redis ou Kafka). Também invalida cache, replicação de mecanismo de pesquisa, análises e auditorias em tempo real.
Bem, antes de tudo você precisa saber que muitos eventos podem ocorrer, como se você atualizasse 1.000.000 de registros na tabela "bar" e precisasse desta inserção da sua tabela "foo". e você precisa aguardar seus dados. Isso é normal e é assim que funciona. Você pode acelerar usando opções de configuração. Além disso, se o script travar, você precisará salvar de vez em quando a posição do formulário binlog (ou gtid) para iniciar a partir desta posição ao executar este script novamente para evitar duplicatas.
Como mencionei no sistema de fila de uso de 1 ponto, como RabbitMQ, Redis ou Kafka, eles permitirão processar dados em vários scripts.
Crie um problema que tentarei trabalhar nele no meu tempo livre :)
Funciona como qualquer outro MYSQL no modo escravo e dá a mesma sobrecarga.
Para corrigir isso, é melhor aumentar as configurações do banco de dados net_read_timeout
e net_write_timeout
para 3600. (tx Bijimon)
Definido em my.conf binlog_row_image=full
para corrigir o recebimento apenas de atualizações parciais.
Defina em my.conf log_slave_updates=on
para corrigir isso (#71)(#66)
A configuração padrão do MYSQL gera um grande blob de fluxo, o que requer mais RAM/CPU. Você pode alterar isso para fluxo menor usando a variável binlog_row_event_max_size
[https://dev.mysql.com/doc/refman/8.0/en/replication-options-binary- log.html#sysvar_binlog_row_event_max_size] para dividir em pedaços menores