日新增百万数据clickhouse大数据解决方案记录分享

news2024/12/23 15:47:20

公司广告业务需求,需要多个维度统计每个应用的设备数,点击率,展示率,等相关数据,而且数据需要进行去重,我第一时间想到的是利用clickhouse来做统计,因为我们平台访问量比较大,用mysql可能不太适合
首先我建了四个表

#点击数据表
CREATE TABLE raw_click
(
    `Date` Date,
    `Time` DateTime,
    `Hour` Int8,
    `AdvertiserID` UInt32 DEFAULT 0,
    `AdsID` UInt32 DEFAULT 0,
    `DeveloperID` UInt32 DEFAULT 0,
    `WebID` UInt32 DEFAULT 0,
    `FeeTypeID` UInt32 DEFAULT 0,
    `AdvType` UInt8 DEFAULT 0,
    `GroupID` UInt32 DEFAULT 0,
    `PlatformID` UInt32 DEFAULT 0,
    `PlatformNameID` UInt8 DEFAULT 0,
    `MaterialId` UInt32 DEFAULT 0,
    `DeviceID` Nullable(String) DEFAULT NULL,
    `AppOs` UInt8 DEFAULT 1
)
ENGINE = MergeTree
PARTITION BY toYYYYMMDD(Date)
ORDER BY Date
SETTINGS index_granularity = 8192

#填充数表
CREATE TABLE raw_fill
(
    `Date` Date,
    `Time` DateTime,
    `Hour` Int8,
    `AdvertiserID` UInt32 DEFAULT 0,
    `AdsID` UInt32 DEFAULT 0,
    `DeveloperID` UInt32 DEFAULT 0,
    `WebID` UInt32 DEFAULT 0,
    `FeeTypeID` UInt32 DEFAULT 0,
    `AdvType` UInt8 DEFAULT 0,
    `GroupID` UInt32 DEFAULT 0,
    `PlatformID` UInt32 DEFAULT 0,
    `PlatformNameID` UInt8 DEFAULT 0,
    `MaterialId` UInt32 DEFAULT 0,
    `DeviceID` Nullable(String) DEFAULT NULL,
    `AppOs` UInt8 DEFAULT 1
)
ENGINE = MergeTree
PARTITION BY toYYYYMMDD(Date)
ORDER BY Date
SETTINGS index_granularity = 8192

#请求数表
CREATE TABLE raw_request
(
    `Date` Date,
    `Time` DateTime,
    `Hour` Int8,
    `AdvertiserID` UInt32 DEFAULT 0,
    `AdsID` UInt32 DEFAULT 0,
    `DeveloperID` UInt32 DEFAULT 0,
    `WebID` UInt32 DEFAULT 0,
    `FeeTypeID` UInt32 DEFAULT 0,
    `AdvType` UInt8 DEFAULT 0,
    `GroupID` UInt32 DEFAULT 0,
    `PlatformID` UInt32 DEFAULT 0,
    `PlatformNameID` UInt8 DEFAULT 0,
    `MaterialId` UInt32 DEFAULT 0,
    `DeviceID` Nullable(String) DEFAULT NULL,
    `AppOs` UInt8 DEFAULT 1
)
ENGINE = MergeTree
PARTITION BY toYYYYMMDD(Date)
ORDER BY Date
SETTINGS index_granularity = 8192

#展示数表
CREATE TABLE raw_show
(
    `Date` Date,
    `Time` DateTime,
    `Hour` Int8,
    `AdvertiserID` UInt32 DEFAULT 0,
    `AdsID` UInt32 DEFAULT 0,
    `DeveloperID` UInt32 DEFAULT 0,
    `WebID` UInt32 DEFAULT 0,
    `FeeTypeID` UInt32 DEFAULT 0,
    `AdvType` UInt8 DEFAULT 0,
    `GroupID` UInt32 DEFAULT 0,
    `PlatformID` UInt32 DEFAULT 0,
    `PlatformNameID` UInt8 DEFAULT 0,
    `MaterialId` UInt32 DEFAULT 0,
    `DeviceID` Nullable(String) DEFAULT NULL,
    `AppOs` UInt8 DEFAULT 1
)
ENGINE = MergeTree
PARTITION BY toYYYYMMDD(Date)
ORDER BY Date
SETTINGS index_granularity = 8192

