为什么要使用ClickHouse
在项目立项之初,对于数据仓库这块的建设,其实有很多的技术选择,根据官方对比数据显示,100M数据集的跑分结果:ClickHouse比Vertia快约5倍,比Hive快279倍,比My SQL 快801倍。Vertia是商业软件,收费且不开源,小公司搞不起;Hive依赖于hadoop生态圈的,成本太高,甲方不太愿意提供那么多服务器,也不愿意虚拟化服务器,且虚拟化后的性能会进一步衰弱;mysql就不用考虑了,大量数据的存储只能靠分库分表,复杂且麻烦。我相信这些是大部分小公司都会面临的问题,总之一句话就是成本太高,承受不起。
另外,我还做过文档型数据库elasticsearch的调研,通过对比,如果数据是放到了buff/cache中,那么elasticsearch的查询速度和ClickHouse是一样的,但是如果没有存放,那么Clickhouse查询效率则比elasticsearch快50倍。且elasticsearch作为文档型数据库,在做数据展示的时候,会随着数据的不断深入,而变得越来越慢,因为文档型数据库就像翻书一样,查询数据是一页一页的往后,所以速度越来越慢。
clickhouse的出现,从一定意义上是补全了hadoop实时性的短板,其实它们对数据的处理有很多相同的地方,比如压缩存储、资源分配、数据分区,只是hadoop更擅长离线处理,而clickhouse是实时处理。hadoop中的hbase也是一种列式数据库,从操作上来说,我感觉它更像是一种nosql数据库,无论是从使用成本、学习成本、运维成本,都远远高于clickhouse。
那么基于以上原因,最终我将数据仓库组件选为ClickHouse。
用clickhouse做什么事情
项目背景:项目由设备和平台组成,设备负责采集日志,生成数据;平台负责接收数据、分析数据、统计数据、展示数据。
clickhouse能为我们做这些工作:
- 数据存储,按每天的数据分片存储,定期自动删除
- 快速查询数据,实时展示
- 秒级统计,可实时聚合计算,响应结果展示
- 节约大量的硬件成本,数据采用高效压缩,顺序IO
安装部署
- 检查一下是否支持SSE 4.2指令集
grep -q sse4_2 /proc/cpuinfo && echo “SSE 4.2 supported” || echo “SSE 4.2 not supported” - 上传最新版的clickhouse安装包
- 开始安装
yum install -y ODBC libicu.x86_64
rpm -Uvh clickhouse-*.rpm --nodeps --force - 设置默认账号密码和只读密码
vi /etc/clickhouse-server/users.xml
参照如下配置
<yandex>
<profiles>
<default>
<max_memory_usage>10000000000</max_memory_usage>
<use_uncompressed_cache>0</use_uncompressed_cache>
<load_balancing>random</load_balancing>
</default>
<readonly>
<max_memory_usage>10000000000</max_memory_usage>
<use_uncompressed_cache>0</use_uncompressed_cache>
<load_balancing>random</load_balancing>
<readonly>1</readonly>
</readonly>
</profiles>
<quotas>
<!-- Name of quota. -->
<default>
<interval>
<duration>3600</duration>
<queries>0</queries>
<errors>0</errors>
<result_rows>0</result_rows>
<read_rows>0</read_rows>
<execution_time>0</execution_time>
</interval>
</default>
</quotas>
<users>
<default>
<password_sha256_hex>967f3bf355dddfabfca1c9f5cab39352b2ec1cd0b05f9e1e6b8f629705fe7d6e</password_sha256_hex>
<networks incl="networks" replace="replace">
<ip>::/0</ip>
</networks>
<profile>default</profile>
<quota>default</quota>
</default>
<ck>
<password_sha256_hex>967f3bf355dddfabfca1c9f5cab39352b2ec1cd0b05f9e1e6b8f629705fe7d6e</password_sha256_hex>
<networks incl="networks" replace="replace">
<ip>::/0</ip>
</networks>
<profile>readonly</profile>
<quota>default</quota>
</ck>
</users>
</yandex>
密码生成方式:
PASSWORD=$(base64 < /dev/urandom | head -c8); # 获取一个随机密码,也可以直接指定
echo "$PASSWORD";
echo -n "$PASSWORD" | sha256sum | tr -d '-'
出现如下
oM9HOLs5 -- 密码
d741aef7b31900eddd525dd588a7e0e2761d5f231a588f36eff9d1090d83392b --密文
- 设置数据目录
vi /etc/clickhouse-server/config.xml
/data/clickhouse/
<tmp_path>/data/clickhouse/tmp/</tmp_path> - 允许远程登录
vi /etc/clickhouse-server/config.xml
取消注释:"<listen_host>::</listen_host>" - 启动|停止
service clickhouse-server stop
service clickhouse-server start - 可视化界面tabix
vi /etc/clickhouse-server/config.xml
取消注释:
<http_server_default_response><![CDATA[<html ng-app="SMI2"><head><base href="http://ui.tabix.io/"></head><body><div ui-view="" class="content-ui"></div><script src="http ://loader.tabix.io/master.js"></script></body></html>]]></http_server_default_response>
service clickhouse-server restart
以上clickhouse服务端和客户端就已经安装启动好了,下面就进行实际操作吧。
开始实战
- 创建数据库和表结构
##登录clickhouse数据库,默认用户名default,密码为abcds,-m表示多行输入,输入回车不执行,遇到分号执行
clickhouse-client --password=abcds -m
##创建aa数据库
create database aa;
##创建表结构
CREATE TABLE aa.equipment_info_test (id String, mac String, device_business_type String, create_time String, create_date String) ENGINE = MergeTree() PARTITION BY device_business_type ORDER BY device_business_type SETTINGS index_granularity = 8192; - 创建一个spring-boot程序
- 增加如下配置
- 加载数据源
package com.nsac.clickhouse.config;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "spring.datasource.click")
@Getter
@Setter
public class JdbcParamConfig {
private String driverClassName;
private String url;
private Integer initialSize;
private Integer maxActive;
private Integer minIdle;
private Integer maxWait;
private String username;
private String password;
}
package com.nsac.clickhouse.config;
import javax.annotation.Resource;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.alibaba.druid.pool.DruidDataSource;
@Configuration
public class DruidConfig {
@Resource
private JdbcParamConfig jdbcParamConfig;
@Bean
public DataSource dataSource() {
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(jdbcParamConfig.getUrl());
datasource.setDriverClassName(jdbcParamConfig.getDriverClassName());
datasource.setInitialSize(jdbcParamConfig.getInitialSize());
datasource.setMinIdle(jdbcParamConfig.getMinIdle());
datasource.setMaxActive(jdbcParamConfig.getMaxActive());
datasource.setMaxWait(jdbcParamConfig.getMaxWait());
datasource.setUsername(jdbcParamConfig.getUsername());
datasource.setPassword(jdbcParamConfig.getPassword());
return datasource;
}
}
- 编写mybatis 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper SYSTEM "http://mybatis.org/dtd/mybatis-3-mapper.dtd" PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN">
-<mapper namespace="com.nsac.clickhouse.dao.TestSQLDao">
<select resultType="java.util.Map" parameterType="String" id="excuteSQL">select count(*) from equipment_info_test eq </select>
-<insert parameterType="java.util.List" id="insertSQL" useGeneratedKeys="false">
insert into equipment_info_test (id, mac, device_business_type,create_time,create_date) values
<foreach separator="," index="index" item="item" collection="list">(#{item.id},#{item.mac, jdbcType=VARCHAR},#{item.deviceBusinessType},#{item.createTime, jdbcType=VARCHAR},#{item.createDate, jdbcType=VARCHAR}) </foreach>
</insert>
</mapper>
- 编写DAO层
package com.nsac.clickhouse.dao;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Repository;
@Repository
public interface TestSQLDao {
List<Map<String, Object>> excuteSQL(String sql);
void insertSQL(List<Map<String, Object>> list);
}
- 接下来就可以编写service、controller层了,在使用上与mysql这种关系型数据库是没有任何区别的,所以,对于java程序猿来说,学习使用clickhouse成本为0,直接就可以上手操作。