【Clickhouse】Clickhouse和C程序交互流程

1、简介

ClickHouse 是俄罗斯的 Yandex 于 2016 年开源的用于在线分析处理查询OLAP :Online Analytical Processing)的列式存储数据库DBMS:Database Management System),能够使用 SQL 查询实时生成分析数据报告。ClickHouse的全称是Click Stream,Data WareHouse

本文只介绍CK安装步骤和简单使用方法以及与C/C++程序交互存储数据,不包括使用场景及优缺点,详细介绍参考CK官方文档说明

2、安装部署

测试虚拟机环境为:CentOS 8.4,使用RPM安装包进行安装(版本Release 22.3.2.2),其它安装方式参考官方安装文档

2.1、系统要求

ClickHouse可以在任何具有x86_64AArch64PowerPC64LE CPU架构的LinuxFreeBSDMac 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"

【Clickhouse】Clickhouse和C程序交互流程_第1张图片

要在不支持SSE 4.2AArch64PowerPC64LE架构的处理器上运行ClickHouse,您应该通过适当的配置调整从源代码构建ClickHouse。

2.2、RPM安装

2.2.1、在线安装

各个版本RPM下载地址

步骤一:

下载RPM安装包

# 需要下载3个 RPM 包, 分别是
# clickhouse-client-22.3.2.2-2.noarch.rpm  包含clickhouse-client客户端,它是交互式ClickHouse控制台客户端。
# clickhouse-common-static-22.3.2.2-2.x86_64.rpm 包含一个ClickHouse可执行文件。
# clickhouse-server-22.3.2.2-2.noarch.rpm 包含要作为服务端运行的ClickHouse配置文件。

# 下载RPM包
[root@localhost CK]# wget https://packages.clickhouse.com/rpm/stable/clickhouse-client-22.3.2.2-2.noarch.rpm
[root@localhost CK]# wget https://packages.clickhouse.com/rpm/stable/clickhouse-common-static-22.3.2.2-2.x86_64.rpm
[root@localhost CK]# wget https://packages.clickhouse.com/rpm/stable/clickhouse-server-22.3.2.2-2.noarch.rpm

下载截图:

【Clickhouse】Clickhouse和C程序交互流程_第2张图片

步骤二:

安装RPM包,根据如下安装步骤进行安装。

# 首先安装 clickhouse-common-static
[root@localhost CK]# rpm -ivh clickhouse-common-static-22.3.2.2-2.x86_64.rpm
# 其次安装 clickhouse-server
[root@localhost CK]# rpm -ivh clickhouse-server-22.3.2.2-2.noarch.rpm
# 最后安装 lickhouse-client
[root@localhost CK]# rpm -ivh clickhouse-client-22.3.2.2-2.noarch.rpm

安装截图:

【Clickhouse】Clickhouse和C程序交互流程_第3张图片

【Clickhouse】Clickhouse和C程序交互流程_第4张图片

安装完成之后,各个目录的分配如下:

  • 配置文件目录:/etc/clickhouse-server/
  • 数据文件目录:/var/lib/clickhouse/
  • 库名 : db_name,数据存储目录:/var/lib/clickhouse/data/db_name
  • 表名 : test,表的数据存储目录:/var/lib/clickhouse/data/db_name/test/
  • 分区: 20220324,分区的存储目录:/var/lib/clickhouse/data/db_name/test/20220324
  • 日志文件目录:/var/log/clickhouse-server/

2.2.2、离线安装

将在线下载的RPM包导入到内网服务器中,执行在线安装的步骤二即可。

2.3、启动

2.3.1、启动服务端

# 查看进程是否已存在
[root@localhost CK]# systemctl status clickhouse-server
# 启动服务端
[root@localhost CK]# systemctl start clickhouse-server

# 注释
#systemctl start clickhouse-server		启动
#systemctl stop clickhouse-server		停止
#systemctl status clickhouse-server		查看状态
#systemctl restart clickhouse-server	重启

# 日志文件将输出在/var/log/clickhouse-server/文件夹。
# 如果服务器没有启动,检查/etc/clickhouse-server/config.xml中的配置。

您也可以手动从控制台启动服务器:

[root@localhost CK]#  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】Clickhouse和C程序交互流程_第5张图片

查看是否启动成功

【Clickhouse】Clickhouse和C程序交互流程_第6张图片

启动服务后,您可以使用命令行客户端连接到它:

2.3.2、启动客户端

# 启动客户端连接到数据库
[root@localhost CK]# clickhouse-client 
ClickHouse client version 22.3.2.1.
Connecting to localhost:9000 as user default.

If you have installed ClickHouse and forgot password you can reset it in the configuration file.
The password for default user is typically located at /etc/clickhouse-server/users.d/default-password.xml
and deleting this file will reset the password.
See also /etc/clickhouse-server/users.xml on the server where ClickHouse is installed.

Code: 516. DB::Exception: Received from localhost:9000. DB::Exception: default: Authentication failed: password is incorrect or there is no user with such name. (AUTHENTICATION_FAILED)

报错提示,鉴权失败:密码或者用户名错误导致

# 添加参数重新启动客户端连接数据库
[root@localhost CK]# clickhouse-client --host=localhost --user=default --password 123456 -m

# 注释
# --host 主机名或者IP地址(需要映射)
# --user 数据库名
# --password 初始设置密码
# -m 启用多行查询,可以执行多条语句,已分号(;)为结束符

查看数据库:

localhost :) show databases;

【Clickhouse】Clickhouse和C程序交互流程_第7张图片

查看当前使用数据库:

localhost :) select currentDatabase();

【Clickhouse】Clickhouse和C程序交互流程_第8张图片

当前使用的数据库命为default

查看当前使用的数据库包含几张表:

localhost :) show tables;

【Clickhouse】Clickhouse和C程序交互流程_第9张图片

当前数据库没有任何表

简单语句

# 查看数据库
show databases;
# 创建一个数据库名为db 
create database db;  
# 删除db数据库
drop database db;
# 切换到db数据库
use db;
# 查看当前使用数据库
select currentDatabase();
# 查看当前使用数据库表
show tables;

至此Clickhouse数据库安装部署完毕,后续可以对其进行建表、存储、查询等操作了~

2.4、修改配置文件

在实际使用当中,还需要根据生产环境对配置文件进行修改,可以通过修改配置文件先对数据库进行优化,主要以下几点:

  1. 修改用户配置文件,优化改用户查询所使用的资源;
  2. 修改数据配置文件,优化数据存储路径和日志存储路径;
  3. 配置ramdisk进行热数据和冷数据的存储策略。

根据实际生产情况进行配置,各个配置文件里的具体参数解释可参考CK官方文档说明

2.4.1、修改用户配置文件

步骤1:

首先停止clickhouse-server服务

[root@localhost CK]#  systemctl stop clickhouse-server

[root@localhost CK]#  systemctl status clickhouse-server

步骤2:

修改配置文件内容

[root@localhost CK]# vim /etc/clickhouse-server/users.xml

# 修改max_memory_usage配置项开头为4(原来默认10G,修改为40G,该配置代表单条查询单机器所使用的最大内存数)
# 添加如下配置
# 160000000000  所有查询占用的最大内存数量,设置为单条的4倍
# 20000000000 (执行group by最大内存,超出将使用落盘存储计算,一般设置为max_memory_usage的一半)
# 20000000000  (排序使用的最大内存限制,10个G)

【Clickhouse】Clickhouse和C程序交互流程_第10张图片

2.4.2、修改数据配置文件

步骤1:创建Clickhouse数据存储目录

由于目前测试环境使用的是一台虚拟机,只分配了20G的磁盘空间,所以现在测试方法是把虚拟机磁盘空间扩展,然后把扩展的空间挂载到某一个路径下。再把数据存储到这个路径下。这也就需要修改Clickhouse的默认配置文件,将存储路径更改到指定路径下

虚拟机扩展磁盘空间及挂载内存步骤不再介绍,这里已经将30G的磁盘挂载到/home/work目录下

【Clickhouse】Clickhouse和C程序交互流程_第11张图片

# 创建clickhouse数据库存储目录
[root@localhost CK]# mkdir /home/work/clickhouse

# 修改所属用户为clickhouse
[root@localhost CK]# cd /home/work
[root@localhost CK]# chown -R clickhouse:clickhouse clickhouse/

# ll查看
[root@localhost work]# ll
total 20
drwxr-xr-x. 4 clickhouse clickhouse  4096 Mar 23 09:58 clickhouse
drwx------. 2 root       root       16384 Mar 22 17:10 lost+found

【Clickhouse】Clickhouse和C程序交互流程_第12张图片

步骤2:

修改配置文件指定路径

[root@localhost CK]# vim /etc/clickhouse-server/config.xml

# 修改点如下:
# 运行日志路径
# /home/work/clickhouse/log/clickhouse-server/clickhouse-server.log
# 出错日志路径
# /home/work/clickhouse/log/clickhouse-server/clickhouse-server.err.log
# 数据存储路径
# /home/work/clickhouse/lib/clickhouse/
# 数据存储临时路径
# /home/work/clickhouse/lib/clickhouse/tmp/
# 用户文件目录
# /home/work/clickhouse/lib/clickhouse/user_files/
# 包含输入格式文件(例如CapnProto格式的方案)的目录路径
# /home/work/clickhouse/lib/clickhouse/format_schemas/

其它参数可参考Clickhouse 配置文件。

更改点截图(位置和配置文件不一样,这里只是为了方便截图作为参考):

【Clickhouse】Clickhouse和C程序交互流程_第13张图片

2.4.3、配置存储策略

配置ramdisk进行热数据和冷数据的存储策略。

步骤一:配置ramdisk

# 1、注入内核模块,设置一个`2G`的内存盘.(服务器上可配置为`16G -- (16777216 )`的)
[root@localhost ~]# modprobe brd rd_nr=1 rd_size=2097152 max_part=0
# 2、格式化内存盘
[root@localhost ~]# mkfs.ext4 /dev/ram0
mke2fs 1.45.6 (20-Mar-2020)
Creating filesystem with 524288 4k blocks and 131072 inodes
Filesystem UUID: e7e0d82d-1fd2-439f-8abb-8ef015a5c201
Superblock backups stored on blocks: 
	32768, 98304, 163840, 229376, 294912

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (16384 blocks): done
Writing superblocks and filesystem accounting information: done 
# 3、创建挂载目录
[root@localhost ~]# mkdir /mnt/ramdisk

# 4、挂载内存盘
[root@localhost ~]# mount /dev/ram0 /mnt/ramdisk
# 4.1、设置为clickhouse所属组
[root@localhost ~]# chown -R clickhouse:clickhouse /mnt/ramdisk/

# 5、设置开启自启动(未验证)
# 5.1 方法一
[root@localhost ~]# echo "options brd rd_nr=1 rd_size=2097152 max_part=0" >> /etc/modprobe.d/memdisk.conf
[root@localhost ~]# echo "mkfs.ext4 /dev/ram0" >> /etc/rc.d/rc.local
[root@localhost ~]# echo "mount /dev/ram0 /mnt/ramdisk" >> /etc/rc.d/rc.local
[root@localhost ~]# chmod +x /etc/rc.d/rc.local

# 5.2、方法二、编写ramdisk.sh脚本加入到自启动目录下
[root@localhost ~]# vim ramdisk.sh
#!/bin/bash
modprobe brd rd_nr=1 rd_size=2097152 max_part=0
mkfs.ext4 /dev/ram0
mount /dev/ram0 /mnt/ramdisk
[root@localhost ~]# chmod +x ramdisk.sh

步骤二:config.d目录下新建config.xml,配置热数据和冷数据存储策略,内容如下:

<?xml version="1.0"?>
<!--
  NOTE: User and query level settings are set up in "users.xml" file.
  If you have accidentally specified user-level settings here, server won't start.
  You can either move the settings to the right place inside "users.xml" file
   or add <skip_check_for_incorrect_settings>1</skip_check_for_incorrect_settings> here.
-->
<clickhouse>
    <storage_configuration>
        <disks>
            <ram_disk>
                <path>/mnt/ramdisk/</path>  <!-- ssd 数据目录 -->
            </ram_disk>
            <sdd_disk>
                <path>/home/work/clickhouse/</path>  <!-- 普通盘数据目录 -->
                <keep_free_space_bytes>104857600</keep_free_space_bytes>  <!-- 磁盘预留空间 -->
            </sdd_disk>
        </disks>
        <policies>
            <hot_to_cold>
                <volumes>
                    <hot_volume>
                       <disk>ram_disk</disk>  <!-- 与上面设置的ram_disk名称对应 -->
                       <max_data_part_size_bytes>1048576</max_data_part_size_bytes>  <!-- 数据块大小 -->
                    </hot_volume>
                    <cold_volume>
                        <disk>sdd_disk</disk>  <!-- 与上面设置的sdd_disk名称对应 -->
                    </cold_volume>
                </volumes>
                <move_factor>0.2</move_factor>  <!-- 当SSD数据盘低于20%存储时会将历史数据存储到hdd. -->
            </hot_to_cold>
        </policies>
    </storage_configuration>
