一、概念
ClickHouse是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS)。
OLAP场景的关键特征
- 绝大多数是读请求
- 数据以相当大的批次(> 1000行)更新,而不是单行更新;或者根本没有更新。
- 已添加到数据库的数据不能修改。
- 对于读取,从数据库中提取相当多的行,但只提取列的一小部分。
- 宽表,即每个表包含着大量的列
- 查询相对较少(通常每台服务器每秒查询数百次或更少)
- 对于简单查询,允许延迟大约50毫秒
- 列中的数据相对较小:数字和短字符串(例如,每个URL 60个字节)
- 处理单个查询时需要高吞吐量(每台服务器每秒可达数十亿行)
- 事务不是必须的
- 对数据一致性要求低
- 每个查询有一个大表。除了他以外,其他的都很小。
- 查询结果明显小于源数据。换句话说,数据经过过滤或聚合,因此结果适合于单个服务器的RAM中
二、应用场景
基于ClickHouse和BI工具构建实时运营监控报表
利用ClickHouse构建实时交互式报表,实时分析订单、收入、用户数等核心业务指标;构建用户来源分析系统,跟踪各渠道PV、UV来源。
海量数据实时多维查询
在数亿至数百亿记录规模大宽表,数百以上维度自由查询,响应时间通常在100毫秒以内。让业务人员能持续探索式查询分析,无需中断分析思路,便于深挖业务价值,具有非常好的查询体验。
用户画像分析
随着数据时代的发展,各行各业数据平台的体量越来越大,用户个性化运营的诉求也越来越突出,用户标签系统,做为个性化千人千面运营的基础服务,应运而生。如今,几乎所有行业(如互联网、游戏、教育等)都有实时精准营销的需求。通过系统生成用户画像,在营销时通过条件组合筛选用户,快速提取目标群体。
基于ClickHouse构建用户特征行为分析系统
利用ClickHouse对人群标签数据进行实时筛选并进行群体画像统计;自定义条件对海量明细日志记录进行过滤,分析用户行为。
用户分群统计
构建用户特征大宽表,任意选择用户属性标签数据和筛选条件,进行人群特征统计分析。
访客来源分析展示
通过批量离线计算对用户访问日志中的用户行为进行关联,生成用户行为路径大宽表同步到ClickHouse,基于ClickHoue构建交互式访客来源探索分析可视化系统。
三、产品特性
真正的列式数据库管理系统
在一个真正的列式数据库管理系统中,除了数据本身外不应该存在其他额外的数据。这意味着为了避免在值旁边存储它们的长度«number»,你必须支持固定长度数值类型。例如,10亿个UInt8类型的数据在未压缩的情况下大约消耗1GB左右的空间,如果不是这样的话,这将对CPU的使用产生强烈影响。即使是在未压缩的情况下,紧凑的存储数据也是非常重要的,因为解压缩的速度主要取决于未压缩数据的大小。这是非常值得注意的,因为在一些其他系统中也可以将不同的列分别进行存储,但由于对其他场景进行的优化,使其无法有效的处理分析查询。例如: HBase,BigTable,Cassandra,HyperTable。在这些系统中,你可以得到每秒数十万的吞吐能力,但是无法得到每秒几亿行的吞吐能力。需要说明的是,ClickHouse不单单是一个数据库, 它是一个数据库管理系统。因为它允许在运行时创建表和数据库、加载数据和运行查询,而无需重新配置或重启服务。
数据压缩
在一些列式数据库管理系统中(例如:InfiniDB CE 和 MonetDB) 并没有使用数据压缩。但是, 若想达到比较优异的性能,数据压缩确实起到了至关重要的作用。
除了在磁盘空间和CPU消耗之间进行不同权衡的高效通用压缩编解码器之外,ClickHouse还提供针对特定类型数据的专用编解码器,这使得ClickHouse能够与更小的数据库(如时间序列数据库)竞争并超越它们。
数据的磁盘存储
许多的列式数据库(如 SAP HANA, Google PowerDrill)只能在内存中工作,这种方式会造成比实际更多的设备预算。
ClickHouse被设计用于工作在传统磁盘上的系统,它提供每GB更低的存储成本,但如果可以使用SSD和内存,它也会合理的利用这些资源。
多核心并行处理
ClickHouse会使用服务器上一切可用的资源,从而以最自然的方式并行处理大型查询。
多服务器分布式处理
上面提到的列式数据库管理系统中,几乎没有一个支持分布式的查询处理。 在ClickHouse中,数据可以保存在不同的shard上,每一个shard都由一组用于容错的replica组成,查询可以并行地在所有shard上进行处理。这些对用户来说是透明的
支持SQL
ClickHouse支持一种基于SQL的声明式查询语言,它在许多情况下与ANSI SQL标准相同。支持的查询GROUP BY, ORDER BY, FROM, JOIN, IN以及非相关子查询。相关(依赖性)子查询和窗口函数暂不受支持,但将来会被实现。
向量引擎
为了高效的使用CPU,数据不仅仅按列存储,同时还按向量(列的一部分)进行处理,这样可以更加高效地使用CPU。
实时的数据更新
ClickHouse支持在表中定义主键。为了使查询能够快速在主键中进行范围查找,数据总是以增量的方式有序的存储在MergeTree中。因此,数据可以持续不断地高效的写入到表中,并且写入的过程中不会存在任何加锁的行为。
索引
按照主键对数据进行排序,这将帮助ClickHouse在几十毫秒以内完成对数据特定值或范围的查找。适合在线查询
在线查询意味着在没有对数据做任何预处理的情况下以极低的延迟处理查询并将结果加载到用户的页面中。
支持近似计算
ClickHouse提供各种各样在允许牺牲数据精度的情况下对查询进行加速的方法:
- 用于近似计算的各类聚合函数,如:distinct values, medians, quantiles
- 基于数据的部分样本进行近似查询。这时,仅会从磁盘检索少部分比例的数据。
- 不使用全部的聚合条件,通过随机选择有限个数据聚合条件进行聚合。这在数据聚合条件满足某些分布条件下,在提供相当准确的聚合结果的同时降低了计算资源的使用。
自适应连接算法
ClickHouse支持自定义JOIN多个表,它更倾向于散列连接算法,如果有多个大表,则使用合并-连接算法
支持数据复制和数据完整性
ClickHouse使用异步的多主复制技术。当数据被写入任何一个可用副本后,系统会在后台将数据分发给其他副本,以保证系统在不同副本上保持相同的数据。在大多数情况下ClickHouse能在故障后自动恢复,在一些少数的复杂情况下需要手动恢复。
更多信息,参见 数据复制。
角色的访问控制
ClickHouse使用SQL查询实现用户帐户管理,并允许角色的访问控制,类似于ANSI SQL标准和流行的关系数据库管理系统。
限制
- 没有完整的事务支持。
- 缺少高频率,低延迟的修改或删除已存在数据的能力。仅能用于批量删除或修改数据,但这符合 GDPR。
- 稀疏索引使得ClickHouse不适合通过其键检索单行的点查询。
四、性能
根据Yandex的内部测试结果,ClickHouse表现出了比同类可比较产品更优的性能。你可以在 这里 查看具体的测试结果。许多其他的测试也证实这一点。你可以使用互联网搜索到它们,或者你也可以从 我们收集的部分相关连接 中查看。
单个大查询的吞吐量
吞吐量可以使用每秒处理的行数或每秒处理的字节数来衡量。如果数据被放置在page cache中,则一个不太复杂的查询在单个服务器上大约能够以2-10GB/s(未压缩)的速度进行处理(对于简单的查询,速度可以达到30GB/s)。如果数据没有在page cache中的话,那么速度将取决于你的磁盘系统和数据的压缩率。例如,如果一个磁盘允许以400MB/s的速度读取数据,并且数据压缩率是3,则数据的处理速度为1.2GB/s。这意味着,如果你是在提取一个10字节的列,那么它的处理速度大约是1-2亿行每秒。
对于分布式处理,处理速度几乎是线性扩展的,但这受限于聚合或排序的结果不是那么大的情况下。
处理短查询的延迟时间
如果一个查询使用主键并且没有太多行(几十万)进行处理,并且没有查询太多的列,那么在数据被page cache缓存的情况下,它的延迟应该小于50毫秒(在最佳的情况下应该小于10毫秒)。 否则,延迟取决于数据的查找次数。如果你当前使用的是HDD,在数据没有加载的情况下,查询所需要的延迟可以通过以下公式计算得知: 查找时间(10 ms) * 查询的列的数量 * 查询的数据块的数量。
处理大量短查询的吞吐量
在相同的情况下,ClickHouse可以在单个服务器上每秒处理数百个查询(在最佳的情况下最多可以处理数千个)。但是由于这不适用于分析型场景。因此我们建议每秒最多查询100次。
数据的写入性能
我们建议每次写入不少于1000行的批量写入,或每秒不超过一个写入请求。当使用tab-separated格式将一份数据写入到MergeTree表中时,写入速度大约为50到200MB/s。如果您写入的数据每行为1Kb,那么写入的速度为50,000到200,000行每秒。如果您的行更小,那么写入速度将更高。为了提高写入性能,您可以使用多个INSERT进行并行写入,这将带来线性的性能提升。
五、安装
系统要求
ClickHouse可以在任何具有x86_64,AArch64或PowerPC64LE CPU架构的Linux,FreeBSD或Mac OS X上运行。
官方预构建的二进制文件通常针对x86_64进行编译,并利用SSE 4.2指令集,因此,除非另有说明,支持它的CPU使用将成为额外的系统需求。下面是检查当前CPU是否支持SSE 4.2的命令:
$ grep -q sse4_2 /proc/cpuinfo && echo "SSE 4.2 supported" || echo "SSE 4.2 not supported"
要在不支持SSE 4.2或AArch64,PowerPC64LE架构的处理器上运行ClickHouse,您应该通过适当的配置调整从源代码构建ClickHouse。
可用安装包
DEB安装包
建议使用Debian或Ubuntu的官方预编译deb软件包。运行以下命令来安装包:
sudo apt-get install -y apt-transport-https ca-certificates dirmngrsudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 8919F6BD2B48D754echo "deb https://packages.clickhouse.com/deb stable main" | sudo tee \ /etc/apt/sources.list.d/clickhouse.listsudo apt-get updatesudo apt-get install -y clickhouse-server clickhouse-clientsudo service clickhouse-server startclickhouse-client # or "clickhouse-client --password" if you've set up a password.
Deprecated Method for installing deb-packages
如果您想使用最新的版本,请用testing替代stable(我们只推荐您用于测试环境)。
你也可以从这里手动下载安装包:下载。
安装包列表:
- clickhouse-common-static — ClickHouse编译的二进制文件。
- clickhouse-server — 创建clickhouse-server软连接,并安装默认配置服务
- clickhouse-client — 创建clickhouse-client客户端工具软连接,并安装客户端配置文件。
- clickhouse-common-static-dbg — 带有调试信息的ClickHouse二进制文件。
RPM安装包
推荐使用CentOS、RedHat和所有其他基于rpm的Linux发行版的官方预编译rpm包。
首先,您需要添加官方存储库:
sudo yum install -y yum-utilssudo yum-config-manager --add-repo https://packages.clickhouse.com/rpm/clickhouse.reposudo yum install -y clickhouse-server clickhouse-clientsudo /etc/init.d/clickhouse-server startclickhouse-client # or "clickhouse-client --password" if you set up a password.
Deprecated Method for installing rpm-packages
如果您想使用最新的版本,请用testing替代stable(我们只推荐您用于测试环境)。prestable有时也可用。
然后运行命令安装:
sudo yum install clickhouse-server clickhouse-client
你也可以从这里手动下载安装包:下载。
Tgz安装包
如果您的操作系统不支持安装deb或rpm包,建议使用官方预编译的tgz软件包。
所需的版本可以通过curl或wget从存储库https://packages.clickhouse.com/tgz/下载。
下载后解压缩下载资源文件并使用安装脚本进行安装。以下是一个最新稳定版本的安装示例:
LATEST_VERSION=$(curl -s https://packages.clickhouse.com/tgz/stable/ | \ grep -Eo '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | sort -V -r | head -n 1)export LATEST_VERSIONcase $(uname -m) in x86_64) ARCH=amd64 ;; aarch64) ARCH=arm64 ;; *) echo "Unknown architecture $(uname -m)"; exit 1 ;;esacfor PKG in clickhouse-common-static clickhouse-common-static-dbg clickhouse-server clickhouse-clientdo curl -fO "https://packages.clickhouse.com/tgz/stable/$PKG-$LATEST_VERSION-${ARCH}.tgz" \ || curl -fO "https://packages.clickhouse.com/tgz/stable/$PKG-$LATEST_VERSION.tgz"donetar -xzvf "clickhouse-common-static-$LATEST_VERSION-${ARCH}.tgz" \ || tar -xzvf "clickhouse-common-static-$LATEST_VERSION.tgz"sudo "clickhouse-common-static-$LATEST_VERSION/install/doinst.sh"tar -xzvf "clickhouse-common-static-dbg-$LATEST_VERSION-${ARCH}.tgz" \ || tar -xzvf "clickhouse-common-static-dbg-$LATEST_VERSION.tgz"sudo "clickhouse-common-static-dbg-$LATEST_VERSION/install/doinst.sh"tar -xzvf "clickhouse-server-$LATEST_VERSION-${ARCH}.tgz" \ || tar -xzvf "clickhouse-server-$LATEST_VERSION.tgz"sudo "clickhouse-server-$LATEST_VERSION/install/doinst.sh" configuresudo /etc/init.d/clickhouse-server starttar -xzvf "clickhouse-client-$LATEST_VERSION-${ARCH}.tgz" \ || tar -xzvf "clickhouse-client-$LATEST_VERSION.tgz"sudo "clickhouse-client-$LATEST_VERSION/install/doinst.sh"
Deprecated Method for installing tgz archives
对于生产环境,建议使用最新的stable版本。你可以在GitHub页面https://github.com/ClickHouse/ClickHouse/tags找到它,它以后缀`-stable`标志。
Docker安装包
要在Docker中运行ClickHouse,请遵循Docker Hub上的指南。它是官方的deb安装包。
其他环境安装包
对于非linux操作系统和Arch64 CPU架构,ClickHouse将会以master分支的最新提交的进行编译提供(它将会有几小时的延迟)。
- macOS — curl -O 'https://builds.clickhouse.com/master/macos/clickhouse' && chmod a+x ./clickhouse
- FreeBSD — curl -O 'https://builds.clickhouse.com/master/freebsd/clickhouse' && chmod a+x ./clickhouse
- AArch64 — curl -O 'https://builds.clickhouse.com/master/aarch64/clickhouse' && chmod a+x ./clickhouse
下载后,您可以使用clickhouse client连接服务,或者使用clickhouse local模式处理数据,不过您必须要额外在GitHub下载server和users配置文件。
不建议在生产环境中使用这些构建版本,因为它们没有经过充分的测试,但是您可以自行承担这样做的风险。它们只是ClickHouse功能的一个部分。
使用源码安装
要手动编译ClickHouse, 请遵循Linux或Mac OS X说明。
您可以编译并安装它们,也可以使用不安装包的程序。通过手动构建,您可以禁用SSE 4.2或AArch64 cpu。
Client: programs/clickhouse-client Server: programs/clickhouse-server
您需要创建一个数据和元数据文件夹,并为所需的用户chown授权。它们的路径可以在服务器配置(src/programs/server/config.xml)中改变,默认情况下它们是:
/opt/clickhouse/data/default/ /opt/clickhouse/metadata/default/
在Gentoo上,你可以使用emerge clickhouse从源代码安装ClickHouse。
启动
如果没有service,可以运行如下命令在后台启动服务:
$ sudo /etc/init.d/clickhouse-server start
日志文件将输出在/var/log/clickhouse-server/文件夹。
如果服务器没有启动,检查/etc/clickhouse-server/config.xml中的配置。
您也可以手动从控制台启动服务器:
$ clickhouse-server --config-file=/etc/clickhouse-server/config.xml
在这种情况下,日志将被打印到控制台,这在开发过程中很方便。
如果配置文件在当前目录中,则不需要指定——config-file参数。默认情况下,它的路径为./config.xml。
ClickHouse支持访问限制设置。它们位于users.xml文件(与config.xml同级目录)。 默认情况下,允许default用户从任何地方访问,不需要密码。可查看user/default/networks。 更多信息,请参见Configuration Files。
启动服务后,您可以使用命令行客户端连接到它:
$ clickhouse-client
默认情况下,使用default用户并不携带密码连接到localhost:9000。还可以使用--host参数连接到指定服务器。
终端必须使用UTF-8编码。 更多信息,请参阅Command-line client。
示例:
$ ./clickhouse-clientClickHouse client version 0.0.18749.Connecting to localhost:9000.Connected to ClickHouse server version 0.0.18749.:) SELECT 1SELECT 1┌─1─┐│ 1 │└───┘1 rows in set. Elapsed: 0.003 sec.:)
恭喜,系统已经工作了!
六、ClickHouse教程
从本教程中可以获得什么?
通过学习本教程,您将了解如何设置一个简单的ClickHouse集群。它会很小,但是可以容错和扩展。然后,我们将使用其中一个示例数据集来填充数据并执行一些演示查询。
单节点设置
为了延迟演示分布式环境的复杂性,我们将首先在单个服务器或虚拟机上部署ClickHouse。ClickHouse通常是从deb或rpm包安装,但对于不支持它们的操作系统也有其他方法。
例如,您选择deb安装包,执行:
sudo apt-get install -y apt-transport-https ca-certificates dirmngr sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 8919F6BD2B48D754 echo "deb https://packages.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
在我们安装的软件中包含这些包:
- clickhouse-client 包,包含clickhouse-client客户端,它是交互式ClickHouse控制台客户端。
- clickhouse-common 包,包含一个ClickHouse可执行文件。
- clickhouse-server 包,包含要作为服务端运行的ClickHouse配置文件。
服务器配置文件位于/etc/clickhouse-server/。在继续之前,请注意config.xml中的<path>元素。它决定了数据存储的位置,因此它应该位于磁盘容量的卷上;默认值是/var/lib/clickhouse/。如果你想调整配置,直接编辑config是不方便的。考虑到它可能会在将来的包更新中被重写。建议重写配置元素的方法是在配置中创建config.d文件夹,作为config.xml的重写方式。
你可能已经注意到了,clickhouse-server安装后不会自动启动。 它也不会在更新后自动重新启动。 您启动服务端的方式取决于您的初始系统,通常情况下是这样:
sudo service clickhouse-server start
或
sudo /etc/init.d/clickhouse-server start
服务端日志的默认位置是/var/log/clickhouse-server/。当服务端在日志中记录Ready for connections消息,即表示服务端已准备好处理客户端连接。
一旦clickhouse-server启动并运行,我们可以利用clickhouse-client连接到服务端,并运行一些测试查询,如SELECT "Hello, world!";.
Clickhouse-client的快速提示
导入示例数据集
现在是时候用一些示例数据填充我们的ClickHouse服务端。 在本教程中,我们将使用Yandex.Metrica的匿名数据,它是在ClickHouse成为开源之前作为生产环境运行的第一个服务(关于这一点的更多内容请参阅ClickHouse历史)。多种导入Yandex.Metrica数据集方法,为了本教程,我们将使用最现实的一个。
下载并提取表数据
curl https://datasets.clickhouse.com/hits/tsv/hits_v1.tsv.xz | unxz --threads=`nproc` > hits_v1.tsvcurl https://datasets.clickhouse.com/visits/tsv/visits_v1.tsv.xz | unxz --threads=`nproc` > visits_v1.tsv
提取的文件大小约为10GB。
创建表
与大多数数据库管理系统一样,ClickHouse在逻辑上将表分组为数据库。包含一个default数据库,但我们将创建一个新的数据库tutorial:
clickhouse-client --query "CREATE DATABASE IF NOT EXISTS tutorial"
与创建数据库相比,创建表的语法要复杂得多(请参阅参考资料. 一般CREATE TABLE声明必须指定三个关键的事情:
- 要创建的表的名称。
- 表结构,例如:列名和对应的数据类型。
- 表引擎及其设置,这决定了对此表的查询操作是如何在物理层面执行的所有细节。
Yandex.Metrica是一个网络分析服务,样本数据集不包括其全部功能,因此只有两个表可以创建:
- hits 表包含所有用户在服务所涵盖的所有网站上完成的每个操作。
- visits 表包含预先构建的会话,而不是单个操作。
让我们看看并执行这些表的实际创建表查询:
CREATE TABLE tutorial.hits_v1( `WatchID` UInt64, `JavaEnable` UInt8, `Title` String, `GoodEvent` Int16, `EventTime` DateTime, `EventDate` Date, `CounterID` UInt32, `ClientIP` UInt32, `ClientIP6` FixedString(16), `RegionID` UInt32, `UserID` UInt64, `CounterClass` Int8, `OS` UInt8, `UserAgent` UInt8, `URL` String, `Referer` String, `URLDomain` String, `RefererDomain` String, `Refresh` UInt8, `IsRobot` UInt8, `RefererCategories` Array(UInt16), `URLCategories` Array(UInt16), `URLRegions` Array(UInt32), `RefererRegions` Array(UInt32), `ResolutionWidth` UInt16, `ResolutionHeight` UInt16, `ResolutionDepth` UInt8, `FlashMajor` UInt8, `FlashMinor` UInt8, `FlashMinor2` String, `NetMajor` UInt8, `NetMinor` UInt8, `UserAgentMajor` UInt16, `UserAgentMinor` FixedString(2), `CookieEnable` UInt8, `JavascriptEnable` UInt8, `IsMobile` UInt8, `MobilePhone` UInt8, `MobilePhoneModel` String, `Params` String, `IPNetworkID` UInt32, `TraficSourceID` Int8, `SearchEngineID` UInt16, `SearchPhrase` String, `AdvEngineID` UInt8, `IsArtifical` UInt8, `WindowClientWidth` UInt16, `WindowClientHeight` UInt16, `ClientTimeZone` Int16, `ClientEventTime` DateTime, `SilverlightVersion1` UInt8, `SilverlightVersion2` UInt8, `SilverlightVersion3` UInt32, `SilverlightVersion4` UInt16, `PageCharset` String, `CodeVersion` UInt32, `IsLink` UInt8, `IsDownload` UInt8, `IsNotBounce` UInt8, `FUniqID` UInt64, `HID` UInt32, `IsOldCounter` UInt8, `IsEvent` UInt8, `IsParameter` UInt8, `DontCountHits` UInt8, `WithHash` UInt8, `HitColor` FixedString(1), `UTCEventTime` DateTime, `Age` UInt8, `Sex` UInt8, `Income` UInt8, `Interests` UInt16, `Robotness` UInt8, `GeneralInterests` Array(UInt16), `RemoteIP` UInt32, `RemoteIP6` FixedString(16), `WindowName` Int32, `OpenerName` Int32, `HistoryLength` Int16, `BrowserLanguage` FixedString(2), `BrowserCountry` FixedString(2), `SocialNetwork` String, `SocialAction` String, `HTTPError` UInt16, `SendTiming` Int32, `DNSTiming` Int32, `ConnectTiming` Int32, `ResponseStartTiming` Int32, `ResponseEndTiming` Int32, `FetchTiming` Int32, `RedirectTiming` Int32, `DOMInteractiveTiming` Int32, `DOMContentLoadedTiming` Int32, `DOMCompleteTiming` Int32, `LoadEventStartTiming` Int32, `LoadEventEndTiming` Int32, `NSToDOMContentLoadedTiming` Int32, `FirstPaintTiming` Int32, `RedirectCount` Int8, `SocialSourceNetworkID` UInt8, `SocialSourcePage` String, `ParamPrice` Int64, `ParamOrderID` String, `ParamCurrency` FixedString(3), `ParamCurrencyID` UInt16, `GoalsReached` Array(UInt32), `OpenstatServiceName` String, `OpenstatCampaignID` String, `OpenstatAdID` String, `OpenstatSourceID` String, `UTMSource` String, `UTMMedium` String, `UTMCampaign` String, `UTMContent` String, `UTMTerm` String, `FromTag` String, `HasGCLID` UInt8, `RefererHash` UInt64, `URLHash` UInt64, `CLID` UInt32, `YCLID` UInt64, `ShareService` String, `ShareURL` String, `ShareTitle` String, `ParsedParams` Nested( Key1 String, Key2 String, Key3 String, Key4 String, Key5 String, ValueDouble Float64), `IslandID` FixedString(16), `RequestNum` UInt32, `RequestTry` UInt8)ENGINE = MergeTree()PARTITION BY toYYYYMM(EventDate)ORDER BY (CounterID, EventDate, intHash32(UserID))SAMPLE BY intHash32(UserID)
CREATE TABLE tutorial.visits_v1( `CounterID` UInt32, `StartDate` Date, `Sign` Int8, `IsNew` UInt8, `VisitID` UInt64, `UserID` UInt64, `StartTime` DateTime, `Duration` UInt32, `UTCStartTime` DateTime, `PageViews` Int32, `Hits` Int32, `IsBounce` UInt8, `Referer` String, `StartURL` String, `RefererDomain` String, `StartURLDomain` String, `EndURL` String, `LinkURL` String, `IsDownload` UInt8, `TraficSourceID` Int8, `SearchEngineID` UInt16, `SearchPhrase` String, `AdvEngineID` UInt8, `PlaceID` Int32, `RefererCategories` Array(UInt16), `URLCategories` Array(UInt16), `URLRegions` Array(UInt32), `RefererRegions` Array(UInt32), `IsYandex` UInt8, `GoalReachesDepth` Int32, `GoalReachesURL` Int32, `GoalReachesAny` Int32, `SocialSourceNetworkID` UInt8, `SocialSourcePage` String, `MobilePhoneModel` String, `ClientEventTime` DateTime, `RegionID` UInt32, `ClientIP` UInt32, `ClientIP6` FixedString(16), `RemoteIP` UInt32, `RemoteIP6` FixedString(16), `IPNetworkID` UInt32, `SilverlightVersion3` UInt32, `CodeVersion` UInt32, `ResolutionWidth` UInt16, `ResolutionHeight` UInt16, `UserAgentMajor` UInt16, `UserAgentMinor` UInt16, `WindowClientWidth` UInt16, `WindowClientHeight` UInt16, `SilverlightVersion2` UInt8, `SilverlightVersion4` UInt16, `FlashVersion3` UInt16, `FlashVersion4` UInt16, `ClientTimeZone` Int16, `OS` UInt8, `UserAgent` UInt8, `ResolutionDepth` UInt8, `FlashMajor` UInt8, `FlashMinor` UInt8, `NetMajor` UInt8, `NetMinor` UInt8, `MobilePhone` UInt8, `SilverlightVersion1` UInt8, `Age` UInt8, `Sex` UInt8, `Income` UInt8, `JavaEnable` UInt8, `CookieEnable` UInt8, `JavascriptEnable` UInt8, `IsMobile` UInt8, `BrowserLanguage` UInt16, `BrowserCountry` UInt16, `Interests` UInt16, `Robotness` UInt8, `GeneralInterests` Array(UInt16), `Params` Array(String), `Goals` Nested( ID UInt32, Serial UInt32, EventTime DateTime, Price Int64, OrderID String, CurrencyID UInt32), `WatchIDs` Array(UInt64), `ParamSumPrice` Int64, `ParamCurrency` FixedString(3), `ParamCurrencyID` UInt16, `ClickLogID` UInt64, `ClickEventID` Int32, `ClickGoodEvent` Int32, `ClickEventTime` DateTime, `ClickPriorityID` Int32, `ClickPhraseID` Int32, `ClickPageID` Int32, `ClickPlaceID` Int32, `ClickTypeID` Int32, `ClickResourceID` Int32, `ClickCost` UInt32, `ClickClientIP` UInt32, `ClickDomainID` UInt32, `ClickURL` String, `ClickAttempt` UInt8, `ClickOrderID` UInt32, `ClickBannerID` UInt32, `ClickMarketCategoryID` UInt32, `ClickMarketPP` UInt32, `ClickMarketCategoryName` String, `ClickMarketPPName` String, `ClickAWAPSCampaignName` String, `ClickPageName` String, `ClickTargetType` UInt16, `ClickTargetPhraseID` UInt64, `ClickContextType` UInt8, `ClickSelectType` Int8, `ClickOptions` String, `ClickGroupBannerID` Int32, `OpenstatServiceName` String, `OpenstatCampaignID` String, `OpenstatAdID` String, `OpenstatSourceID` String, `UTMSource` String, `UTMMedium` String, `UTMCampaign` String, `UTMContent` String, `UTMTerm` String, `FromTag` String, `HasGCLID` UInt8, `FirstVisit` DateTime, `PredLastVisit` Date, `LastVisit` Date, `TotalVisits` UInt32, `TraficSource` Nested( ID Int8, SearchEngineID UInt16, AdvEngineID UInt8, PlaceID UInt16, SocialSourceNetworkID UInt8, Domain String, SearchPhrase String, SocialSourcePage String), `Attendance` FixedString(16), `CLID` UInt32, `YCLID` UInt64, `NormalizedRefererHash` UInt64, `SearchPhraseHash` UInt64, `RefererDomainHash` UInt64, `NormalizedStartURLHash` UInt64, `StartURLDomainHash` UInt64, `NormalizedEndURLHash` UInt64, `TopLevelDomain` UInt64, `URLScheme` UInt64, `OpenstatServiceNameHash` UInt64, `OpenstatCampaignIDHash` UInt64, `OpenstatAdIDHash` UInt64, `OpenstatSourceIDHash` UInt64, `UTMSourceHash` UInt64, `UTMMediumHash` UInt64, `UTMCampaignHash` UInt64, `UTMContentHash` UInt64, `UTMTermHash` UInt64, `FromHash` UInt64, `WebVisorEnabled` UInt8, `WebVisorActivity` UInt32, `ParsedParams` Nested( Key1 String, Key2 String, Key3 String, Key4 String, Key5 String, ValueDouble Float64), `Market` Nested( Type UInt8, GoalID UInt32, OrderID String, OrderPrice Int64, PP UInt32, DirectPlaceID UInt32, DirectOrderID UInt32, DirectBannerID UInt32, GoodID String, GoodName String, GoodQuantity Int32, GoodPrice Int64), `IslandID` FixedString(16))ENGINE = CollapsingMergeTree(Sign)PARTITION BY toYYYYMM(StartDate)ORDER BY (CounterID, StartDate, intHash32(UserID), VisitID)SAMPLE BY intHash32(UserID)
您可以使用clickhouse-client的交互模式执行这些查询(只需在终端中启动它,而不需要提前指定查询)。或者如果你愿意,可以尝试一些替代接口。
正如我们所看到的, hits_v1使用 MergeTree引擎,而visits_v1使用 Collapsing引擎。
导入数据
数据导入到ClickHouse是通过INSERT INTO方式完成的,查询类似许多SQL数据库。然而,数据通常是在一个提供支持序列化格式而不是VALUES子句(也支持)。
我们之前下载的文件是以制表符分隔的格式,所以这里是如何通过控制台客户端导入它们:
clickhouse-client --query "INSERT INTO tutorial.hits_v1 FORMAT TSV" --max_insert_block_size=100000 < hits_v1.tsvclickhouse-client --query "INSERT INTO tutorial.visits_v1 FORMAT TSV" --max_insert_block_size=100000 < visits_v1.tsv
ClickHouse有很多要调整的设置在控制台客户端中指定它们的一种方法是通过参数,就像我们看到上面语句中的--max_insert_block_size。找出可用的设置、含义及其默认值的最简单方法是查询system.settings 表:
SELECT name, value, changed, descriptionFROM system.settingsWHERE name LIKE '%max_insert_b%'FORMAT TSVmax_insert_block_size 1048576 0 "The maximum block size for insertion, if we control the creation of blocks for insertion."
您也可以OPTIMIZE导入后的表。使用MergeTree-family引擎配置的表总是在后台合并数据部分以优化数据存储(或至少检查是否有意义)。 这些查询强制表引擎立即进行存储优化,而不是稍后一段时间执行:
clickhouse-client --query "OPTIMIZE TABLE tutorial.hits_v1 FINAL"clickhouse-client --query "OPTIMIZE TABLE tutorial.visits_v1 FINAL"
这些查询开始I/O和CPU密集型操作,所以如果表一直接收到新数据,最好不要管它,让合并在后台运行。
现在我们可以检查表导入是否成功:
clickhouse-client --query "SELECT COUNT(*) FROM tutorial.hits_v1"clickhouse-client --query "SELECT COUNT(*) FROM tutorial.visits_v1"
查询示例
SELECT StartURL AS URL, AVG(Duration) AS AvgDurationFROM tutorial.visits_v1WHERE StartDate BETWEEN '2014-03-23' AND '2014-03-30'GROUP BY URLORDER BY AvgDuration DESCLIMIT 10
SELECT sum(Sign) AS visits, sumIf(Sign, has(Goals.ID, 1105530)) AS goal_visits, (100. * goal_visits) / visits AS goal_percentFROM tutorial.visits_v1WHERE (CounterID = 912887) AND (toYYYYMM(StartDate) = 201403) AND (domain(StartURL) = 'yandex.ru')
集群部署
ClickHouse集群是一个同质集群。 设置步骤:
- 在群集的所有机器上安装ClickHouse服务端
- 在配置文件中设置集群配置
- 在每个实例上创建本地表
- 创建一个分布式表
分布式表实际上是一种view,映射到ClickHouse集群的本地表。 从分布式表中执行SELECT查询会使用集群所有分片的资源。 您可以为多个集群指定configs,并创建多个分布式表,为不同的集群提供视图。
具有三个分片,每个分片一个副本的集群的示例配置:
<remote_servers> <perftest_3shards_1replicas> <shard> <replica> <host>example-perftest01j.yandex.ru</host> <port>9000</port> </replica> </shard> <shard> <replica> <host>example-perftest02j.yandex.ru</host> <port>9000</port> </replica> </shard> <shard> <replica> <host>example-perftest03j.yandex.ru</host> <port>9000</port> </replica> </shard> </perftest_3shards_1replicas></remote_servers>
为了进一步演示,让我们使用和创建hits_v1表相同的CREATE TABLE语句创建一个新的本地表,但表名不同:
CREATE TABLE tutorial.hits_local (...) ENGINE = MergeTree() ...
创建提供集群本地表视图的分布式表:
CREATE TABLE tutorial.hits_all AS tutorial.hits_localENGINE = Distributed(perftest_3shards_1replicas, tutorial, hits_local, rand());
常见的做法是在集群的所有计算机上创建类似的分布式表。 它允许在群集的任何计算机上运行分布式查询。 还有一个替代选项可以使用以下方法为给定的SELECT查询创建临时分布式表远程表功能。
让我们运行INSERT SELECT将该表传播到多个服务器。
INSERT INTO tutorial.hits_all SELECT * FROM tutorial.hits_v1;
!!! warning "注意:" 这种方法不适合大型表的分片。 有一个单独的工具 clickhouse-copier 这可以重新分片任意大表。
正如您所期望的那样,如果计算量大的查询使用3台服务器而不是一个,则运行速度快N倍。
在这种情况下,我们使用了具有3个分片的集群,每个分片都包含一个副本。
为了在生产环境中提供弹性,我们建议每个分片应包含分布在多个可用区或数据中心(或至少机架)之间的2-3个副本。 请注意,ClickHouse支持无限数量的副本。
包含三个副本的一个分片集群的示例配置:
<remote_servers> ... <perftest_1shards_3replicas> <shard> <replica> <host>example-perftest01j.yandex.ru</host> <port>9000</port> </replica> <replica> <host>example-perftest02j.yandex.ru</host> <port>9000</port> </replica> <replica> <host>example-perftest03j.yandex.ru</host> <port>9000</port> </replica> </shard> </perftest_1shards_3replicas></remote_servers>
启用本机复制Zookeeper是必需的。 ClickHouse负责所有副本的数据一致性,并在失败后自动运行恢复过程。建议将ZooKeeper集群部署在单独的服务器上(其中没有其他进程,包括运行的ClickHouse)。
!!! note "注意" ZooKeeper不是一个严格的要求:在某些简单的情况下,您可以通过将数据写入应用程序代码中的所有副本来复制数据。 这种方法是不建议的,在这种情况下,ClickHouse将无法保证所有副本上的数据一致性。 因此需要由您的应用来保证这一点。
ZooKeeper位置在配置文件中指定:
<zookeeper> <node> <host>zoo01.yandex.ru</host> <port>2181</port> </node> <node> <host>zoo02.yandex.ru</host> <port>2181</port> </node> <node> <host>zoo03.yandex.ru</host> <port>2181</port> </node></zookeeper>
此外,我们需要设置宏来识别每个用于创建表的分片和副本:
<macros> <shard>01</shard> <replica>01</replica></macros>
如果在创建复制表时没有副本,则会实例化新的第一个副本。 如果已有实时副本,则新副本将克隆现有副本中的数据。 您可以选择首先创建所有复制的表,然后向其中插入数据。 另一种选择是创建一些副本,并在数据插入之后或期间添加其他副本。
CREATE TABLE tutorial.hits_replica (...)ENGINE = ReplcatedMergeTree( '/clickhouse_perftest/tables/{shard}/hits', '{replica}')...
在这里,我们使用ReplicatedMergeTree表引擎。 在参数中,我们指定包含分片和副本标识符的ZooKeeper路径。
INSERT INTO tutorial.hits_replica SELECT * FROM tutorial.hits_local;
复制在多主机模式下运行。数据可以加载到任何副本中,然后系统自动将其与其他实例同步。复制是异步的,因此在给定时刻,并非所有副本都可能包含最近插入的数据。至少应该有一个副本允许数据摄入。另一些则会在重新激活后同步数据并修复一致性。请注意,这种方法允许最近插入的数据丢失的可能性很低。
文章下方有交流学习区!一起学习进步!也可以前往官网,加入官方微信交流群 你的支持和鼓励是我创作的动力❗❗❗
Doker的成长,欢迎大家一起陪伴!!!
我发好文,兄弟们有空请把我的官方旗舰店流量撑起来!!!
官网:Doker 多克; 官方旗舰店:Doker 多克 官方旗舰店-淘宝网 全品优惠