柴少的官方网站 技术在学习中进步,水平在分享中升华

ClickHouse安装及简单使用(一)

ClickHouse是近年来备受关注的开源列式数据库,主要用于数据分析(OLAP)领域,很多大厂都在使用,网上介绍的文章一搜有很多就不过介绍了。

官网:https://clickhouse.com/

官网文档:https://clickhouse.com/docs/en/architecture/introduction

一、ClickHouse单机安装

# grep -q sse4_2 /proc/cpuinfo && echo "SSE 4.2 supported" || echo "SSE 4.2 not supported"  #检查当前CPU是否支持SSE 4.2的命令

SSE 4.2 supported

1.1 yum安装

#yum install -y yum-utils

#yum-config-manager --add-repo https://packages.clickhouse.com/rpm/clickhouse.repo

#yum install -y clickhouse-server clickhouse-client

#/etc/init.d/clickhouse-server start

1.2 rpm安装

#wget https://packages.clickhouse.com/rpm/stable/clickhouse-client-24.6.2.17.x86_64.rpm

#wget https://packages.clickhouse.com/rpm/stable/clickhouse-common-static-24.6.2.17.x86_64.rpm

#wget https://packages.clickhouse.com/rpm/stable/clickhouse-common-static-dbg-24.6.2.17.x86_64.rpm

#wget https://packages.clickhouse.com/rpm/stable/clickhouse-server-24.6.2.17.x86_64.rpm

#rpm -ivh clickhouse-common-static-24.6.2.17.x86_64.rpm 

#rpm -ivh clickhouse-common-static-dbg-24.6.2.17.x86_64.rpm

#rpm -ivh clickhouse-server-24.6.2.17.x86_64.rpm

#rpm -ivh clickhouse-client-24.6.2.17.x86_64.rpm 

#/etc/init.d/clickhouse-server start

1.3 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_VERSION

case $(uname -m) in
  x86_64) ARCH=amd64 ;;
  aarch64) ARCH=arm64 ;;
  *) echo "Unknown architecture $(uname -m)"; exit 1 ;;
esac

for PKG in clickhouse-common-static clickhouse-common-static-dbg clickhouse-server clickhouse-client
do
  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"
done
tar -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" configure
sudo /etc/init.d/clickhouse-server start

tar -xzvf "clickhouse-client-$LATEST_VERSION-${ARCH}.tgz" \
  || tar -xzvf "clickhouse-client-$LATEST_VERSION.tgz"
sudo "clickhouse-client-$LATEST_VERSION/install/doinst.sh"

对于生产环境,建议使用最新的stable版本。你可以在GitHub页面https://github.com/ClickHouse/ClickHouse/tags找到它,它以后缀`-stable`标志。

二、跟着官网学习一些Deploying的知识

2.1 Terminology(术语)

Replica(副本)

数据副本。ClickHouse始终至少有一个数据副本,因此副本的最小数量为一个。这是一个重要的细节,你可能不习惯将数据的原始副本视为副本,但这是ClickHouse代码和文档中使用的术语。添加数据的第二个副本可以提供容错性。

Shard(分片)

数据的子集。ClickHouse总是至少有一个数据分片,所以如果你不在多个服务器上分割数据,你的数据将存储在一个分片中。如果你超过了单个服务器的容量,则可以使用跨多个服务器的分片数据来分担负载。目标服务器由分片键决定,并在创建分布式表时定义。分片键可以是随机的,也可以作为哈希函数的输出。涉及分片的部署示例将使用rand()作为分片键,并将提供有关何时以及如何选择不同分片键的进一步信息。

Distributed coordination(分布式协调)

ClickHouse Keeper为数据复制和分布式DDL查询的执行提供了协调系统。ClickHouse Keeper与Apache ZooKeeper兼容。

2.2 Scaling out(扩展)

此示例架构旨在提供可扩展性。它包括三个节点:两个组合的ClickHouse+协调(ClickHouse Keeper)服务器,以及一个只有ClickHouse Keeper的第三个服务器以完成三个指定ClickHouse Keeper节点数的仲裁。在本例中,我们将创建一个数据库、一个表和一个分布式表,它们将能够查询两个节点上的数据。

Environment(环境)

Architecture Diagram(架构图)

image.png

在生产环境中,官方是强烈建议ClickHouse Keeper在专用主机上运行。

Editing configuration files(编辑配置文件)

最佳实践,通过添加或编辑配置文件配置ClickHouse Server时,你应该:

将文件添加到/etc/clickhouse服务器/config.d/目录
将文件添加到/etc/clickhouse服务器/users.d/目录
保持/etc/clickhouse服务器/config.xml文件不变
保持/etc/clickhouse server/users.xml文件不变

