Replicação em tempo real de MySQL para Clickhouse


MySQL e Clickhouse são dois bancos de dados completamente diferentes, ambos com vantagens e desvantagens, e os cenários de negócios aos quais são adequados também são diferentes. No negócio real, precisamos escolher o certo de acordo com as características e vantagens do banco de dados em si. Cena de negócios. Embora o banco de dados MySQL tradicional suporte negócios OLTP muito bem, ainda existem grandes gargalos de desempenho em cenários de negócios, como OLAP, que requerem análise estatística de grandes quantidades de dados. Se quisermos fazer uma melhor análise estatística de BI e consulta nos principais dados de negócios online, devemos enfrentar como sincronizar os dados online com o banco de dados de análise estatística correspondente. A partir de 2020, Clickhouse lançou o mecanismo MaterializeMySQL, que realiza o uso de Clickhouse como um banco de dados escravo de MySQL, sincronização em tempo real de dados MySQL e um salto de OLTP para OLAP.

Próximo Próximo MaterializeMySQL

1.1 Comparação simples entre MySQL e CK

As principais semelhanças e diferenças entre MySQL e Clickhouse são as seguintes:

MySQL Clickhouse
Banco de dados relacional, coisas de suporte Banco de dados de colunas distribuído, não suporta transações
Modo de armazenamento de linha, adequado para ler o mínimo possível de dados de linha O modo de armazenamento de coluna e a alta taxa de compressão de dados têm uma vantagem natural para a leitura de dados em massa
Serviço multi-thread de processo único, uma única consulta de solicitação de negócios não pode utilizar efetivamente vários recursos da CPU Paralelo multi-core
Para negócios OLTP OLAP orientado para o processamento analítico online

1.2 Princípio MaterializeMySQL

No segundo semestre de 2020, a Yandex Company lançou o mecanismo MaterializeMySQL na comunidade ClickHouse, que é usado principalmente para dar suporte à sincronização de dados em tempo real completa e incremental do MySQL. Atualmente suporta a versão MySQL 5.6 / 5.7 / 8.0, compatível com as instruções Delete / Update e as operações DDL mais comumente usadas.

Como todos sabemos, a própria replicação do MySQL depende principalmente do log de transações binlog, e o mecanismo MaterializeMySQL não é exceção. No entanto, a diferença entre a replicação binlog do MySQL nativo é que, devido às diferenças gramaticais entre os dois, MaterializeMySQL não converte as instruções SQL no evento em instruções específicas no CK para execução, mas converte diretamente o evento Binlog no subjacente Estrutura de blocos. Em seguida, ela é gravada diretamente no mecanismo de armazenamento subjacente, que está próximo da replicação física.