当时建表时,我犹豫了两个方面,第一需不需要进行按月分表,然后我问了chatgpt在这里插入图片描述
翻译过来的意思就是《你硬件的极限才是我clickhouse的极限》,那我就放心把数据往里面塞了
犹豫的第二点就是,我要不要只建一个表,将点击展示填充这些行为用type区分。后来仔细思考了一下,还是觉得每个行为进行一次分表是最好的
数据表里的每个字段,都将是我们业务报表,需要进行维度查询的条件,所以数据库就这样定下来了。
接下来就是需要考虑怎么将数据插入进来,我这里只分享一下我的插入数据脚本

#!/usr/local/php/bin/php -q
<?php
declare(ticks=1);

const _TOUCHER_NAME_ = "ch_stat";#同步器的名称

// 如果存在开发环境配置,则加载
include("int/clickhouse1.3.10/Clickhouse.php");
include("int/config.php");

$mq_name = $argv[1] ?? '';
if (empty($mq_name)) {
    exit("不是正确的打开方式!");
}
$table_name_arr = [
    'raw_show_mq' => 'raw_show',
    'raw_click_mq' => 'raw_click',
    'raw_fill_mq' => 'raw_fill',
    'raw_request_mq' => 'raw_request'
];
$table_name = $table_name_arr[$mq_name] ?? '';
if (empty($table_name)) {
    exit("不是正确的打开方式啊!");
}
#监听断开信号
$handle = true;
pcntl_signal(SIGTERM, 'handleSignal');
pcntl_signal(SIGINT, 'handleSignal');
pcntl_signal(SIGQUIT, 'handleSignal');

#链接redis
$redisconn = redis_conn();
$redisconn->select(9);


$clickhouse = new Clickhouse($ch_config, '数据库表名');

while (true) {
    if (date("H") == '05' && date("i") == '00' && date("s") == '00') {
        exit(_TOUCHER_NAME_ . ":I am gone away");
    }
    $start_time = microtime_float();  //记录开始时间
    try {
        $queueLen = $redisconn->lLen($mq_name);
    } catch (\Exception $e) {
        # 预防redis 挂掉
        exit(_TOUCHER_NAME_ . ": redis gone away ");
    }
    #暂时一次插入1000
    $queue_count = 1000;
    $data = [];

    if ($queueLen < $queue_count) {
        #数据不够 我在等等
        $queue_count = $queueLen;
//        msg2log(_TOUCHER_NAME_ . ":数据不够 我在等等!");
//        sleep(3);
//        continue;
    }
    for ($i = 0; $i < $queue_count; $i++) {
        #取出队列的数据
        $json_data = $redisconn->rPop($mq_name);
        if (empty($json_data)) {
            #会有为空吗
            continue;
        }
        #组装数据插入
        $data[] = json_decode($json_data, true);
    }
    if (empty($data)) {
        msg2log(_TOUCHER_NAME_ . ":队列暂时没有可消耗数据!");
        sleep(5);
        continue;
    }
    #批量插入
    try {
        $clickhouse->insert($table_name, $data);
    } catch (Exception $exception) {
        #批量插入失败 全部推回去
        msg2log(_TOUCHER_NAME_ . ":批量插入失败,将数据推回去");
        foreach ($data as $v) {
            #数据结构有问题 可暂时先注释
            $redisconn->lPush($mq_name, json_encode($v));
        }
        #清空数据
        $data = [];
        #排除是不是clickhouse挂了
        if (!$clickhouse->alive()) {
            exit("clickhouse 链接异常 尝试退出重连!");
        }
    }
    $end_time = microtime_float();
    if (!$handle) {
        msg2log(_TOUCHER_NAME_ . ":程序主动退出!Using Time " . ($end_time - $start_time) . " Sec, Totoal touched :" . count($data));
        break;
    }
    msg2log(_TOUCHER_NAME_ . ": Using Time " . ($end_time - $start_time) . " Sec, Totoal touched :" . count($data));
    sleep(3);
}