chnode1 configuration

对于chnode1,有五个配置文件。可以选择将这些文件合并为一个文件,但为了文档的清晰性,单独查看它们可能更简单。当你阅读配置文件时,你会发现chnode1和chnode2之间的大部分配置都是相同的;差异将被突出显示。

Network and logging configuration(网络和日志配置)

#所有的参数配置说明:https://clickhouse.com/docs/en/operations/server-configuration-parameters/settings

这些值可以根据需要进行自定义。此示例配置为您提供了一个调试日志,该日志将以1000M的大小切割滚动三次。ClickHouse将在端口8123和9000上监听IPv4网络,并将使用端口9009进行服务器间通信。network-and-logging.xml on chnode1

<clickhouse>
   <logger>
     <!--日志级别,none(关闭输出)/fatal(致命)/critical(关键)/error/warning/notice(通知)/information/debug/trace/test(不用于生产)--> 
     <level>debug</level>
     <log>/var/log/clickhouse-server/clickhouse-server.log</log>
     <errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
     <size>1000M</size>
     <count>3</count>
   </logger>
   <!--这个名称将显示在clickhouse-client中。默认情况下,任何带有"production"的内容都将在查询提示符中以红色突出显示。-->
   <display_name>clickhouse</display_name>
   <listen_host>0.0.0.0</listen_host>
   <!--HTTP API的端口。这个接口也被ODBC和JDBC驱动程序(DataGrip, Dbeaver,…)使用。以及大多数web界面(嵌入式UI、Grafana、Redash等)。-->
   <http_port>8123</http_port>
   <!--通过本机协议与以下设备进行交互的端口:clickhouse-client/clickhouse-server/ClickHouse驱动程序和支持本机协议的应用程序 -->
   <tcp_port>9000</tcp_port>
   <!--副本之间通信的端口。用于数据交换。它提供服务器之间的 low-level数据访问。此端口不应从不受信任的网络访问。-->
   <interserver_http_port>9009</interserver_http_port>
</clickhouse>