Processo de implementação do MaterializeMySQL:

  • MaterializeMySQL oferece suporte à replicação no nível do banco de dados.
  • Depois de criar uma cópia de nível de banco de dados no Clickhouse, o clickhouse se conecta aos dados via TCP / IP por meio de nossa conta de banco de dados designada, executa Flush table com read lock no banco de dados e obtém binlog relacionado e informações de metadados de estrutura de tabela; após os metadados serem copiados Libere o bloqueio global somente leitura e comece a copiar as informações dos dados da tabela por meio de select * from table_name.
  • Para a sincronização de dados incremental subsequente, MaterializeMySQL realiza a sincronização em tempo real por meio da análise do evento binlog (MYSQL_QUERY_EVENT (DDL), MYSQL_WRITE_ROWS_EVENT (inserir), MYSQL_UPDATE_ROWS_EVENT (atualizar), MYSQL_DELETE_ROWS_EVENT (excluir)
  • Para operações DDL, MaterializeMySQL usa a chave primária dos dados da tabela MySQL como a chave de classificação e chave de partição da tabela CK por padrão, mas devido à diferença entre as definições de dados de Clickhouse e MySQL, a instrução DDL também será convertida de acordo
  • Para operações de atualização / exclusão, MaterializeMySQL introduz o campo oculto de _version, que é usado para controle de versão, e combina o campo _sign para marcar a validade dos dados

Quando o MaterializeMySQL cria um canal de replicação, durante a fase de sincronização de inicialização completa, você pode ver os detalhes de execução específicos do MySQL por meio do general_log. Os logs de execução específicos são os seguintes:

2021-03-14T15:40:02.016351+08:00	   26 Connect	[email protected] on ck_test using TCP/IP
2021-03-14T15:40:02.017402+08:00	   26 Query	SET NAMES utf8
2021-03-14T15:40:02.018822+08:00	   26 Query	SHOW VARIABLES WHERE (Variable_name = 'log_bin' AND upper(Value) = 'ON') OR (Variable_name = 'binlog_format' AND upper(Value) = 'ROW') OR (Variable_name = 'binlog_row_image' AND upper(Value) = 'FULL') OR (Variable_name = 'default_authentication_plugin' AND upper(Value) = 'MYSQL_NATIVE_PASSWORD')
2021-03-14T15:40:02.032549+08:00	   26 Query	SELECT version() AS version
2021-03-14T15:40:02.033620+08:00	   26 Query	FLUSH TABLES
2021-03-14T15:40:02.051444+08:00	   26 Query	FLUSH TABLES WITH READ LOCK
2021-03-14T15:40:02.052364+08:00	   26 Query	SHOW MASTER STATUS
2021-03-14T15:40:02.053295+08:00	   26 Query	SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ
2021-03-14T15:40:02.054027+08:00	   26 Query	START TRANSACTION /*!40100 WITH CONSISTENT SNAPSHOT */
2021-03-14T15:40:02.055520+08:00	   26 Query	SELECT TABLE_NAME AS table_name FROM INFORMATION_SCHEMA.TABLES  WHERE TABLE_SCHEMA = 'ck_test'
2021-03-14T15:40:02.057527+08:00	   26 Query	SHOW CREATE TABLE ck_test.t1
2021-03-14T15:40:02.060780+08:00	   26 Query	SHOW CREATE TABLE ck_test.t2
2021-03-14T15:40:02.062275+08:00	   26 Query	UNLOCK TABLES
2021-03-14T15:40:02.075348+08:00	   26 Query	SELECT * FROM ck_test.t2
2021-03-14T15:40:02.101797+08:00	   26 Query	SELECT * FROM ck_test.t1
2021-03-14T15:40:02.106329+08:00	   26 Query	COMMIT
2021-03-14T15:40:02.109026+08:00	   27 Connect	[email protected] on  using TCP/IP
2021-03-14T15:40:02.109637+08:00	   27 Query	SET @master_binlog_checksum = 'CRC32'
2021-03-14T15:40:02.110123+08:00	   27 Query	SET @master_heartbeat_period = 1000000000
2021-03-14T15:40:02.111290+08:00	   27 Binlog Dump GTID	Log: '' Pos: 4 GTIDs: '4a2dfc1c-1f50-11eb-a38b-fa057042bc00:1-53,
a4ec8037-1a70-11eb-91ff-fa9f1ef63700:1-1741042'

2. Replicação em tempo real do MySQL-> CK

1.1 Preparação Ambiental

1 、 MySQL

  • Ative o log binlog e row_format = row
  • Copiar usando o modo gtid
gtid_mode=ON
enforce_gtid_consistency=1
binlog_format=ROW

2 、 Clickhouse

1) Parâmetros ambientais

-- 该参数默认关闭,若需要使用MaterializeMySQL引擎,必须打开该参数
mdw :) set allow_experimental_database_materialize_mysql=1;             

2) Crie um canal de replicação

-- 语法
CREATE DATABASE ${dbname} ENGINE = MaterializeMySQL('${mysql_ip}:${mysql_port}', '${mysql_dbname}', '${mysql_user}', '${mysql_passoword}');

-- 执行SQL
mdw :) CREATE DATABASE ck_test ENGINE = MaterializeMySQL('172.16.104.13:3306', 'ck_test', 'root', '123');