</clickhouse>

【Clickhouse】Clickhouse和C程序交互流程_第14张图片
**NOTE:**在建表时注意加入 SETTINGS storage_policy = 'hot_to_cold'策略

保存退出后,同样的设置配置文件到clickhouse所属组。

[root@localhost ~]# chown -R clickhouse:clickhouse /etc/clickhouse-server/config.d/config.xml 

【Clickhouse】Clickhouse和C程序交互流程_第15张图片

完成之后重新启动clickhouse-server

[root@localhost users.d]# systemctl start clickhouse-server
[root@localhost users.d]# systemctl status clickhouse-server

【Clickhouse】Clickhouse和C程序交互流程_第16张图片

服务端启动完成~~

连接数据库

[root@localhost CK]#  clickhouse-client --host=localhost --user=default --password 123456 -m;

查看存储路径

localhost :) select * from system.disks;

【Clickhouse】Clickhouse和C程序交互流程_第17张图片

2.5、建表

连接数据库,在default数据库下创建一个学生档案表student_table,具体包含字段如下:

学号 姓名 性别 出生日期 年龄 家庭住址 监护人姓名 监护人电话
UInt64 String String DateTime64 UInt8 String String String

步骤1: 连接默认default数据库

[root@localhost CK]#  clickhouse-client --host=localhost --user=default --password 123456 -m;

建表语句如下:

create table student_table
(
  `Sno` UInt64 COMMENT '学生学号',
  `Sname` String COMMENT '学生姓名',
  `Ssex` String COMMENT '学生性别',
  `Sbirthday` DateTime64 COMMENT '学生出生日期',
  `Sage` UInt8 COMMENT '学生年龄',
  `Saddress` String COMMENT '学生家庭住址',
  `Sguardian` String COMMENT '学生监护人',
  `Sguardian_tel` String COMMENT '学生监护人电话'
)
engine =MergeTree()
ORDER BY Sno
PRIMARY KEY Sno
SETTINGS storage_policy = 'hot_to_cold';

截图如下:

【Clickhouse】Clickhouse和C程序交互流程_第18张图片

# 查看表
localhost :) show tables;

# 查看表字段
localhost :) desc student_table;

【Clickhouse】Clickhouse和C程序交互流程_第19张图片

至此,clickhouse配置文件以及建表已经完成,下面开始对clickhouse客户端源码(C++版本)进行编译,然后使用测试程序连接到数据库并且写入数据。

3、编译源码

3.1、获取源码

# 下载源码 版本为v2.1.0
[root@localhost CK]# wget https://github.91chi.fun/https://github.com//ClickHouse/clickhouse-cpp/archive/refs/tags/v2.1.0.tar.gz

# 解压缩
[root@localhost CK]# tar -zxvf v2.1.0.tar.gz 

【Clickhouse】Clickhouse和C程序交互流程_第20张图片

3.2、编译源码

[root@localhost CK]# cd clickhouse-cpp-2.1.0/

[root@localhost clickhouse-cpp-2.1.0]# mkdir build ./

[root@localhost clickhouse-cpp-2.1.0]# cd build/

[root@localhost build]# cmake ../

[root@localhost build]# make -j4

【Clickhouse】Clickhouse和C程序交互流程_第21张图片

Note:如果编译报错则考虑升级g++cmake版本

编译完成后,一共生成了4个静态库文件,本次测试依赖这几个静态库,如下:

【Clickhouse】Clickhouse和C程序交互流程_第22张图片

【Clickhouse】Clickhouse和C程序交互流程_第23张图片

3.3、创建工程

3.3.1、工程目标

假如目前你已经有一个程序实现了数据接收解析的部分,现在想让这一部分数据使用clickhouse存储下来,那么可以参考如下方法实现:

在程序层面,clickhouse-cpp只是用来实现一个客户端,连接到服务端并根据服务端配置写入存储数据的,只需把clichhouse-cpp的测试用例更改我们所需要的接口后编译成静态库文件,然后将编写的接口静态库和头文件以及上述源码编译的4个静态库文件合并到源数据接收解析程序中,即可调用相关接口向clickhouse服务端插入数据。

