Canal PHP[實戰系列]

豎橫山發表於2023-03-03

官方文件

canal-php

簡介

  • canal server偽裝自己為 MySQL slave ,向 MySQL master 傳送 dump 協議
  • MySQL master 收到 dump 請求,開始推送 binary log 給canal server
  • canal server 解析 binary log 物件(原始為 byte 流)
  • canal client連線上canal server之後可以實時收到MySQL master推送過來的binlog
  • canal server也可以把binlog直接推送到MySQL,Hbase,Es,Mongodb,Redis,RabbitMq,RocketMq

前期準備

我本次測試使用的是phpstudy自帶的mysql8.0.12,需要先開啟 Binlog 寫入功能,配置 binlog-format 為 ROW 模式,my.cnf 中配置如下,phpstudy預設配置就是這樣,不用修改

[mysqld]
log-bin=mysql-bin # 開啟 binlog
binlog-format=ROW # 選擇 ROW 模式
server_id=1 # 配置 MySQL replaction 需要定義,不要和 canal 的 slaveId 重複

授權 canal 連結 MySQL 賬號具有作為 MySQL slave 的許可權, 如果已有賬戶可直接 grant

CREATE USER canal IDENTIFIED BY 'canal';  
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';
-- GRANT ALL PRIVILEGES ON *.* TO 'canal'@'%' ;
FLUSH PRIVILEGES;

安裝Canal Server

我這裡選擇用docker安裝

//下載指令碼
# wget https://raw.githubusercontent.com/alibaba/canal/master/docker/run.sh 
//賦予許可權
# chmod +x run.sh
//構建一個destination name為test的佇列
./run.sh 
-e canal.auto.scan=false 
-e canal.destinations=test 
-e canal.instance.master.address=127.0.0.1:3306 
-e canal.instance.dbUsername=canal  
-e canal.instance.dbPassword=canal  
-e canal.instance.connectionCharset=UTF-8 
-e canal.instance.tsdb.enable=true 
-e canal.instance.gtidon=false  

指令碼會docker pull最新的canal/canal-server映象
Canal PHP實戰
讓我們稍微等幾年看看什麼情況…

Canal PHP實戰
容器跑起來了,預設埠是11111,destinations是test

啟動Canal-client

  • 獲取canal-client

    composer require xingwenge/canal_php
  • 新建canal.php

    <?php
    namespace xingwenge\canal_php\sample;
    use xingwenge\canal_php\CanalClient;
    use xingwenge\canal_php\CanalConnectorFactory;
    use xingwenge\canal_php\Fmt;
    require_once './vendor/autoload.php';
    ini_set('display_errors', 'On');
    error_reporting(E_ALL);
    try {
      $client = CanalConnectorFactory::createClient(CanalClient::TYPE_SOCKET_CLUE);
      # $client = CanalConnectorFactory::createClient(CanalClient::TYPE_SWOOLE);
      $client->connect("127.0.0.1", 11111);
      $client->checkValid();
      $client->subscribe("1001", "test", ".*\\..*");
      # $client->subscribe("1001", "test", "db_name.tb_name"); # 指定某個庫某個表
      while (true) {
          $message = $client->get(100);
          if ($entries = $message->getEntries()) {
              foreach ($entries as $entry) {
                  Fmt::println($entry);
              }
          }
          sleep(1);
      }
      $client->disConnect();
    } catch (\Exception $e) {
      echo $e->getMessage(), PHP_EOL;
    }
  • 執行canal.php
    去資料庫改幾條資料看看
    Canal PHP實戰
    收到binlog訊息

  • 實戰成功

什麼時候可以使用Canal

mysql和es,redis,mongdb資訊同步

可以不用在應用層加程式碼就可以實現資料同步

mysql 不停機舊錶遷移新表
1.canal-server開始監聽舊錶table的binlog,儲存到日誌檔案canal.log(也可以存到mq)
2.mysqldump備份舊錶生成table.sql,記錄執行mysqldump的大概時間
3.寫程式碼按新的規則匯入table.sql到新表table_new
4.寫程式碼按新的規則消費canal.log到新表table_new(取mysqldump之後的log)
5.比較兩個表資料是否一致
6.停止消費canal.log
7.原子操作換名
RENAME TABLE `table` TO `table_old`, `table_new` TO `table`
8.寫程式碼按新的規則繼續消費canal.log到table(如果canal.log還有沒有同步完的操作)
9.刪除table_old
10.評論區有沒有更好的方式,求留言
本作品採用《CC 協議》,轉載必須註明作者和本文連結
遇強則強,太強另說

相關文章