3) Copiar informações

Para obter informações de replicação em tempo real do MySQL, elas são armazenadas no diretório de metadados em datadir.

-- MySQL的binlog位点信息
root@mysql 15:05:  [ck_test]> show master status\G
*************************** 1. row ***************************
             File: mysql-bin.000005
         Position: 4048
     Binlog_Do_DB:
 Binlog_Ignore_DB:
Executed_Gtid_Set: 4a2dfc1c-1f50-11eb-a38b-fa057042bc00:1-37,
a4ec8037-1a70-11eb-91ff-fa9f1ef63700:1-1741042
1 row in set (0.00 sec)

-- Clickhouse复制位点信息
[root@mdw ck_test]# pwd
/data/clickhouse-server/data/metadata/ck_test
[root@mdw ck_test]# cat .metadata
Version:	2
Binlog File:	mysql-bin.000005                                            //binlog文件
Executed GTID:	4a2dfc1c-1f50-11eb-a38b-fa057042bc00:1-37,a4ec8037-1a70-11eb-91ff-fa9f1ef63700:1-1741042        //GTID信息
Binlog Position:	4048                                                    //binlog位点
Data Version:	9                                                           //数据版本信息,全局递增

1.2 Teste de função básica

1. Sincronização de gravação de dados

Para todos os dados do MySQL, haverá campos ocultos _sign e _version correspondentes no CK, que são usados ​​para marcar e consultar o controle de versão. ,

-- MySQL
root@mysql 14:44:  [ck_test]> create table t2(id int primary key not null auto_increment,name varchar(2));
Query OK, 0 rows affected (0.03 sec)

root@mysql 14:45:  [ck_test]> insert into t2 values(null,'aa'),(null,'bb');
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0

root@mysql 14:45:  [ck_test]> select * from t2;
+----+------+
| id | name |
+----+------+
|  1 | aa   |
|  2 | bb   |
+----+------+
2 rows in set (0.01 sec)

-- Clickhouse
mdw :) select * from ck_test.t2 order by id ;

SELECT *
FROM ck_test.t2
ORDER BY id ASC

┌─id─┬─name─┐
│  1 │ aa   │
└────┴──────┘
┌─id─┬─name─┐
│  2 │ bb   │
└────┴──────┘

2 rows in set. Elapsed: 0.009 sec.

-- Clickhouse隐藏字段查询
mdw :) select *,_sign,_version from ck_test.t2 order by id;

SELECT
    *,
    _sign,
    _version
FROM ck_test.t2
ORDER BY id ASC

┌─id─┬─name─┬─_sign─┬─_version─┐
│  1 │ aa   │     1 │        7 │                //一次性写入的_version=7一致,由于是insert操作,_sign=1。
│  2 │ bb   │     1 │        7 │
└────┴──────┴───────┴──────────┘

2 rows in set. Elapsed: 0.003 sec.


2. Atualização de dados

Para a operação de atualização do MySQL, quando consultamos diretamente os dados da tabela CK, podemos ver que os dados da tabela foram "atualizados" normalmente, mas quando consultamos adicionalmente as informações de _sign, _version, podemos descobrir que os dados não foram excluídos fisicamente antes da atualização. Portanto, para a operação de atualização do Clickhouse, o registro alterado é realmente escrito e marcado com _sign = 1, _version = $ {versão atual} +1. Quando executamos a consulta, CK nos ajudará finalmente a retornar como informações de conjunto de resultados normais.

-- MySQL
root@mysql 14:45:  [ck_test]> select * from t2;
+----+------+
| id | name |
+----+------+
|  1 | aa   |
|  2 | bb   |
+----+------+
2 rows in set (0.01 sec)

root@mysql 14:47:  [ck_test]> update t2 set name='aaa' where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

root@mysql 14:47:  [ck_test]> select * from t2;
+----+------+
| id | name |
+----+------+
|  1 | aaa  |
|  2 | bb   |
+----+------+
2 rows in set (0.01 sec)