3.3.2、代码框架

【Clickhouse】Clickhouse和C程序交互流程_第24张图片

clickhouse-cpp-2.1.0/tests/simple文件夹下main.cpp文件更改后,clickhouse.h用来声明接口名,编译出clickhouse.a静态库文件,将源码编译的4个静态库为文件和clickhouse.a文件复制到数据接收程序代码的lib目录下,将接口声明文件clickhouse.h复制到include目录下,然后修改Makefile文件,将涉及到的.a静态库文件链接到源程序中即可。

3.3.3、样例代码介绍

github上的参考样例

#include 

using namespace clickhouse;

/// Initialize client connection.
Client client(ClientOptions().SetHost("localhost"));

/// Create a table.
client.Execute("CREATE TABLE IF NOT EXISTS test.numbers (id UInt64, name String) ENGINE = Memory");

/// Insert some values.
{
    Block block;

    auto id = std::make_shared();
    id->Append(1);
    id->Append(7);

    auto name = std::make_shared();
    name->Append("one");
    name->Append("seven");

    block.AppendColumn("id"  , id);
    block.AppendColumn("name", name);

    client.Insert("test.numbers", block);
}

/// Select values inserted in the previous step.
client.Select("SELECT id, name FROM test.numbers", [] (const Block& block)
    {
        for (size_t i = 0; i < block.GetRowCount(); ++i) {
            std::cout << block[0]->As()->At(i) << " "
                      << block[1]->As()->At(i) << "\n";
        }
    }
);

/// Delete table.
client.Execute("DROP TABLE test.numbers");

通过对上述代码分析,可以帮助我们编写自己代码逻辑,如下:

步骤一:Initialize client connection

首先需要连接到clickhouse服务端,连接成功后可以通过client和服务端进行交互,这里请注意连接服务端所传入的参数和返回值

参数:仅有主机名,所以如果服务端设置了其它用户名或者设置了密码,就需要添加其它参数了,详细的可以参考clickhouse-cpp-2.1.0/tests/simple文件夹下main.cpp文件。

返回值:这里运用了C++语法构造了一个栈上的对象,相同的还可以在堆上构造一个client对象,如下:

Client *client = Client(ClientOptions().SetHost("localhost"));

这样写的好处在于我们可以把构造的client用作返回值给带出去。

步骤二:Create a table.

建表的操作这一步可以忽略,应该为一般场景下表格都是事先创建好的。

步骤三:Insert some values.

这里首先构造了一个block,然后创建了两个临时变量idname(可以认为是列名),给它们定义好类型,id类型为uint64_tvector; name类型为stringvector。然后赋值,最后调用client.insert插入到数据库。

一般来讲,可以根据实际情况定义一次性插入数据量,这里只是临时的插入了两条数据。如果一次性插入5W条数据,可以写成如下:

Block block;

auto id = std::make_shared();
auto name = std::make_shared();

for(int i = 0; i < 50000; i++) {
    id->Append(i);
    name->Append("one");
}

block.AppendColumn("id"  , id);
block.AppendColumn("name", name);

client.Insert("test.numbers", block);

这个是伪代码,其中插入的类型要和前面定义数据类型一致。

步骤四: Select values inserted in the previous step.

打印插入的数据,一般测试使用,正常使用不到。

步骤五:Delete table.

删除表格,同样测试使用。

总结:

在使用过程中,重点需要考虑步骤一步骤三

3.3.4、数据解析程序

步骤一:创建decode目录

如果程序比较简单,可以按照如下框架设计目录文件,如下:

创建decode工程目录及子目录和相关文件。

【Clickhouse】Clickhouse和C程序交互流程_第25张图片

其中

app为代码子目录,用来存放功能模块中的.c.h文件;

include为头文件目录,全局使用的头文件和lib目录下的静态库所依赖的头文件;

lib为库文件目录,用来存放编译出的静态库文件;

build为可执行程序目录,用来存放编译生成的二进制可执行程序;

Makefile编译连接所有的文件,生成可执行程序;

main.c 主要代码,用来编写代码的整体流程部分。

步骤二:编写代码

加入clickhouse库之前代码

1)、创建5个线程

【Clickhouse】Clickhouse和C程序交互流程_第26张图片

2)、循环去伪造数据写入到提前申请好的内存中

【Clickhouse】Clickhouse和C程序交互流程_第27张图片

3.3.5、编译接口静态库

