背景:

随着数据量的上升,OLAP一直是被讨论的话题,虽然druid,kylin能够解决OLAP问题,但是druid,kylin也是需要和hadoop全家桶一起用的,异常的笨重,再说我也搞不定,那只能找我能搞定的技术。故引进clickhoue,关于clickhoue在17年本人就开始关注,并且写了一些入门的介绍,直到19年clickhoue功能慢慢的丰富才又慢慢的关注,并且编写了同步程序,把mysql数据实时同步到clickhoue,并且最终在线上使用起来。

关于clickhouse是什么请自行查阅官网:https://clickhouse.yandex/

clickhouse官方性能测试:https://clickhouse.yandex/benchmark.html

clickhouse面对海量数据,比如单表过百亿可以使用集群(复制+分片),如果数据量比较小,比如单表10-20亿使用单机就足以满足查询需求。如果使用复制需要使用zk,更多集群的请自行查阅官方资料。

单机部署(以前的文章也有写过单机部署) :

在2016年clickhouse刚开始开源的时候对Ubuntu支持非常友好,一个apt命令就可以安装了。对于centos等系统 支持就比较差,需要自己编译,而且不一定能够成功。随着使用人群的扩大,目前对于centos支持也是非常的友好 了,有rpm包可以直接安装。甚至目前Altinity公司已经制作了yum源,添加源之后直接yum安装完成。这个在官方 文档里面也有提到,参考: https://clickhouse.yandex/docs/en/getting_started/ https://github.com/Altinity/clickhouse-rpm-install 。目前线上使用的是centos 7.0的系统。之所以使用7.0的系统是因为同步数据的程序是用python写的,而且用到的 一个核心包:python-mysql-replication需要使用python 2.7的环境。同时由于clickhouse不兼容mysql协议,为了方便开发接入系统不用过多更改代码,引入了proxysql兼容mysql协议,clickhouse最新版本已经支持mysql协议,支持clickhouse的proxysql也需要python 2.7的环境,所以干脆直接用centos 7.0系统

测试环境:
服务器数量:1台
操作系统:centos 7.1
安装服务:clickhouse,mysql
安装mysql是测试clickhouse从mysql同步数据。

clickhouse安装:

添加yum源

curl -s https://packagecloud.io/install/repositories/altinity/clickhouse/script.rpm.sh | sudo bash

yum安装

yum install -y clickhouse-server clickhouse-client

服务启动

/etc/init.d/clickhouse-server start

默认数据存放位置是: /var/lib/clickhouse/

登录,查看数据库(默认用户是default,密码为空)

[root@ck-server- sync]# clickhouse-client -h 127.0.0.1
ClickHouse client version 19.9.2.4.
Connecting to 127.0.0.1: as user default.
Connected to ClickHouse server version 19.9. revision . ck-server- :) show databases; SHOW DATABASES ┌─name────┐
│ default │
│ system │
└─────────┘ rows in set. Elapsed: 0.003 sec. ck-server- :)

default数据库里面没有任何东西,和mysql里面的test库是一样的。system库看名字就知道是什么。到这里clickhouse就部署完成,是不是很简单?

补充一点,在官方的文档里面有几点建议:
1. 关闭大页
2. 调整内存使用
3. 关闭cpu节能模式

echo 'performance' | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
echo > /proc/sys/vm/overcommit_memory
echo 'never' > /sys/kernel/mm/transparent_hugepage/enabled

mysql部署请自行部署。这里不做介绍。如果想从mysql同步数据那么binlog 格式必须是row。而且必须binlog_row_image=full

安装同步程序依赖的包;同步程序可以放在clickhouse服务器上面,也可以单独放在其他服务器。同步程序使用pypy启动,所以安装包的时候需要安装pypy的包。

yum -y install pypy-libs pypy pypy-devel
wget https://bootstrap.pypa.io/get-pip.py
pypy get-pip.py
/usr/lib64/pypy-5.0./bin/pip install MySQL-python
/usr/lib64/pypy-5.0./bin/pip install mysql-replication
/usr/lib64/pypy-5.0./bin/pip install clickhouse-driver
/usr/lib64/pypy-5.0./bin/pip install redis

