14.【clickhouse】ClickHouse从入门到放弃-实战

简介: 【clickhouse】ClickHouse从入门到放弃-实战

前文如下:


11.【clickhouse】ClickHouse从入门到放弃-概述

12.【clickhouse】ClickHouse从入门到放弃-环境搭建

13.【clickhouse】ClickHouse从入门到放弃-引擎

4.clickhouse实战

基于上一篇的总结,做一个入门的demo,场景基于业务的spm场景:

首先先回顾一下clickhouse的优缺点。

优点:

1,为了高效的使用CPU,数据不仅仅按列存储,同时还按向量进行处理;

2,数据压缩空间大,减少IO;处理单查询高吞吐量每台服务器每秒最多数十亿行;

3,索引非B树结构,不需要满足最左原则;只要过滤条件在索引列中包含即可;即使在使用的数据不在索引中,由于各种并行处理机制ClickHouse全表扫描的速度也很快;

4,写入速度非常快,50-200M/s ,对于大量的数据更新非常适用

缺点:

1,不支持事务,不支持真正的删除/更新

2,不支持高并发,官方建议qps为100,可以通过修改配置文件增加连接数,但是在服务器足够好的情况下;

3,SQL满足日常使用80%以上的语法,join写法比较特殊;最新版已支持类似SQL的join,但性能不好

4,尽量做1000条以上批量的写入,避免逐行insert或小批量的insert,update,delete操作,因为ClickHouse底层会不断的做异步的数据合并,会影响查询性能,这个在做实时数据写入的时候要尽量避开;

5,Clickhouse快是因为采用了并行处理机制,即使一个查询,也会用服务器一半的CPU去执行,所以ClickHouse不能支持高并发的使用场景,默认单查询使用CPU核数为服务器核数的一半,安装时会自动识别服务器核数,可以通过配置文件修改该参数。

全量数据导入:数据导入临时表 -> 导入完成后,将原表改名为tmp1 -> 将临时表改名为正式表 -> 删除原表

增量数据导入:增量数据导入临时表 -> 将原数据除增量外的也导入临时表 -> 导入完成后,将原表改名为tmp1-> 将临时表改成正式表-> 删除原数据表

4.1 应用参考

基于Clickhouse的日志体系

参考文档

cloud.tencent.com/developer/a…

mp.weixin.qq.com/s/d2PbeLesL…

www.cnblogs.com/gentleschol…

4.2 clickhouse+mybatis plus集成

参考文档

https://blog.csdn.net/douglas8287/article/details/84705750
https://blog.csdn.net/xhaimail/article/details/122084999
https://www.jianshu.com/p/953ba54d434c
https://blog.csdn.net/fx9590/article/details/105163804

创建表结构

-- 本地创建SPM表:业务:用户行为分析
CREATE TABLE default.trade_spm
(
  `id` Int64,
  `user_id` Int64 COMMENT '用户id 未登录为0',
  `from_type` String COMMENT '来源:ios,
\r\nandroid,
\r\napplet',
  `client_id` String COMMENT '客户端ID',
  `spm_platfrom` String COMMENT '访问平台固定;10=ios,11=小程序,12=H5 ,
\r\n13=android',
  `spm_page` String COMMENT '页面',
  `spm_model` String COMMENT '模块',
  `spm_position` String COMMENT '位置',
  `param_content` Nullable(String) COMMENT '内容(商品ID或专题模板ID或链接)',
  `ip` String COMMENT 'IP',
  `ua` String COMMENT 'User-Agent',
  `create_time` DateTime DEFAULT toDateTime(now(), 'Asia/Shanghai') COMMENT '行为发生时间',
  `update_time` DateTime DEFAULT toDateTime(now(), 'Asia/Shanghai') COMMENT '修改时间',
  `project_code` String COMMENT '项目编码',
  `_sign` Int8 DEFAULT 1,
  `_version` UInt64 DEFAULT 1
)
ENGINE = ReplacingMergeTree(_version)
PARTITION BY intDiv(id,
18446744073709551)
ORDER BY tuple(id)
SETTINGS index_granularity = 8192

工程配置

环境dubbo+spring boot +mybatisplus +nacos+swagger ui;使用nacos作为服务注册中心和配置中心