function handleSignal($signal)
{
    global $handle;
    switch ($signal) {
        case SIGTERM:
        case SIGINT:
        case SIGQUIT:
            $handle = false;
        #exit;
        // 处理其他信号...
    }
}

?>

脚本的内容,主要就是从队列里面拿到数据插入到clickhouse里面去,然后里面加了一点检测redis,clickhouse是否断开的判断处理,以及当数据存在异常时,将数组从新推回队列,防止数据丢失,最后一点就是当我们断掉脚本的时候,检测信号,将数据整理完毕之后再断开,这样尽可能的避免数据的丢失
在这里插入图片描述
插入数据脚本没问题了之后,等到数据进来,发现数据增长的是真的快,这是跑了2个多月的数据,因为平台流量大,导致数据很多,虽然查询起来有没有问题,但是我发现每次执行sql,时间大约在一个四五秒左右(以下面这段sql为例)

SELECT Date, 
    SUM(dau) AS dau, 
    SUM(request) AS request, 
    SUM(fill) AS fill, 
    SUM(show) AS show, 
    SUM(click) AS click 
FROM (
    SELECT Date, count(distinct DeviceID) AS dau, count(*) AS request, 0 AS fill, 0 AS show, 0 AS click 
    FROM raw_request 
    WHERE PlatformNameID > 0 AND Date BETWEEN '2024-03-07' AND '2024-03-13' 
    GROUP BY Date
    
    UNION ALL
    
    SELECT Date, 0 AS dau, 0 AS request, count(*) AS fill, 0 AS show, 0 AS click 
    FROM raw_fill 
    WHERE PlatformNameID > 0 AND Date BETWEEN '2024-03-07' AND '2024-03-13' 
    GROUP BY Date
    
    UNION ALL
    
    SELECT Date, 0 AS dau, 0 AS request, 0 AS fill, count(*) AS show, 0 AS click 
    FROM raw_show 
    WHERE PlatformNameID > 0 AND Date BETWEEN '2024-03-07' AND '2024-03-13' 
    GROUP BY Date
    
    UNION ALL
    
    SELECT Date, 0 AS dau, 0 AS request, 0 AS fill, 0 AS show, count(*) AS click 
    FROM raw_click 
    WHERE PlatformNameID > 0 AND Date BETWEEN '2024-03-07' AND '2024-03-13' 
    GROUP BY Date
) AS subquery
GROUP BY Date
ORDER BY Date DESC;

后面我发现其实,之前的历史数据,基本上都用不到,另外一直存着这些数据,备份起来,担心磁盘不够用,所以我想着只保存前面一个月的数据,因为我的数据存储是按天分区的,所以我删除的时候也要按天来删,注意删之后一定要归档一份,删除语句主要用到的是
ALTER TABLE table DROP PARTITION date
日期的格式是20240303 这样的,删除之后,发现数据查询确实也是会快一点,后面再慢慢优化

ALTER TABLE table ADD column 字段名 UInt8 DEFAULT 默认值;

clickhouse目的是为了存储更多的信息,尽量扩展到每一个我们可能会用到的查询条件,如果忘记了,那么我们就需要新增字段,新增字段还是比较快的,上亿条数据执行这段sql,一秒不到,个人猜测可能跟他的列式存储方式有关
最后,这是我个人的一个经验分享,欢迎大家交流学习,也希望能对你有帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1544405.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32-01基于HAL库(CubeMX+MDK+Proteus)仿真开发环境搭建(LED点亮测试实例)