步骤一:编写代码

代码就以下两个文件,clickhouse.hclickhouse.cpp

clickhouse.h

#ifndef __CLICKHOUSE_H__
#define __CLICKHOUSE_H__

#ifdef __cplusplus
extern "C"
{
#endif

#define INSERT_STD_CNT_EVERY_TIME 50000

// 连接数据库初始化接口
void* DatabaseInit();
// 断开数据库连接接口
void DatabaseDeinit(void*);
// 插入数据接口
int DataInsertClickhouse(void*, char*, int);

#ifdef __cplusplus
}
#endif

#endif // __CLICKHOUSE_H__

clickhouse.cpp

// 头文件包含路径修改为源码存储路径
#include "/mnt/hgfs/code/clickhouse-cpp-2.1.0/clickhouse/client.h"
#include "/mnt/hgfs/code/clickhouse-cpp-2.1.0/clickhouse/error_codes.h"
#include "/mnt/hgfs/code/clickhouse-cpp-2.1.0/clickhouse/types/type_parser.h"
#include "/mnt/hgfs/code/clickhouse-cpp-2.1.0/clickhouse/base/socket.h"
#include "clickhouse.h"

#include "/mnt/hgfs/code/clickhouse-cpp-2.1.0/ut/utils.h"

#include 
#include 
#include 

#if defined(_MSC_VER)
#   pragma warning(disable : 4996)
#endif

using namespace clickhouse;
using namespace std;


#define SERVER_INFO_MAX_LEN 64

// 学生信息,和数据解析模块保持一致
typedef struct Student_
{
	uint64_t sno;
	char name[64];
	char sex[8];
	uint64_t timestamp;
	uint8_t age;
	char address[128];
	char guardian[64];
	char guardian_tel[64];

}Student;

// 断开数据库连接
void DatabaseDeinit(void* cli){
	Client* client = static_cast(cli);

	if(client) {
		delete client;
	}
}

// 数据库连接初始化
// 成功后将cli返回
void *DatabaseInit(void){
	Client* cli = NULL;

	try {
		cli = new Client(ClientOptions()
						.SetHost(           getEnvOrDefault("CLICKHOUSE_HOST",     "localhost"))
		                .SetPort(   getEnvOrDefault("CLICKHOUSE_PORT",     "9000"))
		                .SetUser(           getEnvOrDefault("CLICKHOUSE_USER",     "default"))
		                .SetPassword(       getEnvOrDefault("CLICKHOUSE_PASSWORD", "123456"))
		                .SetDefaultDatabase(getEnvOrDefault("CLICKHOUSE_DB",       "default")));
	} catch (const std::exception& e) {
        std::cerr << "exception : " << e.what() << std::endl;
	}
	return cli;
}

// 数据插入实现。传入要插入的结构体数组和数量以及数据库连接的"句柄-cli"
int DataInsertClickhouse(void* cli, char* std_info, int std_cnt)
{
	int iret = 0;

	if(cli == NULL) return -1;

	if(std_info == NULL) return 0;

	Client* client = static_cast(cli);
	
	struct Student_* std = (struct Student_*)std_info;

	Block block;

	auto sno = std::make_shared();
	auto sname = std::make_shared();
	auto ssex = std::make_shared();
	auto stime = std::make_shared(3);
	auto sage = std::make_shared();
	auto saddress = std::make_shared();
	auto guardian = std::make_shared();
	auto guardian_tel = std::make_shared();

	for(int i = 0; i < std_cnt; i++) {
		sno->Append(std[i].sno);
		sname->Append(std[i].name);
		ssex->Append(std[i].sex);
		stime->Append(std[i].timestamp);
		sage->Append(std[i].age);
		saddress->Append(std[i].address);
		guardian->Append(std[i].guardian);
		guardian_tel->Append(std[i].guardian_tel);
		
	}

	block.AppendColumn("Sno", sno);
	block.AppendColumn("Sname", sname);
	block.AppendColumn("Ssex", ssex);
	block.AppendColumn("Sbirthday", stime);
	block.AppendColumn("Sage", sage);
	block.AppendColumn("Saddress", saddress);
	block.AppendColumn("Sguardian", guardian);
	block.AppendColumn("Sguardian_tel", guardian_tel);
	
	try {
		client->Insert("default.student_table", block);
	} catch (const std::exception& e) {
		std::cerr << "exception : " << e.what() << std::endl;
		iret = -1;
	}
	return iret;
}

