clickhouse 高可用集群的部署

clickhouse简介

核心简介操作官方网站 https://clickhouse.tech/docs/zh/introduction/distinctive-features
ClickHouse是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS)。

数据压缩

在一些列式数据库管理系统中(例如: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提供各种各样在允许牺牲数据精度的情况下对查询进行加速的方法:

  1. 用于近似计算的各类聚合函数,如:distinct values, medians, quantiles
  2. 基于数据的部分样本进行近似查询。这时,仅会从磁盘检索少部分比例的数据。
  3. 不使用全部的聚合条件,通过随机选择有限个数据聚合条件进行聚合。这在数据聚合条件满足某些分布条件下,在提供相当准确的聚合结果的同时降低了计算资源的使用。

clickhouse 集群部署

Merge Tree

MergeTree 系列的引擎被设计用于插入极大量的数据到一张表当中。数据可以以数据片段的形式一个接着一个的快速写入,数据片段在后台按照一定的规则进行合并。相比在插入时不断修改(重写)已存储的数据,这种策略会高效很多。
主要特点:

  • 存储的数据按主键排序。
    这使得你能够创建一个小型的稀疏索引来加快数据检索。
  • 支持数据分区
    在相同数据集和相同结果集的情况下 ClickHouse 中某些带分区的操作会比普通操作更快。查询中指定了分区键时 ClickHouse 会自动截取分区数据。这也有效增加了查询性能。
  • 支持数据副本。
  • 支持数据采样。

ReplicatedMergeTree

ReplicatedMergeTree 是MergeTree的一个 扩展,主要是用户表级别的复制

测试集群规划

1: 下载并且在3台机器上安装clickhouse, 安装步骤参见 官方文档
https://clickhouse.tech/docs/zh/getting-started/install/
2: 安装zookeeper
3台物理机器(ubantu18.04)
node1: 172.16.1.x1
node2: 172.16.1.x2
node3: 172.16.1.x3
3 个shard,2 个副本
重点: clickhouse 一个物理节点保存 同一个表的同一个shard的副本数据。测试环境需要在3台物理机器上面
启动6个节点,由于端口等限制。 测试环境 每一个物理节点启动两个 clickhouse的进程,分别监听不同的端口
划分为两个逻辑的集群 集群1(9000), 集群2(9002)

物理规划图

image.png

其中 shard1-01表示 shard1的第一副本,以此类推

配置文件编写

ubantu 安装的linux 的配置文件路径为: /etc/clickhouse-server

配置文件复制

复制该目录下的config.xml 
cp config.xml  config1.xml 
config.xml 配置文件为9000 节点使用
config1.xml 配置文件为9001 节点使用

创建服务通用配置,设置分片和副本

创建配置文件内容如下。后续在config.xml和config1.xml的 include_form中需要引用该文件

clickhouse_self.xml

<yandex>
  <clickhouse_remote_servers>
    <cluster_3shards_1replicas>
        <shard>
           <internal_replication>true</internal_replication>
        <replica>
          <host>172.16.1.x1</host>
      <port>9000</port>
      <user>default</user>
      <password>admin123</password>
    </replica>
    <replica>
          <host>172.16.1.x2</host>
      <port>9001</port>
      <user>default</user>
      <password>admin123</password>
        </replica>
      </shard>
      <shard>
          <internal_replication>true</internal_replication>
        <replica>
          <host>172.16.1.x2</host>
      <port>9000</port>
      <user>default</user>
      <password>admin123</password>
      </replica>
    <replica>
          <host>172.16.1.x3</host>
      <port>9001</port>
      <user>default</user>
      <password>admin123</password>
        </replica>
      </shard>
      <shard>
          <internal_replication>true</internal_replication>
        <replica>
          <host>172.16.1.x3</host>
      <port>9000</port>
      <user>default</user>
      <password>admin123</password>
    </replica>
        <replica>
          <host>172.16.1.x1</host>
      <port>9001</port>
      <user>default</user>
      <password>admin123</password>
        </replica>
      </shard>
    </cluster_3shards_1replicas>
  </clickhouse_remote_servers>
  <zookeeper-servers>
    <node index="1">
      <host>172.16.1.x1</host>
      <port>2181</port>
    </node>
    <node index="2">
      <host>172.16.1.x2</host>
      <port>2181</port>
    </node>
    <node index="3">
      <host>172.16.1.x3</host>
      <port>2181</port>
    </node>
  </zookeeper-servers>
</yandex> 

修改config.xml和config1.xml

config.xml修改如下

引入外部配置

<include_from>/etc/clickhouse-server/clickhouse_self.xml</include_from>

修改macros

<macros>
            <shard>1</shard>
            <replica>172.16.1.x1-1</replica>
    </macros>

config1.xml的改动 (需要改动日志存储文件名称, 数据文件存储的路径,监听的端口等)
备注: 如果物理机器足够直接在不同的物理上启动 6个节点。不要做这些改动。
需要提前创建server1目录

数据文件存储改动

 <path>/var/lib/clickhouse/server1/</path>

    <!-- Path to temporary data for processing hard queries. -->
    <tmp_path>/var/lib/clickhouse/server1/tmp/</tmp_path>

    <!-- Policy from the <storage_configuration> for the temporary files.
         If not set <tmp_path> is used, otherwise <tmp_path> is ignored.

         Notes:
         - move_factor              is ignored
         - keep_free_space_bytes    is ignored
         - max_data_part_size_bytes is ignored
         - you must have exactly one volume in that policy
    -->
    <!-- <tmp_policy>tmp</tmp_policy> -->

    <!-- Directory with user provided files that are accessible by 'file' table function. -->
    <user_files_path>/var/lib/clickhouse/server1/user_files/</user_files_path>

    <!-- Path to folder where users and roles created by SQL commands are stored. -->
    <access_control_path>/var/lib/clickhouse/server1/access/</access_control_path>

引入外部文件

<include_from>/etc/clickhouse-server/clickhouse_self.xml</include_from>

端口改动如下

 <http_port>8124</http_port>
    <tcp_port>9001</tcp_port>
    <mysql_port>9005</mysql_port>

日志改动如下

<logger>
        <level>trace</level>
        <log>/var/log/clickhouse-server/clickhouse-server1.log</log>
        <errorlog>/var/log/clickhouse-server/clickhouse-server1.err.log</errorlog>
        <size>1000M</size>
        <count>10</count>
</logger>

修改macors

<macros>
            <shard>3</shard>
            <replica>172.16.1.3x-2</replica>
 </macros>

配置其他服务器

分别在node2 nod3 做相同的处理, 完成集群的配置工作

启动集群(每个节点做相同的工作)

启动clickhouse-server1的时候,可能出现文件权限问题,需要根据提示 修改相应的文件权限(server1的文件权限)

nohup  /usr/bin/clickhouse-server --config=/etc/clickhouse-server/config1.xml 
--pid-file=/run/clickhouse-server/clickhouse-server1.pid &
nohup  /usr/bin/clickhouse-server --config=/etc/clickhouse-server/config.xml 
--pid-file=/run/clickhouse-server/clickhouse-server.pid &

查看集群信息

任意服务器执行
clickhouse-client --password  xxxxx 
进入集群

查看集群配置

select cluster, shard_num, replica_num,host_name, port from system.clusters;
image.png

创建复制表

只是需要在一个节点上创建,采用分布式ddl操作

create database test_log on cluster cluster_3shards_1replicas
use test_log 切换数据库
CREATE TABLE log_test on cluster cluster_3shards_1replicas
(
    event_name String,
    event_type String,
    event_time DateTime64(3,'Asia/Shanghai'),
    module String,
    page   String,
    user_id Int,
    user_type String,
    property String
) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}', '{replica}')
ORDER BY event_time
partition by toYYYYMM(event_time)