STM32-01基于HAL库&#xff08;CubeMXMDKProteus&#xff09;仿真开发环境搭建&#xff08;LED点亮测试实例&#xff09; 一、 开发工具版本列表二、安装过程三、实例测试&#xff08;点亮单个LED&#xff09;0、功能需求分析1、Proteus绘制电路原理图2、STMCubeMX 配置引脚及模…

35.网络游戏逆向分析与漏洞攻防-游戏网络通信数据解析-登录成功数据包内容分析

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果 内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;34.登录数据包的…

2.3 Mac OS安装Python环境

Mac OS安装Python环境 和 Linux 发行版类似&#xff0c;最新版的 Mac OS X 也会默认自带 Python 2.x。 我们可以在终端&#xff08;Terminal&#xff09;窗口中输入python命令来检测是否安装了 Python 开发环境&#xff0c;以及安装了哪个版本&#xff0c;如下所示&#xff1…

go的for循环应该这么用

目录 目录 一&#xff1a;介绍 1: for流程控制 2&#xff1a;for-range流程控制 二&#xff1a;实例展示 1&#xff1a;//按照一定次数循环 2&#xff1a;//无限循环 3: //循环遍历整数、各种容器和通道 4&#xff1a;遍历通道 5&#xff1a;//指针数组循环 6&…

javaWeb个人日记(博客)管理系统

一、简介 在快节奏的生活中&#xff0c;记录生活点滴、感悟和思考是一种重要的方式。基于此&#xff0c;我设计了一个基于JavaWeb的个人日记本系统&#xff0c;旨在帮助用户轻松记录并管理自己的日记。该系统包括登录、首页、日记列表、写日记、日记分类管理和个人中心等功能&…

ssm006基于java的少儿编程网上报名系统+vue

少儿编程网上报名系统 摘 要 在国家重视教育影响下&#xff0c;教育部门的密确配合下&#xff0c;对教育进行改革、多样性、质量等等的要求&#xff0c;使教育系统的管理和运营比过去十年前更加理性化。依照这一现实为基础&#xff0c;设计一个快捷而又方便的网上少儿编程网上…

Python程序怎么打包成exe文件

前言 pyinstaller可以将.py文件打包成.exe可执行文件&#xff0c;即使别人的电脑上没有搭建Python环境&#xff0c;也是可以直接运行程序的。 pyinstaller安装 首先打开cmd&#xff0c;在里面输入下面这一行命令&#xff0c;回车即可。 pip install pyinstaller 我运行命令…

力扣面试150 直线上最多的点数 数学 直线斜率 欧几里得求最大公约数

Problem: 149. 直线上最多的点数 思路 &#x1f468;‍&#x1f3eb; 参考题解 &#x1f496; 枚举直线 枚举统计 时间复杂度: O ( n 3 ) O(n^3) O(n3) 空间复杂度: O ( 1 ) O(1) O(1) class Solution {public int maxPoints(int[][] points){int n points.length;int…

学会Sass的高级用法,减少样式冗余

在当今的前端开发领域&#xff0c;样式表语言的进步已经显著提升了代码组织性和可维护性。Sass&#xff08;Syntactically Awesome Style Sheets&#xff09;作为CSS预处理器的翘楚&#xff0c;以其强大的变量、嵌套规则、混合宏&#xff08;mixin&#xff09;、循环和函数等高…

2015年认证杯SPSSPRO杯数学建模B题(第二阶段)替换式密码全过程文档及程序

2015年认证杯SPSSPRO杯数学建模 B题 替换式密码 原题再现&#xff1a; 历史上有许多密码的编制方法。较为简单的是替换式密码&#xff0c;也就是将文中出现的字符一对一地替换成其它的符号。对拼音文字而言&#xff0c;最简单的形式是单字母替换加密&#xff0c;也就是以每个…

鸿蒙开发图形图像:【图形子系统】