-- Clickhouse
mdw :) select * from ck_test.t2 order by id ;                   //可以看到,正常的查询,CK已经帮我们做了处理

SELECT *
FROM ck_test.t2
ORDER BY id ASC

┌─id─┬─name─┐
│  1 │ aaa  │
└────┴──────┘
┌─id─┬─name─┐
│  2 │ bb   │
└────┴──────┘

2 rows in set. Elapsed: 0.014 sec.

mdw :) select *,_sign,_version from ck_test.t2 order by id;

SELECT
    *,
    _sign,
    _version
FROM ck_test.t2
ORDER BY id ASC

┌─id─┬─name─┬─_sign─┬─_version─┐
│  1 │ aaa  │     1 │        8 │                                //update更新后的数据被写入ck表,_version+1
└────┴──────┴───────┴──────────┘
┌─id─┬─name─┬─_sign─┬─_version─┐
│  1 │ aa   │     1 │        7 │
│  2 │ bb   │     1 │        7 │
└────┴──────┴───────┴──────────┘

3 rows in set. Elapsed: 0.008 sec.

3. Exclusão de dados

Para a operação Delete, quando consultamos diretamente os dados da tabela CK, podemos ver que os dados da tabela foram "excluídos" normalmente, mas quando consultamos adicionalmente as informações de _sign, _version, podemos descobrir que os dados não foram excluídos fisicamente antes a atualização, e é para adicionar uma nova linha de dados de registro de linha que precisam ser excluídos e marcar _sign = -1, _version = versão atual +1, para a operação de exclusão de ck, o registro não será excluído fisicamente diretamente, mas será excluído por uma marca de sinal. Quando executamos a consulta de consulta, o CK nos ajuda finalmente a retornar às informações normais do conjunto de resultados de acordo com o controle de versão.

-- MySQL
root@mysql 14:47:  [ck_test]> select * from t2;
+----+------+
| id | name |
+----+------+
|  1 | aaa  |
|  2 | bb   |
+----+------+
2 rows in set (0.00 sec)

root@mysql 14:48:  [ck_test]> delete from t2 where id=2;
Query OK, 1 row affected (0.01 sec)

root@mysql 14:48:  [ck_test]> select * from t2;
+----+------+
| id | name |
+----+------+
|  1 | aaa  |
+----+------+
1 row in set (0.01 sec)

-- Clickhouse
mdw :) select * from ck_test.t2 order by id ;                           //query操作正常显示结果集信息

SELECT *
FROM ck_test.t2
ORDER BY id ASC

┌─id─┬─name─┐
│  1 │ aaa  │
└────┴──────┘

1 rows in set. Elapsed: 0.009 sec.

mdw :) select *,_sign,_version from ck_test.t2 order by id;

SELECT
    *,
    _sign,
    _version
FROM ck_test.t2
ORDER BY id ASC

┌─id─┬─name─┬─_sign─┬─_version─┐
│  1 │ aaa  │     1 │        8 │
└────┴──────┴───────┴──────────┘
┌─id─┬─name─┬─_sign─┬─_version─┐
│  1 │ aa   │     1 │        7 │
│  2 │ bb   │    -1 │        9 │                                            //新增删除记录行,并标记_sign=-1表示删除操作
│  2 │ bb   │     1 │        7 │
└────┴──────┴───────┴──────────┘

4 rows in set. Elapsed: 0.008 sec.


4 、 DDL

1) Para as informações da estrutura de dados da tabela CK, uma vez que MaterializeMySQL não suporta a sintaxe show create xx por enquanto, podemos ver as informações da estrutura da tabela criada pelo CK por meio do arquivo físico correspondente.