ClickHouse Keeper configuration(ClickHouse Keeper得配置

      ClickHouse Keeper为数据复制和分布式DDL查询执行提供了协调系统。ClickHouse Keeper与Apache ZooKeeper兼容。此配置在端口9181上启用ClickHouse Keeper。突出显示的行指定此Keeper实例的server_id为1。这是三台服务器上enable-keeper.xml文件的唯一区别。chnode2的server_id将设置为2,chnode3的server_id设置为3。raft配置部分在所有三台服务器上都是相同的,下面突出显示的是raft配置中server_id和服务器实例之间的关系。

     如果出于任何原因替换或重建了Keeper节点,请不要重用现有的server_id。例如,如果重建了server_id为2的Keeper节点,则将其设置为server_id为4或更高。enable-keeper.xml on chnode1

#文件中的配置含义在:https://clickhouse.com/docs/en/guides/sre/keeper/clickhouse-keeper#keeper-configuration-settings

<clickhouse>
  <keeper_server>
    <!--客户端连接的端口--> 
    <tcp_port>9181</tcp_port>
    <!--唯一的服务器id, ClickHouse Keeper集群的每个参与者必须有一个唯一的数字(1、2、3,等等)。-->
    <server_id>1</server_id>
    <!--协调日志的路径,就像ZooKeeper一样,最好将日志存储在非繁忙节点上。-->
    <log_storage_path>/var/lib/clickhouse/coordination/log</log_storage_path>
    <!--coordination快照的路径-->
    <snapshot_storage_path>/var/lib/clickhouse/coordination/snapshots</snapshot_storage_path>

    <coordination_settings>
        <!--单个客户端操作的超时时间(ms),默认值是10000-->
        <operation_timeout_ms>10000</operation_timeout_ms>
        <!--客户端会话最小超时时间(ms),默认值是10000-->
        <session_timeout_ms>30000</session_timeout_ms>
        <!--coordination的文本日志级别-->
        <raft_logs_level>trace</raft_logs_level>
    </coordination_settings>

    <raft_configuration>
        <server>
            <!--仲裁中的服务器标识符。-->
            <id>1</id>
            <!--服务器所在的主机名-->
            <hostname>chnode1</hostname>
            <!--此服务器侦听连接的端口-->
            <port>9234</port>
        </server>
        <server>
            <id>2</id>
            <hostname>chnode2</hostname>
            <port>9234</port>
        </server>
        <server>
            <id>3</id>
            <hostname>chnode3</hostname>
            <port>9234</port>
        </server>
    </raft_configuration>
  </keeper_server>
</clickhouse>

Macros configuration(宏配置)

       宏分片和副本降低了分布式DDL的复杂性。配置的值会在DDL查询中自动替换,从而简化DDL。此配置的宏指定了每个节点的分片和副本编号。在这个2分片1副本的示例中,由于只有一个副本,因此副本宏在chnode1和chnode2上都是replica_1。分片宏在chnode1上为1,在chnode2上为2。

macros.xml on chnode1

<clickhouse>
  <macros>
    <shard>1</shard>
    <replica>replica_1</replica>
  </macros>
</clickhouse>

Replication and sharding configuration(副本和分配配置)

从上面开始:

      XML的remote_servers部分指定了环境中的每个集群。replace=true属性将默认ClickHouse配置中的示例remote_servers替换为此文件中指定的remote_server配置。如果没有此属性,默认情况下,此文件中的远程服务器将附加到示例列表中。

      在这个例子中,有一个名为cluster_2S_1R的集群。

      为名为cluster_2S_1R的集群创建一个secret,其值为mysecretphrase。secret在环境中的所有远程服务器之间共享,以确保将正确的服务器连接在一起。

      集群cluster_2S_1R有两个分片,每个分片有一个副本。看一下本文开头的架构图,并将其与下面XML中的两个分片定义进行比较。在每个分片定义中都有一个副本。副本是针对该特定分片的。指定该副本的主机和端口。配置中第一个分片的副本存储在chnode1上,第二个分片的副本存储在chnode2上。

      将分片的内部复制设置为true。每个shard都可以在配置文件中定义internal_replication参数。如果该参数设置为true,则写操作将选择第一个健康副本并向其写入数据。remote-servers.xml on chnode1

<clickhouse>
  <remote_servers replace="true">
    <cluster_2S_1R>
    <secret>mysecretphrase</secret>
        <shard>
            <!--可选的。是否只向其中一个副本写入数据。默认值:false(向所有副本写入数据)。--> 
            <internal_replication>true</internal_replication>
            <replica>
                <host>chnode1</host>
                <port>9000</port>
            </replica>
        </shard>
        <shard>
            <internal_replication>true</internal_replication>
            <replica>
                <host>chnode2</host>
                <port>9000</port>
            </replica>
        </shard>
    </cluster_2S_1R>
  </remote_servers>
</clickhouse>

Configuring the use of Keeper(配置Keeper的使用)

上面配置了几个文件ClickHouse Keeper。此配置文件use-keeper.xml正在将ClickHouse Server配置为使用ClickHouse keeper来协调复制和分布式DDL。此文件指定ClickHouse服务器应在端口9181上的节点chnode1-3上使用Keeper,并且chnode1和chnode2上的文件相同。use-keeper.xml on chnode1

<clickhouse>
    <zookeeper>
        <node index="1">
            <host>chnode1</host>
            <port>9181</port>
        </node>
        <node index="2">
            <host>chnode2</host>
            <port>9181</port>
        </node>
        <node index="3">
            <host>chnode3</host>
            <port>9181</port>
        </node>
    </zookeeper>
</clickhouse>

chnode2 configuration

network-and-logging.xml on chnode2(无变化)

enable-keeper.xml on chnode2   #只记录变化的地方

    <server_id>2</server_id>

macros.xml on chnode2 #只记录变化的地方

    <shard>2</shard>

remote-servers.xml on chnode2  #无变化

use-keeper.xml on chnode2  #无变化

chnode3 configuration

由于chnode3不存储数据,仅用于ClickHouse Keeper提供仲裁中的第三个节点,所以安装的软件和配置文件也有所不同:

#yum install clickhouse-keeper -y

# vim /etc/clickhouse-keeper/keeper_config.xml

<clickhouse>
    <logger>
        <level>error</level>
        <log>/var/log/clickhouse-keeper/clickhouse-keeper.log</log>
        <errorlog>/var/log/clickhouse-keeper/clickhouse-keeper.err.log</errorlog>
        <size>1000M</size>
        <count>3</count>
    </logger>
    <listen_host>0.0.0.0</listen_host>
    <keeper_server>
        <tcp_port>9181</tcp_port>
        <server_id>3</server_id>
        <log_storage_path>/var/lib/clickhouse/coordination/log</log_storage_path>
        <snapshot_storage_path>/var/lib/clickhouse/coordination/snapshots</snapshot_storage_path>
        <coordination_settings>
            <operation_timeout_ms>10000</operation_timeout_ms>
            <session_timeout_ms>30000</session_timeout_ms>
            <raft_logs_level>trace</raft_logs_level>
        </coordination_settings>
        <raft_configuration>
            <server>
                <id>1</id>
                <hostname>192.168.1.164</hostname>
                <port>9234</port>
            </server>
            <server>
                <id>2</id>
                <hostname>192.168.1.165</hostname>
                <port>9234</port>
            </server>
            <server>
                <id>3</id>
                <hostname>192.168.1.166</hostname>
                <port>9234</port>
            </server>
        </raft_configuration>
    </keeper_server>
</clickhouse>

# mkdir /var/lib/clickhouse-keeper && chown  clickhouse:clickhouse  /var/lib/clickhouse-keeper  

# systemctl restart clickhouse-keeper 

# ps aux|grep click

/usr/bin/clickhouse-keeper --config=/etc/clickhouse-keeper/keeper_config.xml --pid-file=/run/clickhouse-keeper/clickhouse-keeper.pid

# netstat -lntup|grep click

tcp        0      0 0.0.0.0:9181            0.0.0.0:*               LISTEN      29561/clickhouse-ke 
tcp6       0      0 :::9234                 :::*                    LISTEN      29561/clickhouse-ke

测试:

#按照上面在1/2台机器上面配置一下,我这里直接用的IP省的配置hosts了,执行一下:/etc/init.d/clickhouse-server restart  就可以关注三台服务器的进程是否启动了。

#特别注意,clickhouse-server的启动出错提示比较少,如果你的服务一直等待启动Waiting for server to start可以看看配置文件和指定的目录是不是clickhouse用户授权,或者配置文件肯定是有改动错误的地方,如果觉得日志刷的太狠了,可以把日志级别调一下

#每个机器都可以执行一下#  echo mntr | nc 127.0.0.1 9181  可以看zk_server_state这个字段会显示leader还是follower

# ps -aux|grep clickhouse  #先看下进程image.png

# netstat -lntup|grep clickhouse|sort -k 3  #再查看下监听端口

image.png

1.连接到chnode1并验证上面配置的集群cluster_2S_1R是否存在

# clickhouse-client   #默认是没有密码的,默认只有default用户,可以在users.xml这里为这个用户设置密码,比如<password>123456</password>

image.png

2.在集群上创建数据库

CREATE DATABASE db1 ON CLUSTER cluster_2S_1R;

3.在集群上使用MergeTree表引擎创建表

#我们不需要在表引擎上指定参数,因为这些参数将根据我们的宏自动定义

CREATE TABLE db1.table1 ON CLUSTER cluster_2S_1R
(
    `id` UInt64,
    `column1` String
)
ENGINE = MergeTree
ORDER BY id

4.连接到chnode1并插入一行

INSERT INTO db1.table1 (id, column1) VALUES (1, 'abc');

5.连接到chnode2并插入一行

INSERT INTO db1.table1 (id, column1) VALUES (2, 'def');

6.连接到任一节点chnode1或chnode2,将只看到该节点上插入该表的行。例如,在chnode2上什么都查不到,因为是在chnode1上面做的操作

SELECT * FROM db1.table1;

7.创建一个分布式表来查询两个节点上的两个分片。(在本例中,rand()函数被设置为分片键,因此它随机分配每次插入)

CREATE TABLE db1.table1_dist ON CLUSTER cluster_2S_1R
(
    `id` UInt64,
    `column1` String
)
ENGINE = Distributed('cluster_2S_1R', 'db1', 'table1', rand())

#为什么先创建本地表再创建分布式表?

Clickhouse是分布式系统,先在每个Shard 每个节点上创建本地表(即 Shard 的副本),本地表只在对应节点内可见;然后再创建分布式表[Distributed],映射到前面创建的本地表。用户在访问分布式表时,ClickHouse 会自动根据集群架构信息,把请求转发给对应的本地表。

8.连接到chnode1或chnode2,查询分布式表以查看插入的数据,两个节点查看到的数据是一致的了。

 SELECT * FROM db1.table1_dist;

image.png

博文来自:www.51niux.com

2.3 Replication for fault tolerance(容错复制)

在此架构中,配置了五台服务器。两个用于托管数据副本。其他三台服务器用于协调数据的复制。通过这个例子,我们将创建一个数据库和表,使用ReplicatedMergeTree表引擎在两个数据节点之间复制。

image.png

clickhouse-01 configuration

# vim /etc/clickhouse-server/config.d/network-and-logging.xml

<clickhouse>
    <logger>
        <level>debug</level>
        <log>/var/log/clickhouse-server/clickhouse-server.log</log>
        <errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
        <size>1000M</size>
        <count>3</count>
    </logger>
    <!--连接clickhouse-client时显示的名称为cluster_1S_2R node 1-->
    <display_name>cluster_1S_2R node 1</display_name>
    <listen_host>0.0.0.0</listen_host>
    <http_port>8123</http_port>
    <tcp_port>9000</tcp_port>
</clickhouse>

# vim /etc/clickhouse-server/config.d/macros.xml

macros shard and replica降低了分布式DDL的复杂性。配置的值会在DDL查询中自动替换,从而简化DDL。此配置的宏指定了每个节点的分片和副本编号。

在这个1分片2副本的示例中,replica macro在clickhouse-01上是replica_1,在clickhouse-02上是replica _2。在clickhouse-01和clickhouse-02上,shard macro都是1,因为只有一个分片。

<clickhouse>
    <macros>
        <shard>01</shard>
        <replica>01</replica>
        <cluster>cluster_1S_2R</cluster>
    </macros>
</clickhouse>

# vim /etc/clickhouse-server/config.d/remote-servers.xml

<clickhouse>
    <remote_servers replace="true">
        <cluster_1S_2R>
            <secret>mysecretphrase</secret>
            <shard>
                <internal_replication>true</internal_replication>
                <replica>
                    <host>192.168.1.164</host>
                    <port>9000</port>
                </replica>
                <replica>
                    <host>192.168.1.165</host>
                    <port>9000</port>
                </replica>
            </shard>
        </cluster_1S_2R>
    </remote_servers>
</clickhouse>

# vim /etc/clickhouse-server/config.d/use-keeper.xml   #指定使用哪三台clickhouse-keeper节点

<clickhouse>
    <zookeeper>
        <!-- where are the ZK nodes -->
        <node>
            <host>192.168.1.166</host>
            <port>9181</port>
        </node>
        <node>
            <host>192.168.1.167</host>
            <port>9181</port>
        </node>
        <node>
            <host>192.168.1.168</host>
            <port>9181</port>
        </node>
    </zookeeper>
</clickhouse>

clickhouse-02 configuration

#只列出差异部分

# vim /etc/clickhouse-server/config.d/network-and-logging.xml

<display_name>cluster_1S_2R node 2</display_name>

# vim /etc/clickhouse-server/config.d/macros.xml

        <replica>02</replica>

clickhouse-keeper-01 configuration

ClickHouse Keeper为数据复制和分布式DDL查询的执行提供了协调系统。ClickHouse Keeper与Apache ZooKeeper兼容。此配置在端口9181上启用ClickHouse Keeper。突出显示的行指定此Keeper实例的server_id为1。这是三个服务器之间enable-keeper.xml文件的唯一不同之处。Clickhouse-keeper-02将有server_id设置为2,clickhouse-keeper-03将有server_id设置为3。

#配置文件/etc/clickhouse-keeper/keeper_config.xml参照前面的配置文件吧就server_id地方node1是1,node2是2,node3是3就行了。

clickhouse-keeper-02 configuration

<server_id>2</server_id>

clickhouse-keeper-03 configuration

<server_id>3</server_id>

测试

使用一个shell中的clickhouse客户端连接到节点clickhouse-01,并使用另一个shell的clickhouse客户机连接到节点clickhouse-02。

1.在上面配置的集群上创建数据库

cluster_1S_2R node 1 :) CREATE DATABASE db2 ON CLUSTER cluster_1S_2R;