步骤二:生成静态库文件

[root@localhost simple]# g++ -std=c++17 -c clickhouse.cpp

【Clickhouse】Clickhouse和C程序交互流程_第28张图片

出现报错信息:网上查证后发现需要安装abseil,安装步骤如下:

[root@localhost]# wget https://github.91chi.fun/https://github.com//abseil/abseil-cpp/archive/refs/tags/20211102.0.tar.gz

[root@localhost]# cd abseil-cpp-20211102.0/

[root@localhost abseil-cpp-20211102.0]# mkdir build
[root@localhost abseil-cpp-20211102.0]# cd build/
[root@localhost build]# cmake ../
[root@localhost build]# make 
[root@localhost build]# make install

问题参考链接:relative import error

安装完成后重新执行

[root@localhost simple]# g++ -std=c++17 -c clickhouse.cpp

在这里插入图片描述

再次出现报错信息,这里修改头文件路径即可,如下:

#include "/mnt/hgfs/code/clickhouse-cpp-2.1.0/ut/utils.h"

修改完成后,继续执行

[root@localhost simple]# g++ -std=c++17 -c clickhouse.cpp

【Clickhouse】Clickhouse和C程序交互流程_第29张图片

成功生成.o文件~

执行如下命令,编译.a静态库文件

[root@localhost simple]# ar -crv clickhouse.a clickhouse.o

【Clickhouse】Clickhouse和C程序交互流程_第30张图片

成功生成clickhouse.a静态库文件

3.3.6、修改数据库解析程序

修改数据库解析程序,添加clichouse.aclickhouse.h以及clickhouse源码编译出来的4个静态库文件:

【Clickhouse】Clickhouse和C程序交互流程_第31张图片

加入成功后,修改头文件引用和静态库连接,完成代码可参考下方链接下载查看。

【Clickhouse】Clickhouse和C程序交互流程_第32张图片

加入clickhouse库之后代码

3.3.7、演示代码流程

步骤一:

使用clickhouse-client命令连接到服务端

[root@localhost CK]#  clickhouse-client --host=localhost --user=default --password 123456 -m;

查看表数据

localhost :) select * from student_table;

【Clickhouse】Clickhouse和C程序交互流程_第33张图片

此时表为空。

步骤二:

启动数据解析程序,连接到数据库并且写入伪造的数据,每个线程是一次性写入5W条,5个线程一共为25W条,写入成功后会Sleep 10s

编译,启动decode程序

[root@localhost decode]# make clean; make
[root@localhost decode]# ./build/decode 
^C

Signal 2 received, preparing to exit...

查看student_table表数量,可以看出一共写入了25w条数据

【Clickhouse】Clickhouse和C程序交互流程_第34张图片

查看表消息内容

localhost :) select * from student_table limit 10;

【Clickhouse】Clickhouse和C程序交互流程_第35张图片

这里表内容是伪造的,具体字段可参考实际使用情况。

3.3.8、总结

1、本文只是遇见的一种场景,由于decode项目代码是由C语言完成的,因此要集成c++代码编写的clickhouse-cpp,就需要进行多次封装,通过调用二次接口把数据传递到clickhouse内部接口,然后完成数据的插入。这样就造成了如果想要修改插入的字段(新增/修改/删除),就需要重新编译接口静态库,然后将数据解析程序传入的结构体字段和编写的接口结构体(本文为Student结构体)字段保持一致。修改完成之后重新生成clickhouse.a,将decode/lib下的替换为新的clickhouse.a静态库。

2、测试程序只是为了模拟多线程先如何使用,值得注意的是如果多线程下使用需要创建多个cli连接服务器,因为cli非线程安全,多线程共同使用一个cli会出现错误。

3、Clickhouse支持数据类型中包含了clickhouse所支持的所有数据类型,可以根据需求初始化创建不同的数据类型插入。

4、程序只是启动之后连接一次数据库,然后每个线程维护一个cli。再不出现异常的情况下,这个cli将保持常链接,这个可以大幅度提升数据插入的速率。

5、调用Insert接口时,一次性插入多少条数据性能最高有待测试。

4、参考连接

CLICKHOUSE官方网站

CLICKHOUSE github网站

CLICKHOUSE-CPP github网站

你可能感兴趣的:(【Clickhouse】,linux,CentOS8.4,clickhouse,c,c++)