这里也安装了redis模块是因为同步的binlog pos可以存放在redis里面,当然程序也是支持存放在文件里面

proxysql安装(主要是为了clickhouse兼容mysql协议): proxysql在这里下载:https://github.com/sysown/proxysql/releases 选择带clickhouse的包下载,否则不会支持clickhouse。ps:较新版本的clickhouse已经原生兼容mysql协议。

proxysql安装及配置

rpm -ivh proxysql-2.0.--clickhouse-centos7.x86_64.rpm

启动(必须这样启动,否则是不支持clickhouse的):

proxysql --clickhouse-server

登录proxysql,设置账户:

mysql -uadmin -padmin -h127.0.0.1 -P6032
INSERT INTO clickhouse_users VALUES ('clicku','clickp',1,100);
LOAD CLICKHOUSE USERS TO RUNTIME;
SAVE CLICKHOUSE USERS TO DISK;

使用proxysql连接到clickhouse:

[root@ck-server- sync]# mysql -u clicku -pclickp -h 127.0.0.1 -P6090
mysql: [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
Server version: 5.5. (ProxySQL ClickHouse Module) Copyright (c) , , 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> show databases;
+---------+
| name |
+---------+
| default |
| system |
+---------+

mysql同步数据到clickhouse

mysql里面有个库yayun,库里面有张表tb1,同步这张表到clickhoue

mysql> use yayun;
Database changed
mysql> show create table tb1\G
*************************** 1. row ***************************
Table: tb1
Create Table: CREATE TABLE `tb1` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`pay_money` decimal(20,2) NOT NULL DEFAULT '0.00',
`pay_day` date NOT NULL,
`pay_time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

1. clickhoue里面建库,建表。

ck-server-01 :) create database yayun;

CREATE DATABASE yayun

Ok.

0 rows in set. Elapsed: 0.021 sec. 

ck-server-01 :) 

2. 建表(clickhouse建表的格式以及字段类型和mysql完全不一样,如果字段少还可以自己建,如果字段多比较痛苦,可以使用clickhouse自带的从mysql导数据的命令来建表),在建表之前需要进行授权,因为程序同步也是模拟一个从库拉取数据.

GRANT REPLICATION SLAVE, REPLICATION CLIENT, SELECT ON *.* TO 'ch_repl'@'127.0.0.1' identified by '';

3. 登陆clickhouse进行建表

ck-server-01 :) use yayun;

USE yayun

Ok.

0 rows in set. Elapsed: 0.001 sec. 

ck-server-01 :) CREATE TABLE tb1
:-] ENGINE = MergeTree
:-] PARTITION BY toYYYYMM(pay_time)
:-] ORDER BY (pay_time) AS
:-] SELECT *
:-] FROM mysql('127.0.0.1:3306', 'yayun', 'tb1', 'ch_repl', '') ; CREATE TABLE tb1
ENGINE = MergeTree
PARTITION BY toYYYYMM(pay_time)
ORDER BY pay_time AS
SELECT *
FROM mysql('127.0.0.1:3306', 'yayun', 'tb1', 'ch_repl', '') Ok. 0 rows in set. Elapsed: 0.031 sec.

这里使用MergeTree引擎,MergeTree是clickhouse里面最牛逼的引擎,支持海量数据,支持索引,支持分区,支持更新删除。toYYYYMM(pay_time)的意思是根据pay_time分区,粒度是按月。ORDER BY (pay_time)的意思是根据pay_time排序存储,同时也是索引。上面的create table命令如果mysql表里面以后数据那么数据也会一并进入clickhouse里面。通常会limit 1,然后更改一下表结构。上面没有报错的话我们看看clickhouse里面的表结构:

ck-server-01 :) show create table tb1;

SHOW CREATE TABLE tb1

┌─statement────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ CREATE TABLE yayun.tb1 (`id` UInt32, `pay_money` String, `pay_day` Date, `pay_time` DateTime) ENGINE = MergeTree PARTITION BY toYYYYMM(pay_time) ORDER BY pay_time SETTINGS index_granularity = 8192 │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ 1 rows in set. Elapsed: 0.002 sec.

其中这里的index_granularity = 8192是指索引的粒度。如果数据量没有达到百亿,那么通常无需更改。表结构也创建完成以后现在配置同步程序配置文件:metainfo.conf

[root@ck-server- sync]# cat metainfo.conf
# 从这里同步数据
[master_server]
host='127.0.0.1'
port=
user='ch_repl'
passwd=''
server_id= # redis配置信息,用于存放pos点
[redis_server]
host='127.0.0.1'
port=
passwd=''
log_pos_prefix='log_pos_' #把log_position记录到文件
[log_position]
file='./repl_pos.log' # ch server信息,数据同步以后写入这里
[clickhouse_server]
host=127.0.0.1
port=
passwd=''
user='default'
#字段大小写. 1是大写,0是小写
column_lower_upper= # 需要同步的数据库
[only_schemas]
schemas='yayun' # 需要同步的表
[only_tables]
tables='tb1' # 指定库表跳过DML语句(update,delete可选)
[skip_dmls_sing]
skip_delete_tb_name = ''
skip_update_tb_name = '' #跳过所有表的DML语句(update,delete可选)
[skip_dmls_all]
#skip_type = 'delete'
#skip_type = 'delete,update'
skip_type = '' [bulk_insert_nums]
#多少记录提交一次
insert_nums=
#选择每隔多少秒同步一次,负数表示不启用,单位秒
interval= # 同步失败告警收件人
[failure_alarm]
mail_host= 'xxx'
mail_port=
mail_user= 'xxx'
mail_pass= 'xxx'
mail_send_from = 'xxx'
alarm_mail = 'xxx' #日志存放路径
[repl_log]
log_dir="/tmp/relication_mysql_clickhouse.log"

设置pos点:
和mysql搭建从库一样,配置从哪里开始同步,看mysql的pos点:

mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000069 | 4024404 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

把pos点写入文件或者redis,我选择记录到文件就是。

[root@ck-server- sync]# cat repl_pos.log
[log_position]
filename = mysql-bin.
position = [root@ck-server- sync]#

启动同步程序:

[root@ck-server- sync]# pypy mysql-clickhouse-replication.py --help
usage: Data Replication to clikhouse [-h] [-c CONF] [-d] [-l] mysql data is copied to clikhouse optional arguments:
-h, --help show this help message and exit
-c CONF, --conf CONF Data synchronization information file
-d, --debug Display SQL information
-l, --logtoredis log position to redis ,default file By dengyayun @
[root@ck-server- sync]#

默认pos点就是记录文件,无需再指定记录binlog pos方式

[root@ck-server- sync]# pypy mysql-clickhouse-replication.py --conf metainfo.conf --debug
:: INFO 开始同步数据时间 -- ::
:: INFO 从服务器 127.0.0.1: 同步数据
:: INFO 读取binlog: mysql-bin.:
:: INFO 同步到clickhouse server 127.0.0.1:
:: INFO 同步到clickhouse的数据库: ['yayun']
:: INFO 同步到clickhouse的表: ['tb1']

mysql插入10条数据:

mysql> insert into  tb1 (pay_money,pay_day,pay_time)values('66.22','2019-06-29','2019-06-29 14:00:00'),('66.22','2019-06-29','2019-06-29 14:00:00'),('66.22','2019-06-29','2019-06-29 14:00:00'),('66.22','2019-06-29','2019-06-29 14:00:00'),('66.22','2019-06-29','2019-06-29 14:00:00'),('66.22','2019-06-29','2019-06-29 14:00:00'),('66.22','2019-06-29','2019-06-29 14:00:00'),('66.22','2019-06-29','2019-06-29 14:00:00'),('66.22','2019-06-29','2019-06-29 14:00:00'),('66.22','2019-06-29','2019-06-29 14:00:00') ;
Query OK, 10 rows affected (0.01 sec)
Records: 10 Duplicates: 0 Warnings: 0 mysql> select * from tb1;
+----+-----------+------------+---------------------+
| id | pay_money | pay_day | pay_time |
+----+-----------+------------+---------------------+
| 1 | 66.22 | 2019-06-29 | 2019-06-29 14:00:00 |
| 3 | 66.22 | 2019-06-29 | 2019-06-29 14:00:00 |
| 5 | 66.22 | 2019-06-29 | 2019-06-29 14:00:00 |
| 7 | 66.22 | 2019-06-29 | 2019-06-29 14:00:00 |
| 9 | 66.22 | 2019-06-29 | 2019-06-29 14:00:00 |
| 11 | 66.22 | 2019-06-29 | 2019-06-29 14:00:00 |
| 13 | 66.22 | 2019-06-29 | 2019-06-29 14:00:00 |
| 15 | 66.22 | 2019-06-29 | 2019-06-29 14:00:00 |
| 17 | 66.22 | 2019-06-29 | 2019-06-29 14:00:00 |
| 19 | 66.22 | 2019-06-29 | 2019-06-29 14:00:00 |

同步程序日志输出:

[root@ck-server- sync]# pypy mysql-clickhouse-replication.py --conf metainfo.conf --debug
:: INFO 开始同步数据时间 -- ::
:: INFO 从服务器 127.0.0.1: 同步数据
:: INFO 读取binlog: mysql-bin.:
:: INFO 同步到clickhouse server 127.0.0.1:
:: INFO 同步到clickhouse的数据库: ['yayun']
:: INFO 同步到clickhouse的表: ['tb1']
:: INFO INSERT 数据插入SQL: INSERT INTO yayun.tb1 VALUES, [{u'id': , u'pay_money': '66.22', u'pay_day': datetime.date(, , ), u'pay_time': datetime.datetime(, , , , )}, {u'id': , u'pay_money': '66.22', u'pay_day': datetime.date(, , ), u'pay_time': datetime.datetime(, , , , )}, {u'id': , u'pay_money': '66.22', u'pay_day': datetime.date(, , ), u'pay_time': datetime.datetime(, , , , )}, {u'id': , u'pay_money': '66.22', u'pay_day': datetime.date(, , ), u'pay_time': datetime.datetime(, , , , )}, {u'id': , u'pay_money': '66.22', u'pay_day': datetime.date(, , ), u'pay_time': datetime.datetime(, , , , )}, {u'id': , u'pay_money': '66.22', u'pay_day': datetime.date(, , ), u'pay_time': datetime.datetime(, , , , )}, {u'id': , u'pay_money': '66.22', u'pay_day': datetime.date(, , ), u'pay_time': datetime.datetime(, , , , )}, {u'id': , u'pay_money': '66.22', u'pay_day': datetime.date(, , ), u'pay_time': datetime.datetime(, , , , )}, {u'id': , u'pay_money': '66.22', u'pay_day': datetime.date(, , ), u'pay_time': datetime.datetime(, , , , )}, {u'id': , u'pay_money': '66.22', u'pay_day': datetime.date(, , ), u'pay_time': datetime.datetime(, , , , )}]

clickhoue数据查询:

ck-server-01 :) select * from tb1;

SELECT *
FROM tb1 ┌─id─┬─pay_money─┬────pay_day─┬────────────pay_time─┐
│ 1 │ 66.22 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 3 │ 66.22 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 5 │ 66.22 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 7 │ 66.22 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 9 │ 66.22 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 11 │ 66.22 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 13 │ 66.22 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 15 │ 66.22 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 17 │ 66.22 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 19 │ 66.22 │ 2019-06-29 │ 2019-06-29 14:00:00 │
└────┴───────────┴────────────┴─────────────────────┘ 10 rows in set. Elapsed: 0.005 sec.

mysql数据更新:

mysql> update tb1 set pay_money='88.88';
Query OK, 10 rows affected (0.00 sec)
Rows matched: 10 Changed: 10 Warnings: 0 mysql> select * from tb1;
+----+-----------+------------+---------------------+
| id | pay_money | pay_day | pay_time |
+----+-----------+------------+---------------------+
| 1 | 88.88 | 2019-06-29 | 2019-06-29 14:00:00 |
| 3 | 88.88 | 2019-06-29 | 2019-06-29 14:00:00 |
| 5 | 88.88 | 2019-06-29 | 2019-06-29 14:00:00 |
| 7 | 88.88 | 2019-06-29 | 2019-06-29 14:00:00 |
| 9 | 88.88 | 2019-06-29 | 2019-06-29 14:00:00 |
| 11 | 88.88 | 2019-06-29 | 2019-06-29 14:00:00 |
| 13 | 88.88 | 2019-06-29 | 2019-06-29 14:00:00 |
| 15 | 88.88 | 2019-06-29 | 2019-06-29 14:00:00 |
| 17 | 88.88 | 2019-06-29 | 2019-06-29 14:00:00 |
| 19 | 88.88 | 2019-06-29 | 2019-06-29 14:00:00 |
+----+-----------+------------+---------------------+
10 rows in set (0.00 sec)

clickhoue数据查询:

ck-server-01 :) select * from tb1;

SELECT *
FROM tb1 ┌─id─┬─pay_money─┬────pay_day─┬────────────pay_time─┐
│ 1 │ 88.88 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 3 │ 88.88 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 5 │ 88.88 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 7 │ 88.88 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 9 │ 88.88 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 11 │ 88.88 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 13 │ 88.88 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 15 │ 88.88 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 17 │ 88.88 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 19 │ 88.88 │ 2019-06-29 │ 2019-06-29 14:00:00 │
└────┴───────────┴────────────┴─────────────────────┘ 10 rows in set. Elapsed: 0.009 sec.

可以看见数据都同步完成。

代码地址:

https://github.com/yymysql/mysql-clickhouse-replication

总结:

目前线上报表业务都已经在使用clickhoue,数据同步采用自行开发的同步程序进行同步。目前数据一致性没有什么问题。当然同步的表需要有自增主键,否则有些情况比较难处理。延时也比较小。数据的延时以及数据的一致性都有监控。

总体来说使用clickhoue处理olap还是非常不错的选择,小伙伴们可以尝试。

参考资料

https://clickhouse-driver.readthedocs.io/en/latest/
https://python-mysql-replication.readthedocs.io/en/latest/examples.html
https://clickhouse.yandex/docs/en/
https://github.com/sysown/proxysql/wiki/ClickHouse-Support

最新文章

  1. axure快速原型设计工具
  2. HTTP协议用的TCP但是只建立单向连接
  3. Python3利用BeautifulSoup4批量抓取站点图片的代码
  4. Linux useful command
  5. mac 无法连接android手机进行调试 解决方案
  6. Global.asax 文件是什么(转)
  7. 工作7年,从《一个苏州IT人的5年挨踢经历》系列开始,博客1年半,纯纪念
  8. const常量折叠
  9. WordPress程序流程分析
  10. 在IE中调试Javascript
  11. 设置cell背景色半透明
  12. countDownLatch和cyclicBarrier
  13. Redis中的基本数据结构
  14. ACM-ICPC 2018 徐州赛区网络预赛 HRyuji doesn't want to study 树状数组
  15. 下划线“_”在oracle中不是单纯的表示下划线的意思,而是表示匹配单一任何字符!
  16. tengine2.1.0RPM包制做 tengine-2.1.0.spec配置
  17. 『Python』图像金字塔、滑动窗口和非极大值抑制实现
  18. cmd导出oracle数据库数据
  19. 实践:由0到1-无线大数据UX团队的成长
  20. led,key通用IO的端口

热门文章

  1. copy-and-swap idiom
  2. 黄聪:Mysql开启InnoDB引擎出现1067错误的解决办法
  3. Java8新特性——集合底层源码实现的改变
  4. Spring Boot 启动以后然后再加载缓存数据 CommandLineRunner
  5. vue拖拽组件开发
  6. Web前端——Html常用标签及属性
  7. org.springframework.util.Base64Utils线程安全问题
  8. 性能篇系列—stream详解
  9. django8-django的中间件
  10. DQL---条件查询、单行函数、多行函数、分组函数、数据类型