2.使用ReplicatedMergeTree表引擎在数据库上创建表

CREATE TABLE db2.table1 ON CLUSTER cluster_1S_2R
(
    `id` UInt64,
    `column1` String
)
ENGINE = ReplicatedMergeTree
ORDER BY id

3.在node1结点上面插入数据,在node2节点上面查询,发现是可以查询到数据的,反之亦然

INSERT INTO db2.table1 (id, column1) VALUES (1, 'abc');
SELECT * FROM db2.table1;

4.现在我们通过命令# /etc/init.d/clickhouse-server stop  把node1节点停掉,然后在node2上面执行命令插入一条数据,然后再查看一下会发现三条数据都是在的

cluster_1S_2R node 2 :) INSERT INTO db2.table1 (id, column1) VALUES (3, 'ghi');
cluster_1S_2R node 2 :) SELECT * FROM db2.table1;

5.将停掉的node1启动起来# /etc/init.d/clickhouse-server start,然后在上面查询一下,会发现数据也是全的,因为每个Node节点都是全量数据:

cluster_1S_2R node 1 :) SELECT * FROM db2.table1;

image.png

2.4 Sizing and Hardware Recommendations(规模和硬件建议)

详细的看:https://clickhouse.com/docs/en/guides/sizing-and-hardware-recommendations
这里就列下内存说明:

内存与存储的比率应该是多少?

对于低数据量,1:1的内存与存储比是可以接受的,但总内存不应低于8GB。

对于数据保留期较长或数据量较大的用例,建议采用1:100至1:130的内存与存储比。例如,如果要存储10TB的数据,则每个副本需要100GB的RAM。

对于频繁访问的用例,例如面向客户的工作负载,建议以1:30到1:50的内存与存储比率使用更多内存。

2.5 List of tools and utilities(工具和实用程序列表)

clickhouse-local #允许在不启动ClickHouse服务器的情况下对数据运行SQL查询,类似于awk的做法
clickhouse-benchmark #用自定义查询和设置加载服务
clickhouse-format #支持格式化输入查询
ClickHouse obfuscator #混淆数据
ClickHouse compressor #压缩和解压缩数据
clickhouse-disks #在不同ClickHouse磁盘之间的文件上提供类似文件系统的操作
clickhouse-odbc-bridge #ODBC驱动程序的代理服务器
clickhouse_backupview #分析ClickHouse备份的python模块

三、性能监控

ClickHouse 从 v20.1.2.4 开始,内置了对接 Prometheus 的功能,可以将其作为 Prometheus 的 Endpoint 服务,从而自动的将 metrics、events 和 asynchronous_metrics(主要用于统计服务运行过程的时候,当前正在后台异步运行的信息) 三张系统的表的数据发送给 Prometheus。

