使用celery做异步的clickhouse表导出--带去重和任务数控制

问题描述

1. 背景

需要对clickhouse里的日志表进行导出,原有的API接口是通过REST API从clickhouse查询并通过HTTP传输,虽然给clickhouse的HTTP接口启用了压缩,但效率和资源利用仍然很低。要等待很长时间,页面可能会超时。原有的API值保留了很少的数据,不存在这个问题。但使用clickhouse后,数据保存的非常大,所以请求时间就很长了。

2. 目标

所以接下来的目标就是很明确了,因为时间长,要使用异步。因为数据量大,所以要更换更高效的导出方式。显然直接用数据库本身的导出方式,直接导出文件更高效。因为要防止用户反复请求统一个参数,因此任务要有管理。首先就是去重,防止重复下发同样的导出任务,第二个就是要限制并发或同时下载的任务数,防止吃太多CPU资源。因为clickhouse的查询通常都会消耗大量的硬盘、CPU、内存资源,尤其是CPU。

目标:异步,利用数据库的导出功能,任务要有数量和状态管理。

3. 方案

根据以往的经验,celery就可以做异步任务。所以直接选定了celery,clickhouse-client的导出。而任务要有状态管理,可以在redis里管理状态。

方案:celery做异步,clickhouse-client直接导出压缩文件。对任务在redis管理。

接下来,就是如何实现。首先从celery执行一个简单任务开始。

一、clickhouse表的导出

clickhouse可以直接导出到压缩文件(见引用),格式也可以支持多种多样。我们需要的压缩的csv格式,因此只需要提供csv.gz的文件名后缀即可。

SELECT *
FROM nyc_taxi
INTO OUTFILE 'taxi_rides.tsv.gz'

根据不同表、不同起止时间查询,可以得出SQL模板:

select * from {table_name} where {time_field} >= {start_time} and {time_field}  < {end_time}
INTO OUTFILE '{filename}'
format CSVWithNames
SETTINGS max_threads = {max_threads}

 这里有两个问题需要解决:

1. clickhouse的HTTP客户端不能使用导出的INTO OUTFILE语句。

所以只能封装一个使用clickhouse-client的命令调用导出,celery的worker也需要和clickhouse运行在一起。

def execute_query_local(query, database):
    # 启动子进程执行命令:
    # clickhouse-client --query  query
    ret = subprocess.check_call(["clickhouse-client","-d", database, "--query", query], shell=False)
    return ret

2. 导出数据的CPU消耗很大,因此要限制一下线程数,以降低消耗。我使用了10个线程。时间长是可以忍受的,但崩溃是无法忍受的。

SETTINGS max_threads = 10

二、celery异步任务

1. 最小可用

首先,一个celery的最小可用任务,这没有什么难度。可以借助ch

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值