一、ClickHouse简介
ClickHouse是俄罗斯的Yandex于2016年开源的一个用于联机分析(OLAP:Online Analytical Processing)的列式数据库管理系统(DBMS:Database Management System),主要用于在线分析处理查询(OLAP),能够使用SQL查询实时生成分析数据报告。
ClickHouse是一个完全的列式数据库管理系统,允许在运行时创建表和数据库,加载数据和运行查询,而无需重新配置和重新启动服务器,支持线性扩展,简单方便,高可靠性,容错。它在大数据领域没有走Hadoop生态,而是采用Local attached storage作为存储,这样整个IO可能就没有Hadoop那一套的局限。它的系统在生产环境中可以应用到比较大的规模,因为它的线性扩展能力和可靠性保障能够原生支持shard + replication 这种解决方案。它还提供了一些SQL直接接口,有比较丰富的原生client。
在传统的行式数据库系统中,数据按如下顺序存储:
行存储
处于同一行中的数据总是被物理的存储在一起。常见的行式数据库系统有:MySQL、Postgres和MS SQL Server。
在列式数据库系统中,数据按如下的顺序存储:
列存储
这些示例只显示了数据的排列顺序。来自不同列的值被单独存储,来自同一列的数据被存储在一起。
常见的列式数据库有: Vertica、 Paraccel (Actian Matrix,Amazon Redshift)、 Sybase IQ、 Exasol、 Infobright、 InfiniDB、 MonetDB (VectorWise, Actian Vector)、 LucidDB、 SAP HANA、 Google Dremel、 Google PowerDrill、 Druid、 kdb+。
1.1 优点
-
灵活的MPP架构,支持线性扩展,简单方便,高可靠性
-
多服务器分布式处理数据,完备的DBMS系统
-
底层数据列式存储,支持压缩,优化数据存储,优化索引数据,优化底层存储
-
容错跑分快:比Vertica快5倍,比Hive快279倍,比MySQL快800倍,其处理的数据级别已达到10亿级别
-
功能多:支持数据统计分析各种场景,支持类SQL查询,异地复制部署,海量数据存储,分布式运算,快速闪电的性能,几乎实时的数据分析,友好的SQL语法,出色的函数支持
1.2 缺点
-
不支持事务,不支持真正的删除/更新
-
不支持高并发(单节点),官方建议qps为100,可以通过修改配置文件增加连接数(在服务器配置足够好的情况下)
-
不支持二级索引
-
不擅长多表join(建议用大宽表)
-
元数据管理需要人为干预
-
尽量做1000条以上批量的写入,避免逐行insert或小批量的insert、update、delete操作
1.3 应用场景
-
绝大多数请求都是用于读访问的,要求实时返回结果
-
数据需要以大批次(大于1000行)进行更新,而不是单行更新,或者根本没有更新操作
-
数据只是添加到数据库,没有必要修改
-
读取数据时,会从数据库中提取出大量的行,但只用到一小部分列
-
表很“宽”,即表中包含大量的列
-
查询频率相对较低(通常每台服务器每秒查询数百次或更少)
-
对于简单查询,允许大约50毫秒的延迟
-
列的值是比较小的数值和短字符串(例如,每个URL只有60个字节)
-
在处理单个查询时需要高吞吐量(每台服务器每秒高达数十亿行)
-
不需要事务
-
数据一致性要求较低
-
每次查询中只会查询一个大表,除了一个大表,其余都是小表
-
查询结果显著小于数据源,即数据有过滤或聚合,返回结果不超过单个服务器内存大小
二、OLAP架构的分类
2.1 ROLAP
ROLAP:Relational OLAP
2.1.1 背景
基于关系型数据库实现,使用关系型数据库存储,采用星型、雪花模型建模。
2.1.2 挑战
当数据量大、维度多的时候,数据查询会变得十分困难。
2.1.3 总结
ROLAP最具有群众基础,但存在性能瓶颈。
2.1.4 历史
- 第一代:Oralce、MySQL、Postgresql
- 第二代:Hive、SparkSQL、ElasticSearch
2.2 MOLAP
MOLAP:Multidimensional OLAP
2.2.1 背景
基于非关系型数据库实现,采用多维数组的方式存储数据,使用立方体模型建模,有十分良好的查询性能。
2.2.2 挑战
通过空间换时间的方式实现,在提升效率的同时会带来额外的存储开销,不能查询立方体之外的数据。
2.2.3 总结
MOLAP性能快,但模型不友好,是为了解决ROLAP性能问题另辟蹊径的方法。
2.3.4 历史
- 第一代:物化视图、位图索引
- 第二代:Apache Kylin、HBase
2.3 HOLAP
HOLAP:Hybrid OLAP
2.3.1 背景
采用混合架构,在MOLAP架构的基础上兼顾明细数据查询的支持(立方体外的数据)。
2.3.2 挑战
架构的复杂性增加
2.3.3 总结
H=R+M,简单粗暴
三、ClickHouse发展历史
Yandex在2016年6月15日开源了一个数据分析的数据库,名字叫做ClickHouse。ClickHouse最初是为 YandexMetrica 世界第二大Web分析平台 而开发的。
3.2 Yandex是一家怎样的公司
1、欧洲最大的互联网公司之一
2、拥有俄罗斯第一的搜索引擎
3、超过50种不同的B2C和B2B产品
4、大数据、机器学习
3.3 Yandex.Metrica
1、全球第三大网络分析工具
2、每天处理超过30亿个事件
3、分析涵盖数百万个网站
4、每天超过10万分析师用户
3.4 ClickHouse发展历程
ClickHouse发展历程3.4.1 另辟蹊径的Metrage时期
1、摒弃关系模型采用key value
2、LSM树索引
3、实时计算改为预处理(立方体)
问题:只提供了内置的40多种固定分析场景
截至到2015年,Metrage中存储了超过3万亿行的数据,集群规模超过了60台,而查询性能也由26秒降到了惊人的1秒以内。
3.4.2 水到渠成的ClickHouse时代
结合Metrage和OLAPServer为基础进一步完善以实现一个完备的数据库管理系统(DBMS)为目标,最终打造出了ClickHouse并于2016年开源。
3.5 为什么叫ClickHouse
ClickHouse = Click Stream + Data WareHouse
四、ClickHouse的特点
4.1 OLAP数据库、ROLAP模型
完整的DBMS,支持SQL、DDL、DML语句。数十种表引擎,内置数百个函数。
4.2 接口丰富
提供TCP、HTTP底层访问接口,提供JDBC、CLI等封装接口,支持Java、Python、Nodejs等众多第三方接口。
4.3 在线查询
实时应答,无需预处理,也支持立方体预聚合。
4.4 分布式
MPP架构,支持集群模式,支持数据分区、分片、副本。
4.5 高性能
列存、高压缩、向量化引擎,秒杀一切的性能。单机部署,即拥有高性能。
4.6 安全可靠
熔断机制、防误删机制
4.7 权限
客户端接入权限、资源访问权限、操作访问权限、数据行级权限。
4.8 Everything is table
面向表编程,包括代理访问外部资源(例如Zookeeper、文件等),贡献者名单也专门有一张表。
4.9 开源免费、社区活跃
2016年开源,Apache-2.0协议
五、ClickHouse核心概念
5.1 数据分片
数据分片是将数据进行横向切分,这是一种在面对海量数据场景下,解决存储和查询瓶颈的有效手段,是一种分治思想的体现。ClickHouse支持分片,而分片则依赖集群。每个集群由1到多个分片组成,而每个分片则对应了ClickHouse的1个服务节点。分片的数据量上限取决于节点数量(1个分片只能对应1个服务节点)。ClickHouse并不像其他分布式系统那样,拥有高度自动化的分片功能。ClickHouse提供了本地表(Local Table)与分布式表(Distributed Table)的概念。一张本地表等同于一份数据的分片。而分布式表本身不存储任何数据,它是本地表的访问代理,其作用类似于分库中间件。借助分布式表,能够代理访问多个数据分片,从而实现分布式查询。这种设计类似于数据库的分库和分表,十分灵活。例如在业务系统上线的初期,数据体量并不高,此时数据表并不需要多个分片。所以使用单个节点的本地表(单个数据分片)即可满足业务需求,待到业务增长、数据量增大的时候,再通过新增数据分片的方式分流数据,并通过分布式表实现分布式查询。
5.2 列式存储
列式数据库更适合于OLAP场景,对于大多数查询而言,处理速度至少提高了100倍。
1、针对分析类查询,通常只需要读取表的一小部分列。在列式数据库中你可以只读取你需要的数据。例如,如果只需要读取100列中的5列,这将帮助你最少减少20倍的I/O消耗。
2、由于数据总是打包成批量读取的,所以压缩是非常容易的。同时数据按列分别存储这也更容易压缩。这进一步降低了I/O的体积。
3、由于I/O的降低,这将帮助更多的数据被系统缓存。
5.3 向量化(可理解为多线程)
ClickHouse不仅将数据按列存储,而且按列进行计算。传统OLTP数据库通常采用按行计算,原因是事务处理中以点查为主,SQL计算量小,实现这些技术的收益不够明显。但是在分析场景下,单个SQL所涉及计算量可能极大,将每行作为一个基本单元进行处理会带来严重的性能损耗。
ClickHouse实现了向量执行引擎(Vectorized execution engine),对内存中的列式数据,一个batch调用一次SIMD指令(而非每一行调用一次),不仅减少了函数调用次数、降低了cache miss,而且可以充分发挥SIMD指令的并行能力,大幅缩短了计算耗时。向量执行引擎,通常能够带来数倍的性能提升。
SIMD全称Single Instruction Multiple Data , 单指令多数据流,能够复制多个操作数,并把它们打包在大型寄存器的一组指令集。以同步方式,在同一时间内执行同一条指令。
5.4 表
上层数据的视图展示概念,包括表的基本结构和数据
5.5 分区
ClickHouse支持partition by 子句,在建表时可以指定按照任意合法表达式进行数据分区操作,比如通过toYYYYMM()
将数据按月进行分区(分区存储)、toMonday()
将数据按照周几进行分区(分区存储),数据以分区的形式统一管理和维护一批数据(批量插入分区,按分区批量删除)。
5.6 副本
数据存储副本,在集群模式下实现高可用,简单理解就是相同的数据备份。
5.7 引擎
不同是引擎决定了表数据的存储特点,位置和表数据的操作行为。
- 决定表存储在哪里以及以何种方式存储
- 支持哪些查询以及如何支持
- 并发数据访问
- 索引的使用
- 是否可以执行多线程请求
- 数据复制参数
- 并发操作,如
insert into tb_x select * from tb_x;
同时进行读和写
表引擎决定了数据在文件系统中的存储方式,常用的也是官方推荐的存储引擎MergeTree
系列,如果需要数据副本的话可以使用ReplicateMergeTree
系列,相当于MergeTree
的副本版本。读取集群数据需要使用分布式表引擎Distribute
六、表引擎
表引擎 MergeTree表引擎家族 MergeTree 数据预聚合 数据去重 数据预聚合 数据修改 数据修改七、为什么ClickHouse那么快
7.1 高层次架构
- Shared nothing
- 并行计算
- 列式存储
- MergeTree
- 稀疏索引
- 数据压缩
7.2 低层次架构-着眼硬件
从硬件功能层面着手设计,基于CPU指令的向量化执行
-
将要使用的硬件水平是怎样?包括CPU、内存、硬盘、网络等等
-
在这样的硬件上,需要达到怎样的性能?包括延迟、吞吐量等等。
-
使用怎样的数据结构?包括String、HashTable、Vector等等。
-
选择的这些数据结构,在硬件上会如何工作?
7.3 算法优化,及时引入世界一流的先进算法
- Volnitsky Substring Search
- Hyperscan和RS2
- SIMD JSON
- Roaring Bitmaps
7.4 特定场景,特殊优化
函数的优化、查询的优化
八、ClickHouse最适合的场景
- 宽表(<10000列),结构化数据
- 查询QPS相对较低,但是每个请求的数据使用量很高
- 可应用于BI、电信、金融、电子商务、信息安全、网络游戏、物联网等领域
九、ClickHouse不适合的场景
- OLTP场景
- Key Value数据库
十、Ubuntu 安装ClickHouse
安装命令
sudo apt-get install apt-transport-https ca-certificates dirmngr
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv E0C56BD4
echo "deb https://repo.clickhouse.com/deb/stable/ main/" | sudo tee \
/etc/apt/sources.list.d/clickhouse.list
sudo apt-get update
sudo apt-get install -y clickhouse-server clickhouse-client
启动服务
sudo service clickhouse-server start
启动服务后,可以使用命令行客户端连接到它
1、默认情况下,使用default
用户并不携带密码连接到localhost:9000
。还可以使用--host
参数连接到指定服务器
clickhouse-client
2、如果设置了密码,则
//默认用户
clickhouse-client --multiline --password 设定的密码
//指定用户名密码
clickhouse-client --user 用户名 --password 密码
连接成功
输入show databases
(查看当前已有的数据库) 和 select 1
测试安装是否成功
十一、客户端连接ClickHouse
11.1 DBeaver
DBeaver 具有ClickHouse支持的通用桌面数据库客户端。
特征:
- 使用语法高亮显示查询开发。
- 表格预览。
- 自动完成
11.2 允许远程连接
先查看ClickHouse server端监听端口的状态:
lsof -i :8123
root@iZm5eetszs07500os8erolZ:~# lsof -i :8123
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
clickhous 8277 clickhouse 113u IPv4 701715 0t0 TCP localhost:8123 (LISTEN)
root@iZm5eetszs07500os8erolZ:~#
这里显示监听本地端口,需要修改配置:
vi /etc/clickhouse-server/config.xml
网上的文章都是把注释掉的<listen_host>::</listen_host>
取消注释,然后重启服务:
sudo service clickhouse-server restart
改了配置后,我的服务一直起不来,通过查看日志文件,异常信息如下:
error.log2021.10.09 11:22:40.809266 [ 14610 ] {} <Error> Application: DB::Exception: Listen [::]:8123 failed: Poco::Exception. Code: 1000, e.code() = 0, DNS error: EAI: Address family for hostname not supported (version 21.9.4.35 (official build))
本机没有开放ipv6,只能对ipv4生效。在/etc/click-house/config.xml中,把<listen_host> 改成0.0.0.0
config.xml重启服务
sudo service clickhouse-server restart
现在就的端口监听情况:
lsof -i :8123
root@iZm5eetszs07500os8erolZ:~# lsof -i :8123
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
clickhous 15330 clickhouse 158u IPv4 727063 0t0 TCP *:8123 (LISTEN)
root@iZm5eetszs07500os8erolZ:~#
11.3 DBeaver连接ClickHouse
DBeaver连接ClickHouse十二、建库建表
12.1 建库
ClickHouse在逻辑上将表分组为数据库。包含一个default
数据库,但我们将创建一个新的数据库db_test
:
CREATE DATABASE IF NOT EXISTS db_test;
建库
12.2 建表
内存引擎,数据存储在内存,服务重启后数据丢失
create table db_test.t_user
(
id UInt64,
user_name String,
birthday Date,
sex UInt8
)
ENGINE = Memory()
MySQL引擎(表引擎)可以对存储在远程 MySQL 服务器上的数据执行 SELECT 查询
CREATE TABLE db_test.t_medal_member_counter_log (
id UInt64,
week UInt64,
member_id UInt64,
action_key_id String,
type String,
modify_time DateTime,
create_time DateTime
)
ENGINE = MySQL('ip:3306', 'testdb', 't_medal_member_counter_log', 'test_u', 'test_PWD_123');
在ClickHouse查询t_medal_member_counter_log
其实查询的是MySQL数据库中的t_medal_member_counter_log
表
select * from db_test.t_medal_member_counter_log;
补充:MySQL数据库表结构
CREATE TABLE `t_medal_member_counter_log` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID',
`week` int DEFAULT '1' COMMENT '周',
`member_id` bigint NOT NULL DEFAULT '0' COMMENT '会员Id',
`type` varchar(20) CHARACTER SET utf8mb4 NOT NULL DEFAULT '' COMMENT '条件类型',
`action_key_id` varchar(45) DEFAULT '' COMMENT '业务ID',
`deleted` bit(1) NOT NULL,
`modify_time` datetime NOT NULL,
`create_time` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `IDX_deleted` (`deleted`),
KEY `search_index` (`member_id`,`type`,`action_key_id`,`week`)
) ENGINE=InnoDB AUTO_INCREMENT=181691593719812 DEFAULT CHARSET=utf8mb4 AVG_ROW_LENGTH=2048 COMMENT='会员行为记录流水'
12.3 视图
创建普通视图
create view db_test.view_medal_member_counter_log
as select
member_id,
COUNT(CASE WHEN type = 'AC_CONTENT_PUB' THEN type END) ac_content_pub_num,
COUNT(CASE WHEN type = 'AC_ACTIVITY' THEN type END) ac_activity_num,
COUNT(CASE WHEN type = 'AC_LIKE' THEN type END) ac_like_num,
COUNT(CASE WHEN type = 'AC_COMMENT_PUB' THEN type END) ac_comment_pub_num,
COUNT(CASE WHEN type = 'AC_COLL' THEN type END) ac_coll_num,
COUNT(CASE WHEN type = 'AC_FORWARD' THEN type END) ac_forward_num,
COUNT(CASE WHEN type = 'AC_PICKME' THEN type END) ac_pickme_num,
COUNT(CASE WHEN type = 'AC_GETME' THEN type END) ac_getme_num,
COUNT(CASE WHEN type = 'AC_JOINME' THEN type END) ac_joinme_num,
toDate(create_time)create_date
from t_medal_member_counter_log
group by member_id,create_date;
创建物化视图
create materialized view view_medal_member_counter_log
ENGINE = SummingMergeTree
PARTITION BY create_date ORDER BY (member_id,create_date)
POPULATE
as
select
member_id,
COUNT(CASE WHEN type = 'AC_CONTENT_PUB' THEN type END) ac_content_pub_num,
COUNT(CASE WHEN type = 'AC_ACTIVITY' THEN type END) ac_activity_num,
COUNT(CASE WHEN type = 'AC_LIKE' THEN type END) ac_like_num,
COUNT(CASE WHEN type = 'AC_COMMENT_PUB' THEN type END) ac_comment_pub_num,
COUNT(CASE WHEN type = 'AC_COLL' THEN type END) ac_coll_num,
COUNT(CASE WHEN type = 'AC_FORWARD' THEN type END) ac_forward_num,
COUNT(CASE WHEN type = 'AC_PICKME' THEN type END) ac_pickme_num,
COUNT(CASE WHEN type = 'AC_GETME' THEN type END) ac_getme_num,
COUNT(CASE WHEN type = 'AC_JOINME' THEN type END) ac_joinme_num,
toDate(create_time)create_date
from t_medal_member_counter_log
group by member_id,create_date;
注意:如果视图里用的表是MySQL的映射表,当MySQL源表插入数据时,物化视图数据不会变化,因此建议用普通视图,实时查询。
网友评论