cluster_1S_2R node 1 :) select count(*) from system.metrics;
cluster_1S_2R node 1 :) select count(*) from system.events;
cluster_1S_2R node 1 :) select count(*) from system.asynchronous_metrics;

3.1 ClickHouse开启内置的endpoint功能

# vim /etc/clickhouse-server/config.xml   #将关于prometheus的注释部分去掉并重启服务

    <prometheus>
        <endpoint>/metrics</endpoint>
        <port>9363</port>

        <metrics>true</metrics>
        <events>true</events>
        <asynchronous_metrics>true</asynchronous_metrics>
    </prometheus>

#curl 127.0.0.1:9363/metrics |more   #可以查看一下都有哪些指标,不过指标太多了不到2000个所以加了个more,后面可以只保留一些需要的指标

3.2 prometheus配置采集

# vim /opt/soft/prometheus/prometheus.yml  #新增job_name,并重新加载

    - job_name: 'clickhouse'
      static_configs:
        - targets: ['192.168.1.164:9363','192.168.1.165:9363']

3.3 grafana出图展示

#去官网上面找一个模版下载下来,以prometheus为数据源自己修改修改

image.png

博文来自:www.51niux.com

4、日志采集

clickhouse集群部署起来了,我们得往里面写入些数据啊,比如我们把nginx的日志存储进去进行分析。这里使用Vector+ClickHouse来采集Nginx日志并做清洗,最终插入到clickhouse存储起来。Vector 是一个用于构建数据传输 pipeline 的工具。它开箱即用支持 ClickHouse。使用 Vector Remap Language (VRL) 可以对日志进行清洗,把非结构化的数据清洗成结构化数据。

官网文档:https://vector.dev/docs/

4.1 Vector 安装

#wget https://packages.timber.io/vector/0.39.0/vector-0.39.0-x86_64-unknown-linux-gnu.tar.gz

#tar xf vector-0.39.0-x86_64-unknown-linux-gnu.tar.gz

#cp -rf /opt/soft/package/vector-x86_64-unknown-linux-gnu /opt/soft/vector
# cd /opt/soft/vector/

./bin/vector --version   #执行下命令看看会不会报错

vector 0.39.0 (x86_64-unknown-linux-gnu......)

我们先看下我们当前的nginx日志格式:

    log_format  main  '$http_host $remote_addr - $remote_user $time_iso8601 '
                      '$scheme "$request" $status $bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" "$gzip_ratio" $request_time '
                      '$upstream_addr $upstream_status $upstream_response_time';

我们先什么都不做处理,先把nginx的日志采集一下

#然后需要先在clickhouse上面创建对应的数据库和表:

cluster_1S_2R node 1 :) CREATE DATABASE nginxdb  ON CLUSTER cluster_1S_2R;
cluster_1S_2R node 1 :) CREATE TABLE nginxdb.access_logs ON CLUSTER cluster_1S_2R (message String) ENGINE = MergeTree() ORDER BY tuple();

然后配置nginx上面的vector的配置文件进行日志采集:

# cat /opt/soft/vector/config/test/nginx.yaml   #先不做任何过滤,先把日志采集一下