[root@mdw metadata]# cat ck_test
cat: ck_test: 是一个目录
[root@mdw metadata]# cat ck_test.sql
ATTACH DATABASE ck_test
ENGINE = MaterializeMySQL('172.16.104.13:3306', 'ck_test', 'root', '123')
[root@mdw metadata]# cat ck_test/t2.sql
ATTACH TABLE t2
(
    `id` Int32,
    `name` Nullable(String),
    `_sign` Int8 MATERIALIZED 1,
    `_version` UInt64 MATERIALIZED 1
)
ENGINE = ReplacingMergeTree(_version)
PARTITION BY intDiv(id, 4294967)                                    //分区键、排序键均由MySQL表数据主键继承
ORDER BY tuple(id)
SETTINGS index_granularity = 8192

2) Nova operação DDL de campo

-- MySQL新增表字段
root@mysql 14:48:  [ck_test]> alter table t2 add age int;
Query OK, 0 rows affected (0.07 sec)
Records: 0  Duplicates: 0  Warnings: 0

root@mysql 14:52:  [ck_test]> select * from t2;
+----+------+------+
| id | name | age  |
+----+------+------+
|  1 | aaa  | NULL |
+----+------+------+
1 row in set (0.00 sec)


-- Clickhouse表字段信息
[root@mdw metadata]# cat ck_test/t2.sql
ATTACH TABLE t2
(
    `id` Int32,
    `name` Nullable(String),
    `age` Nullable(Int32),                                          //CK表同步MySQL新增字段,对于ck这种列存储来讲,新增字段的操作还是比较简单的
    `_sign` Int8 MATERIALIZED 1,
    `_version` UInt64 MATERIALIZED 1
)
ENGINE = ReplacingMergeTree(_version)
PARTITION BY intDiv(id, 4294967)
ORDER BY tuple(id)

mdw :) select * from ck_test.t2 order by id ;

SELECT *
FROM ck_test.t2
ORDER BY id ASC

┌─id─┬─name─┬──age─┐
│  1 │ aaa  │ ᴺᵁᴸᴸ │
└────┴──────┴──────┘

1 rows in set. Elapsed: 0.010 sec.

mdw :) select *,_sign,_version from ck_test.t2 order by id;

SELECT
    *,
    _sign,
    _version
FROM ck_test.t2
ORDER BY id ASC

┌─id─┬─name─┬──age─┬─_sign─┬─_version─┐
│  1 │ aa   │ ᴺᵁᴸᴸ │     1 │        7 │
│  1 │ aaa  │ ᴺᵁᴸᴸ │     1 │        8 │
│  2 │ bb   │ ᴺᵁᴸᴸ │    -1 │        9 │
│  2 │ bb   │ ᴺᵁᴸᴸ │     1 │        7 │
└────┴──────┴──────┴───────┴──────────┘

4 rows in set. Elapsed: 0.023 sec.

3. Perguntas e pensamentos de acompanhamento

  • Para que o Clickhouse crie uma replicação, é necessário obter um bloqueio de leitura global e executar uma consulta de varredura de tabela completa da tabela de crescimento, que são algumas operações que consomem muitos recursos. Portanto, ainda é recomendado copiar da biblioteca com binlog e log_slave_updates como a fonte para a replicação ck.
  • Quando ck cria um canal de replicação, as permissões mínimas de usuário do banco de dados necessárias são: SELECT, REPLICATION SLAVE ON .
  • Para negócios OLTP normais, nossas alterações de dados de tabela ainda têm operações de atualização frequentes e ck todos fazem uma operação de inserção redundante. O primeiro ponto que nos preocupa é o desempenho. As atualizações frequentes de dados farão com que o ck consuma muitos recursos e o segundo ponto seja o consumo de espaço em disco. O ck excluirá rapidamente dados inválidos históricos em algumas operações de mesclagem em segundo plano?

Referência do artigo:

A estrada do MySQL ao mecanismo ClickHouse-MaterializeMySQL :
ClickHouse e seus amigos (9) Replicação e implementação em tempo real do MySQL
Documento oficial CK
Clickhouse para Github

Acho que você gosta

Origin blog.csdn.net/weixin_37692493/article/details/114791399
Recomendado
Clasificación