创建分布式表

CREATE TABLE test_log_all AS test_log
ENGINE = Distributed(cluster_3shards_1replicas, log_test, test_log, rand())

真个集群中每个节点都包含了 test_log 数据库和 log_test 复制表

插入数据到节点1

java 集成mybatis 写入数据到clickhouse(本地表)
读取的时候,读分布式表

pom文件

       <dependency>
            <groupId>com.github.housepower</groupId>
            <artifactId>clickhouse-native-jdbc</artifactId>
            <version>2.5.4</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
        </dependency>

mybatis的配置

<environments default="clickhouse">
        <!-- 连接环境信息,取一个任意唯一的名字 -->
        <environment id="clickhouse">
            <!-- mybatis使用jdbc事务管理方式 -->
            <transactionManager type="jdbc"/>
            <!-- mybatis使用连接池方式来获取连接 -->
            <dataSource type="pooled">
                <!-- 配置与数据库交互的4个必要属性 -->
                <property name="driver" value="com.github.housepower.jdbc.ClickHouseDriver"/>
                <property name="url" value="jdbc:clickhouse://172.16.1.x1:9000/test_log"/>
                <property name="username" value="default"/>
                <property name="password" value="xxxxxx"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="ClickhouseMapper.xml"/>
    </mappers>

LogEvent定义

@Data
public class LogEvent {
    ZonedDateTime eventTime;
    String eventName;
    String eventType;
    String module;
    String page;
    Integer userId;
    String userType;
    String properties;
}

Mapper定义

@Mapper
public interface ClickhouseMapper {
    void insertIntoData(@Param("event") LogEvent event);
}

Mapper.xml

<insert id="insertIntoData" parameterType="com.clickhouse.LogEvent">
        insert into log_test(event_time,
        event_name,
        event_type,
        module,
        page,
        user_id,
        user_type,
        property)
        values(
        #{event.eventTime},
        #{event.eventName},
        #{event.eventType},
        #{event.module},
        #{event.page},
        #{event.userId},
        #{event.userType},
        #{event.properties})
    </insert>

插入java代码

public class DriverClickHouseWriter {
    public static void main(String[] args) throws Exception {
        Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        SqlSession sqlSession = sqlSessionFactory.openSession();

        ClickhouseMapper mapper = sqlSession.getMapper(ClickhouseMapper.class);
        LogEvent event = new LogEvent();
        Map<String, String> map = new HashMap<>();
        map.put("question", "商品问题");
        map.put("order_id", "923456");

        ObjectMapper objectMapper = new ObjectMapper();
        String pro = objectMapper.writeValueAsString(map);
        event.setEventTime(ZonedDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()), ZoneId.of("+8")));
        event.setEventName("page_index_click");
        event.setEventType("click");
        event.setModule("im");
        event.setPage("index");
        event.setUserId(12344);
        event.setUserType("supplier");
        event.setProperties(pro);
        mapper.insertIntoData(event);
        sqlSession.close();
    }
}

总结

通过上面的不走,写入数据到复制表中(本地表),只要写入其中一个节点, 集群回通过zk自动复制 数据到对应的 节点。 主节点挂掉之后,不影响分布式表的读取。保证了集群的高可用
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,064评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,606评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,011评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,550评论 1 269
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,465评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,919评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,428评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,075评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,208评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,185评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,191评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,914评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,482评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,585评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,825评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,194评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,703评论 2 339

推荐阅读更多精彩内容