data_dir: "/var/log/vector"
sources:
  nginx_logs:
    type: "file"
    include: [ "/opt/log/nginx/app.test.cn/app.test.cn_access.log" ]
    read_from: "end"

sinks:
  clickhouse:
    type: "clickhouse"
    inputs: ["nginx_logs"]
    endpoint: "http://192.168.1.164:8123"
    database: "nginxdb"
    table: "access_logs"
    skip_unknown_fields: true
    auth:
      user: default
      password: "123456"
      strategy: basic

4.2 构建物理视图

我们先查看一下采集上来的数据

cluster_1S_2R node 1 :) select * from nginxdb.access_logs limit  2\G

下面是查询结果:

SELECT *
FROM nginxdb.access_logs
LIMIT 2

Query id: e67245bf-2509-4623-840f-45fc0a0c4b72

Row 1:
──────
message: app.test.cn 123.199.53.68 - - 2024-05-26T11:13:28+08:00 http "POST /app/uplog/ HTTP/1.1" 200 402 "-" "Dalvik/2.1.0 (Linux; U; Android 10; VCE-AL00 Build/HUAWEIVCE-AL00)" "-" "-" 0.014 192.168.1.228:38007 200 0.013

Row 2:
──────
message: app.test.cn 123.199.53.69 - - 2024-05-26T11:14:14+08:00 http "POST /app/uplog/ HTTP/1.1" 200 402 "-" "Dalvik/2.1.0 (Linux; U; Android 10; PBDM00 Build/QKQ1.190918.001)" "-" "-" 0.004 192.168.1.228:38007 200 0.004

2 rows in set. Elapsed: 0.002 sec.

创建物理视图之前记录下数据库大小(先采集了几十条数据vector先停止了):

cluster_1S_2R node 1 :) select database,formatReadableSize(sum(bytes_on_disk)) AS size_on_disk FROM system.parts WHERE active GROUP BY database ORDER BY size_on_disk DESC

image.png

现在开始创建物理视图:

CREATE MATERIALIZED VIEW nginxdb.access_logs_view
(
    HttpHost String, 
    RemoteAddr String,
    Client String,
    RemoteUser String,
    TimeLocal DateTime,
    HttpProtocol String,
    RequestMethod String,
    Request_Url String,
    HttpVersion String,
    Status Int32,
    BytesSent Int64,
    Http_Referer  String,
    UserAgent String,
    Forwarded_For String,
    Gzip_Ratio String,
    Request_Time Float32,
    Upstream_Addr String,
    Upstream_Status String,
    Upstream_Response_Time Float32
)
ENGINE = MergeTree()
ORDER BY RemoteAddr
POPULATE AS
WITH
    splitByWhitespace(message) as split,
    splitByRegexp('\S \d+ "(^"]*)"', message) as referer,
    splitByRegexp('[)]',trim(BOTH '" ' from splitByRegexp('\S \d+ "([^"]*)"', message)[2])) as  referer2,
    splitByWhitespace(splitByRegexp('[)]',message)[2]) as  referer3
SELECT
    split[1] AS HttpHost,
    split[2] AS RemoteAddr,
    split[3] AS Client,
    split[4] AS RemoteUser,
    parseDateTimeBestEffort(split[5]) AS TimeLocal,
    trim(LEADING '"' FROM split[6]) AS HttpProtocol,
    split[7] AS RequestMethod,
    split[8] AS Request_Url,
    split[9] AS HttpVersion,
    split[10] AS Status,
    split[11] AS BytesSent,
    split[12] AS Http_Refere,
    concat(referer2[1] AS UserAgent,')'),
    referer3[2] AS Forwarded_For,
    referer3[3] AS Gzip_Ratio,
    toFloat32OrZero(referer3[4]) AS Request_Time, 
    referer3[5] AS Upstream_Addr,    
    referer3[6] AS Upstream_Status,    
    toFloat32OrZero(referer3[7]) AS Upstream_Response_Time
FROM
    (SELECT message FROM nginxdb.access_logs)

#我们再查看一下创建完物理视图后数据库的大小

image.png

博文来自:www.51niux.com

#所以可以看出,ClickHouse 中物化视图(Materialized View)是一种预先计算并缓存结果的视图,它存储在磁盘上并自动更新,典型的空间换时间思路。物化视图是一种优化技术,它可以加速查询操作,降低系统负载,并提高查询性能。

#上面的sql语句为什么要是toFloat32OrZero而不是toFloat32呢?是因为如果user_agent并不是所有的都是()包起来的,还有其他形式,那么你的取值就会不完整就会导致后面得数都取不出来了,string格式倒是没事大不了就空嘛,但是这种浮点数的就会报错,下面看看不同效果的展示