bootstrap.yml配置文件,配置nacos配置中心,使用远程配置,配置测试环境mall-log测试环境配置文件 profiles: active为 test.

网络异常,图片无法展示
|

# nacos配置
server:
port: 8090
spring:
application:
  name: mall-log
profiles:
  active: test
cloud:
  config:
    override-none: true
    allow-override: true
    override-system-properties: false
  nacos:
    discovery:
      server-addr: 127.0.0.1:8848 #localhost:8848 #Nacos服务注册中心地址
    config:
      server-addr: 127.0.0.1:8848 #Nacos作为配置中心地址
      file-extension: yml #指定yaml格式的配置
      group: DEFAULT_GROUP
      namespace: 803931a7-6d1b-44be-a8ee-8732822722bf   #指定配置中心命名空间

登录 127.0.0.1:8848/nacos ,用户名密码nacos

nacos 点击命名空间:看到之前以及创建了一个locolhost本地测试的命名空间,id和bootstrap.yml的 namespace配置一致:

网络异常,图片无法展示
|

nacos点击配置列表,选择localhost命名空间,导入配置,或者克隆配置,文件名称和bootstrap.yml和application:name: mall-log 加上profiles:active: test一致,profiles:active区分是生产还是测试环境配置

网络异常,图片无法展示
|

编辑配置如下,文件类型选择yaml

dubbo:
application:
  name: mall-log
protocol:
  name: dubbo
  port: 20881
registry:
  address: nacos://127.0.0.1:8848   #使用本地nacos作为服务注册中心
  check: false
  timeout: 5000
scan:
  base-packages: com.anchu.log.web.service
config-center:
  check:
consumer:
  check: false
  timeout: 5000
server:
port: 8090
spring:
cloud:
  config:
    override-none: true
datasource:
  driver-class-name: com.clickhouse.jdbc.ClickHouseDriver
  url: jdbc:clickhouse://192.168.120.110:8123/default
  userName: default
  password: clickhouse
  druid:
     # 按照自己连接的 clickhouse 数据库来
    filters: none  #clickhouse不支持wall及监控
     #配置初始化大小/最小/最大
    initial-size: 5
    min-idle: 5
    max-active: 20
     #获取连接等待超时时间
    max-wait: 60000
     #间隔多久进行一次检测,检测需要关闭的空闲连接
    time-between-eviction-runs-millis: 60000
     #一个连接在池中最小生存的时间
    min-evictable-idle-time-millis: 30000
    validation-query: SELECT 1
#mybatis
mybatis-plus:
mapper-locations: classpath:mapper/*.xml
configuration:
  log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
  db-config:
    logic-delete-field: flag  # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
    logic-delete-value: 1 # 逻辑已删除值(默认为 1)
    logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
logging:
config: classpath:log4j2.xml

代码编写(部分逻辑,其实实现和操作关系型数据库类似)

启动类,@EnableDiscoveryClient注解,服务发现

/**
* @author hh
* @date 2022/4/6 16:26
*/
@SpringBootApplication(scanBasePackages = {"com.anchu.log"})
@MapperScan(basePackages = {"com.anchu.log.dao"})
@EnableConfigurationProperties
@EnableDiscoveryClient
@EnableAsync
public class WsnbLogApplication {
   public static void main(String[] args) {
       SpringApplication.run(WsnbLogApplication.class, args);
  }
}

伪代码如下:

//controller
@RestController
@RequestMapping("/spm")
@Api(tags = "用户端SPM埋点")
public class TradeSpmAppController {
   @Reference
   private JwtService jwtService;
   @Autowired
   private ITradeSpmService iTradeSpmService;
   @ApiOperation(value = "增加埋点点击事件", httpMethod = "POST")
   @PostMapping("add")
   public ResultEntity add(HttpServletRequest request, @RequestBody TradeSpmDto dto){
       if(Objects.isNull(dto)){
           throw new CustomException(ResultEnum.PARAMS_IS_EMPTY);
      }
       String token = request.getHeader(ShiroConstants.AUTHORIZATION);
       String userAgent = request.getHeader("User-Agent");
//       if(!Objects.isNull(token) && !("".equals(token))){
//           TradeUserDto userDto =jwtService.parseToken(token);
//           dto.setUserId(userDto.getUserId());
//       }
       dto.setUserId(1L);
       dto.setIp(IPUtil.getIp(request));
       dto.setUa(Objects.isNull(userAgent) ? "unknow" : userAgent);
       iTradeSpmService.add(dto);
       return ResultTemplate.success();
  }
}
//service 
public interface ITradeSpmService {
    void add(TradeSpmDto dto);
}
@Service
public class TradeSpmLogServiceImpl extends ServiceImpl<TradeSpmLogMapper,
TradeSpmLog> implements ITradeSpmLogService {
    @Override
    public void add(TradeSpmLogDto dto) {
        if(Objects.isNull(dto)){
            throw new CustomException(ResultEnum.PARAMS_IS_EMPTY);
        }
        TradeSpmLog entity = dto.cloneToDomain(TradeSpmLog.class);
        //clickhouse 不支持自增主键,雪花算法生成
        entity.setId(SnowflakeIdWorker.generateId());
        this.baseMapper.insert(entity);
    }
}
//Mapper
public interface TradeSpmLogMapper extends BaseMapper<TradeSpmLog> {
}
//dao,dto,entity省略
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = false)
public class TradeSpm extends BaseObject {
    private static final long serialVersionUID = 1L;
    //@TableId(value = "id", type = IdType.AUTO) 不支持自增
    private Long id;
    private Long userId;
    /**
     * 来源:ios,android,applet
     */
    private String fromType;
    /**
     * 客户端ID
     */
    private String clientId;
    /**
     * 访问平台固定;10=APP,11=小程序,12=H5
     */
    private String spmPlatfrom;
    /**
     * 页面
     */
    private String spmPage;
    /**
     * 模块
     */
    private String spmModel;
    /**
     * 位置
     */
    private String spmPosition;
    /**
     * 内容
     */
    private String paramContent;
    /**
     * IP
     */
    private String ip;
    /**
     * User-Agent
     */
    private String ua;
    /**
     * 创建时间
     */
    private Date createTime;
    /**
     * 修改时间
     */
    private Date updateTime;
}

swagger ui测试:

http://127.0.0.1:8090/doc.html

网络异常,图片无法展示
|

//请求体
{
"clientId": "1",
"fromType": "1",
"id": 0,
"ip": "127.0.0.1",
"paramContent": "{"goodId":1}",
"spmModel": "10",
"spmPage": "11",
"spmPlatfrom": "11",
"spmPosition": "111",
"ua": "microsoft edge",
"userId": 1
}

问题

(1)主键不支持自增,可以业务代码自己生成,比如雪花算法id

(2)时区问题

blog.csdn.net/tomMMMMMMMM…

# 确保机器时间正确 时区确保正确,PDT是太平洋夏季时间。
[root@localhost anchu]# date -s 2022-05-18
Wed May 18 00:00:00 PDT 2022
[root@localhost anchu]# date -s 11:14:20
Wed May 18 11:14:20 PDT 2022
[root@localhost anchu]# hwclock --systohc
[root@localhost anchu]# date
Wed May 18 11:14:48 PDT 2022
[root@localhost anchu]#
#修改时区
[root@localhost anchu]# ll /etc/localtime
lrwxrwxrwx. 1 root root 41 Apr 22 12:36 /etc/localtime -> ../usr/share/zoneinfo/America/Los_Angeles
[root@localhost anchu]# ll /etc/localtime
lrwxrwxrwx. 1 root root 41 Apr 22 12:36 /etc/localtime -> ../usr/share/zoneinfo/America/Los_Angeles
[root@localhost anchu]# ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
[root@localhost anchu]# ll /etc/localtime
lrwxrwxrwx. 1 root root 33 May 19 03:39 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai
[root@localhost anchu]# date
Thu May 19 03:39:22 CST 2022
[root@localhost anchu]# date -s 2022-05-18
Wed May 18 00:00:00 CST 2022
[root@localhost anchu]# date -s 12:48:30
Wed May 18 12:48:30 CST 2022
#修改clickhouse配置文件,并重启
[root@localhost anchu]# vi /etc/clickhouse-server/config.xml
<timezone>Asia/Shanghai</timezone>
[root@localhost anchu]# clickhouse restart
#查看clickhouse时区配置
localhost :) show SETTINGS like '%time_zone%';
SHOW SETTINGS LIKE '%time_zone%'
Query id: a31192e8-b011-4117-91ce-2abc86bbbeef
┌─name─────────────────┬─type─┬─value─┐
│ use_client_time_zone │ Bool │ 0     │
└──────────────────────┴──────┴───────┘
localhost :) show SETTINGS like '%time_zone%';
SET use_client_time_zone = 1;
localhost :) select toTimeZone(toDateTime(now()), 'Asia/Shanghai');
┌─toTimeZone(toDateTime(now()), 'Asia/Shanghai')─┐
│                            2022-05-18 12:50:06 │
└────────────────────────────────────────────────┘

