Чистый PHP. Реализация протокола репликации MySQL. Это позволяет вам получать такие события, как вставка, обновление, удаление, с их данными и необработанными SQL-запросами.
Основано на великой работе авторов: https://github.com/noplay/python-mysql-replication и https://github.com/fengxiangyun/mysql-replication.
В вашем проекте
composer require krowinski/php-mysql-replication
или автономный
git clone https://github.com/krowinski/php-mysql-replication.git
composer install -o
PHP
MySQL
В файле конфигурации вашего сервера MySQL вам необходимо включить репликацию:
[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
Объяснение событий репликации MySQL https://dev.mysql.com/doc/internals/en/event-meanings.html
Права пользователя MySQL:
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'user'@'host';
GRANT SELECT ON `dbName`.* TO 'user'@'host';
Используйте ConfigBuilder или ConfigFactory для создания конфигурации. Доступные варианты:
'user' - ваш пользователь MySQL (обязательно)
'ip' или 'host' - ваш хост/ip mysql (обязательно)
'пароль' - ваш пароль MySQL (обязательно)
'port' - ваш порт хоста MySQL (по умолчанию 3306)
'charset' - кодировка соединения с БД (по умолчанию utf8)
'gtid' — маркер(ы) GTID, с которых следует начинать (формат 9b1c8d18-2a76-11e5-a26b-000c2976f3f3:1-177592)
'mariaDbGtid' — маркеры GTID MariaDB, с которых нужно начинать (формат 1-1-3,0-1-88)
'slaveId' - идентификатор подчиненного скрипта для идентификации (по умолчанию: 666) (ПОКАЗАТЬ ВЕДОМЫЕ ХОСТЫ)
'binLogFileName' - имя файла журнала bin, с которого нужно начать
'binLogPosition' - позиция журнала бункера, с которой начинается
'eventsOnly' - массив для прослушивания событий (полный список в файле ConstEventType.php)
'eventsIgnore' - массив для игнорирования событий (полный список в файле ConstEventType.php)
'tablesOnly' — массив для прослушивания только определенных таблиц (по умолчанию все таблицы)
'databasesOnly' — массив для прослушивания только определенных баз данных (по умолчанию все базы данных)
'tableCacheSize' — некоторые данные собираются из информационной схемы, эти данные кэшируются.
'custom' - если некоторые параметры должны быть установлены в расширенных/реализованных собственных классах
«heartbeatPeriod» — устанавливает интервал в секундах между тактами репликации. Каждый раз, когда двоичный журнал ведущего устройства обновляется событием, период ожидания следующего контрольного сигнала сбрасывается. интервал — десятичное значение в диапазоне от 0 до 4294967 секунд и разрешение в миллисекундах; наименьшее ненулевое значение равно 0,001. Контрольные сигналы отправляются главным устройством только в том случае, если в двоичном файле журнала нет неотправленных событий в течение периода, превышающего интервал.
'saveUuid' — устанавливает uuid подчиненного устройства для идентификации (по умолчанию: 0015d2b6-8a06-4e5e-8c07-206ef3fbd274)
Руби: https://github.com/y310/kodama.
Java: https://github.com/shyiko/mysql-binlog-connector-java.
ПОЙДИТЕ: https://github.com/siddontang/go-mysql.
Python: https://github.com/noplay/python-mysql-replication
.NET: https://github.com/rusuly/MySqlCdc.
Все примеры доступны в каталоге примеров.
В этом примере все события репликации будут выведены на консоль:
Не забудьте изменить конфигурацию вашего пользователя, хоста и пароля.
Пользователь должен иметь права репликации [REPLICATION CLIENT, SELECT]
php example/dump_events.php
Для тестовых событий SQL:
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 ;
Вывод будет аналогичен этому (зависит от конфигурации, например, выключение/включение GTID):
=== 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
Протестировано на виртуальной машине
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)
Ну, во-первых, MYSQL не дает вам асинхронных вызовов. Обычно вам нужно запрограммировать это в своем приложении (путем диспетчеризации событий и добавления в некоторую систему очередей, и если ваша база данных имеет много точек входа, таких как Интернет, серверная часть других микросервисов, не всегда дешево добавлять обработку ко всем из них. Но используя репликацию MySQL протокол, вы можете прослушивать события записи и затем обрабатывать их асинхронно (лучшее сочетание — добавить элемент в какую-либо систему очередей, например RabbitMQ, Redis или Kafka), а также аннулировать кеш, репликацию поисковых систем, аналитику и аудит в реальном времени.
Ну, во-первых, вам нужно знать, что может произойти много событий, например, если вы обновите 1 000 000 записей в таблице «bar» и вам понадобится одна вставка из вашей таблицы «foo». Тогда все должно быть обработано сценарием, и вам нужно дождаться ваших данных. Это нормально, и так это работает. Вы можете ускориться, используя параметры конфигурации. Кроме того, в случае сбоя сценария вам необходимо время от времени сохранять позицию в форме binlog (или gtid), чтобы начинать с этой позиции при повторном запуске этого сценария, чтобы избежать дублирования.
Как я упоминал в 1 пункте, используйте систему очередей, такую как RabbitMQ, Redis или Kafka, они дадут вам возможность обрабатывать данные в нескольких сценариях.
Создайте задачу, я постараюсь над ней поработать в свободное время :)
Он работает как любой другой MYSQL в подчиненном режиме и дает такие же накладные расходы.
Чтобы это исправить, лучше всего увеличить настройки базы данных net_read_timeout
и net_write_timeout
до 3600. (tx Bijimon)
Установите в my.conf binlog_row_image=full
, чтобы исправить получение только частичных обновлений.
Установите в my.conf log_slave_updates=on
, чтобы исправить это (#71)(#66)
Настройка MYSQL по умолчанию генерирует один большой блок потока, для этого требуется больше ОЗУ/ЦП. Вы можете изменить это на меньший поток, используя переменную 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] для разделения на более мелкие фрагменты