Row 5:
-------------
UserAgent:    Dalvik/2.1.0 (Linux; U; Android 10; PBDM00 Build/QKQ1.190918.001)
Forwarded_For:  "-"
Gzip_Ratio:   "-"
Request_Time:  0.004
Upstream_Addr:  192.168.1.228:38007
Upstream_Status:   200
Upstream_Response_Time: 0.004
Row 6:
──────
UserAgent:  Driver/1 CFNetwork/1408.0.4 Darwin/22.5.0" "-" "-" 0.009 192.168.1.228:38007 200 0.009)
Forwarded_For:          
Gzip_Ratio:             
Request_Time: 0
Upstream_Addr:          
Upstream_Status:        
Upstream_Response_Time: 0

#别的字段还好,都是单个字段,user_agent比较复杂是由多个字段构成的。

第一种解决办法:将user_agent放到最后,然后sql就变成了,这里只展示差异部分

WITH
    splitByWhitespace(message) as split,
    splitByRegexp('\S \d+ "([^"]*)"', message) as referer
SELECT
    ......
        trim(BOTH '"' from referer[2]) AS UserAgent

#但是上面的这种方式显然不太友好,一般日志记录并不会把user_agent放到最后,这就改变了我们的传统查看习惯。

第二种解决办法:就是在nginx的日志格式中[user_agent]这样包一下,这样就可以正则切割的特殊标识了。

    log_format  main  '$http_host $remote_addr - $remote_user $time_iso8601 '
                      '$scheme "$request" $status $bytes_sent "$http_referer" '
                      '"[$http_user_agent]" "$http_x_forwarded_for" "$gzip_ratio" $request_time '
                      '$upstream_addr $upstream_status $upstream_response_time';

# /opt/soft/vector/bin/vector --config /opt/soft/vector/config/test/nginx.yaml   #重新采集一下

再看现在的日志格式就发生了变化:

app.test.cn 123.199.53.68 - - 2024-05-27T16:25:58+08:00 https "POST /app/uplog/ HTTP/1.1" 200 402 "-" "[Dalvik/2.1.0 (Linux; U; Android 12; LIO-AL00 Build/HUAWEILIO-AL00)]" "-" "-" 0.002 192.168.1.228:38007 200 0.001
app.test.cn 123.199.53.67- - 2024-05-27T16:26:40+08:00 http "POST /app/uplog/ HTTP/1.1" 200 402 "-" "[Dalvik/2.1.0 (Linux; U; Android 12; ANA-AN00 Build/HUAWEIANA-AN00)]" "-" "-" 0.004 192.168.1.228:38007 200 0.004

再执行下创建物理视图的sql语句,这次我们以时间排序ORDER BY TimeLocal,之前用IP排序,时间都是乱的看着很别扭:

CREATE MATERIALIZED VIEW nginxdb.access_logs_view
(
    HttpHost String, 
    RemoteAddr String,
    TimeLocal DateTime,
    HttpProtocol String,
    RequestMethod String,
    Request_Url String,
    Status Int32,
    BytesSent Int64,
    Http_Referer  String,
    UserAgent String,
    Forwarded_For String,
    Request_Time Float32,
    Upstream_Status String,
    Upstream_Response_Time Float32
)
ENGINE = MergeTree()
ORDER BY TimeLocal
POPULATE AS
WITH
    splitByWhitespace(splitByRegexp('\"\[',message)[1]) as split,
    splitByWhitespace(splitByRegexp('\]\"',message)[2]) as referer3,
    splitByRegexp('[\"\[\]\"]',message) as referer2
SELECT
    split[1] AS HttpHost,
    split[2] AS RemoteAddr,
    parseDateTimeBestEffort(split[5]) AS TimeLocal,
    trim(LEADING '"' FROM split[6]) AS HttpProtocol,
    split[7] AS RequestMethod,
    split[8] AS Request_Url,
    split[10] AS Status,
    split[11] AS BytesSent,
    split[12] AS Http_Refere,
    referer2[7] AS UserAgent,
    referer3[1] AS Forwarded_For,
    toFloat32OrZero(referer3[3]) AS Request_Time, 
    referer3[5] AS Upstream_Status,    
    toFloat32OrZero(referer3[6]) AS Upstream_Response_Time
FROM
    (SELECT message FROM nginxdb.access_logs)

来查看一下显示效果:

cluster_1S_2R node 1 :) select TimeLocal,UserAgent,Request_Time,Upstream_Response_Time from nginxdb.access_logs_view

image.png

作者:忙碌的柴少 分类:ClickHouse 浏览:282 评论:0
留言列表
发表评论
来宾的头像