(3)性能问题

由于clickhouse对高并发支持不高,其次类似标题5.1说明,避免逐行insert或小批量的insert,update,delete操作,尽量做1000条以上批量的写入,我们可以优化代码,先将spm数据队列缓存起来,后面多并发批处理。

队列及处理相关参考文档:

blog.csdn.net/qq_34561243…


相关文章
|
存储 SQL 大数据
大数据技术之ClickHouse---入门篇---介绍
大数据技术之ClickHouse---入门篇---介绍
|
安全 大数据 Linux
大数据技术之Clickhouse---入门篇---安装
大数据技术之Clickhouse---入门篇---安装
|
存储 SQL 大数据
大数据技术之Clickhouse---入门篇---数据类型、表引擎
大数据技术之Clickhouse---入门篇---数据类型、表引擎
|
存储 数据库 索引
61.【clickhouse】ClickHouse从入门到放弃-MergeTree的存储结构
【clickhouse】ClickHouse从入门到放弃-MergeTree的存储结构
61.【clickhouse】ClickHouse从入门到放弃-MergeTree的存储结构
|
28天前
|
分布式计算 大数据 Apache
ClickHouse与大数据生态集成:Spark & Flink 实战
【10月更文挑战第26天】在当今这个数据爆炸的时代,能够高效地处理和分析海量数据成为了企业和组织提升竞争力的关键。作为一款高性能的列式数据库系统,ClickHouse 在大数据分析领域展现出了卓越的能力。然而,为了充分利用ClickHouse的优势,将其与现有的大数据处理框架(如Apache Spark和Apache Flink)进行集成变得尤为重要。本文将从我个人的角度出发,探讨如何通过这些技术的结合,实现对大规模数据的实时处理和分析。
82 2
ClickHouse与大数据生态集成:Spark & Flink 实战
|
28天前
|
存储 SQL Docker
ClickHouse入门指南:快速搭建与使用
【10月更文挑战第26天】在大数据时代,如何高效地处理海量数据成为了许多企业和开发者的关注点。ClickHouse 是一个开源的列式数据库管理系统(Column-Oriented DBMS),以其出色的查询性能和高并发能力,在数据分析领域迅速崛起。本文将从一个初学者的角度出发,详细介绍如何快速上手 ClickHouse,涵盖从环境搭建到基础操作的全过程。
51 3
|
27天前
|
消息中间件 存储 SQL
ClickHouse实时数据处理实战:构建流式分析应用
【10月更文挑战第27天】在数字化转型的大潮中,企业对数据的实时处理需求日益增长。作为一款高性能的列式数据库系统,ClickHouse 在处理大规模数据集方面表现出色,尤其擅长于实时分析。本文将从我个人的角度出发,分享如何利用 ClickHouse 结合 Kafka 消息队列技术,构建一个高效的实时数据处理和分析应用,涵盖数据摄入、实时查询以及告警触发等多个功能点。
46 0
|
SQL 缓存 大数据
大数据技术之Clickhouse---入门篇---SQL操作、副本
大数据技术之Clickhouse---入门篇---SQL操作、副本
|
存储 索引
67.【clickhouse】ClickHouse从入门到放弃-对于分区、索引、标记和压缩数据的协同总结
【clickhouse】ClickHouse从入门到放弃-对于分区、索引、标记和压缩数据的协同总结
67.【clickhouse】ClickHouse从入门到放弃-对于分区、索引、标记和压缩数据的协同总结
|
存储 缓存 数据库
66.【clickhouse】ClickHouse从入门到放弃-数据标记
【clickhouse】ClickHouse从入门到放弃-数据标记
66.【clickhouse】ClickHouse从入门到放弃-数据标记