图形子系统 图形子系统主要包括UI组件、布局、动画、字体、输入事件、窗口管理、渲染绘制等模块&#xff0c;构建基于轻量OS应用框架满足硬件资源较小的物联网设备或者构建基于标准OS的应用框架满足富设备的OpenHarmony系统应用开发。 1.1 轻量系统 简介 图形子系统主要包括…

小迪安全47WEB 攻防-通用漏洞Java 反序列化EXP 生成数据提取组件安全

#知识点&#xff1a; 1、Java 反序列化演示-原生 API 接口 2、Java 反序列化漏洞利用-Ysoserial 使用 3、Java 反序列化漏洞发现利用点-函数&数据 4、Java 反序列化考点-真实&CTF 赛题-审计分析 #内容点&#xff1a; 1、明白-Java 反序列化原理 2、判断-J…

开源流程图表库(01):Mermaid.js生成流程图、时序图、甘特图等

一、Mermaid.js的特点 Mermaid.js是一个用于生成流程图、时序图、甘特图等各种图表的开源库。它使用简洁的文本语法来描述图表结构&#xff0c;并将其转换为可视化的图形。 Mermaid.js的主要特点包括&#xff1a; 简洁易用&#xff1a;Mermaid.js使用简单的文本语法来描述图表…

AugmentedReality之路-通过蓝图启动AR相机(2)

1、启动AR相关插件 通过Edit->Plugins启用AugmentedReality下面的所有插件 2、自定义Pawn 在Content->ARBase目录右键&#xff0c;Blueprint Class->Pawn创建一个自定义Pawn&#xff0c;命名为ARPawn 给ARPawn添加1个Camera组件 在Content->ARBase目录右键&a…

聚观早报 | 滴滴2023年Q4营收;微软推广Copilot

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 3月25日消息 滴滴2023年Q4营收 微软推广Copilot 极狐汽车将出口西班牙 华为公开智能驾驶新专利 华为P70系列发布…

数据可视化基础与应用-04-seaborn库从入门到精通03

总结 本系列是数据可视化基础与应用的第04篇seaborn&#xff0c;是seaborn从入门到精通系列第3篇。本系列的目的是可以完整的完成seaborn从入门到精通。主要介绍基于seaborn实现数据可视化。 参考 参考:数据可视化-seaborn seaborn从入门到精通03-绘图功能实现01-关系绘图 …

抖音视频无水印批量下载软件|视频关键词爬虫提取工具

抖音视频无水印批量下载软件&#xff0c;轻松获取你想要的视频内容&#xff01; 想要快速获取抖音上的视频内容吗&#xff1f;现在推出的抖音视频无水印批量下载软件将帮助你实现这一愿望&#xff01;主要功能包括关键词批量提取视频和单独视频提取&#xff0c;让你轻松下载喜欢…

分类模型评估:混淆矩阵与ROC曲线

1.混淆矩阵2.ROC曲线 & AUC指标 理解混淆矩阵和ROC曲线之前&#xff0c;先区分几个概念。对于分类问题&#xff0c;不论是多分类还是二分类&#xff0c;对于某个关注类来说&#xff0c;都可以看成是二分类问题&#xff0c;当前的这个关注类为正类&#xff0c;所有其他非关注…

阿里二面:谈谈ThreadLocal的内存泄漏问题?问麻了。。。。

引言 ThreadLocal在Java多线程编程中扮演着重要的角色&#xff0c;它提供了一种线程局部存储机制&#xff0c;允许每个线程拥有独立的变量副本&#xff0c;从而有效地避免了线程间的数据共享冲突。ThreadLocal的主要用途在于&#xff0c;当需要为每个线程维护一个独立的上下文…

影视文件数字指纹签名检验系统的用户操作安全大多数

国内网盘服务大规模出现版权问题。 一些个人或团体会通过云存储客户端将主要由电影、电视、音乐组成的文件上传到网盘&#xff0c;然后在圈子里分享。 可供下载。 大量受版权保护的视频音乐就是通过这种特殊的盗版方式传播的&#xff0c;而这种传播方式暂时不受监管。 一些云存…