黄金眼业务形态

 

京东集团使命——“技术为本,致力于更高效和可持续的世界”。黄金眼作为集团内经营数据分析的重要入口,为众多采销与运营提供分析型数据看板,向其制定经营策略、复盘经营成果提供了重要数据支撑。但集团数以万计的采销岗位变化、组织架构变化、品牌、品类等属性变化,会导致数据库中历史的离线岗位、属性信息不准确;商家和自营sku关联信息需要实时更新,每日更新数据量千亿以上,诸如此类因素会对推数和查询产生巨大影响。这意味着,高效稳定的推数工具和查询架构对数据看板的准确、高效显得尤为重要。

 

 Easy OLAP 数据链路

Easy OLAP 数据源主要为实时JDQ(kafka topic)、离线Hive数据。依赖ClickHouse官方 JDBC ,实时数据支持通过Flink 导入,离线数据主要使用Spark job 导入。

 

2、 EasyOLAP ClickHouse 全链路监控

 

ClickHouse在京东流量分析的应用实践_ClickHouse

Easy OLAP  ClickHouse 监控链路

 

目前Easy OLAP ClickHouse 项目,主要依赖node_exporter 采集暴露机器层面指标和Clickhouse Prometheus port 暴露ClickHouse 服务层面指标,Prometheus 采集,时序数据库存储。

值得一提的是,Grafana支持直接链接ClickHouse server查询,我们为ClickHouse 定制了很多依赖system库下的表而建立了很多全局的分布式表,供Grafana展示。

 

3、 Easy OLAP ClickHouse HA

 

ClickHouse在京东流量分析的应用实践_ClickHouse_02

ClickHouse HA

概念:

Cluster: 单个clickhouse 物理集群

Group:  单个 clickhouse 逻辑组,在clickhouse group内实现数据备份,集群节点扩缩容Group 为最小单位,实现最小粒度的数据迁移工作

Node: 单台物理机器

Instance: 单个ClickHouse Server 进程

shard_replica:  图中 0_0、0_1、0_2 .. 表示相同shard内不同replica

 

设计亮点:

1. 设计逻辑Group概念,在单个Group内副本达到高可用。

2. 依赖ClickHouse storage_policy 设计单台机器多实例、多磁盘部署。

3. Group 为集群扩缩容最小单元,集群在扩缩容情况下,可达到最小数据迁移甚至不迁移的情况。

4. 可满足单个SQL使用集群所有资源。

 

 

1、 集群检查

元数据补全:推数前检测CK所有节点上system.tables是否已存在表、表结构是否一致,如不存在,根据hive表schema信息,字段类型自动映射成CK表类型,支持自定义分区、表字段函数生成新的DataFrame,on Cluster方式创建CK本地表和分布式表。

集群负载:调用集群接口或者直接访问集群物理机,获取集群中是否存在cpu低于80%、内存低于70%、负载低于峰值60%副本集合,如存在,则按资源等级动态降低并发,直至暂停推数,以保障推数期间ck集群稳定使用。

删除数据检查:因CK删除大分区存在一定延时性,超过1G分区先detachPartition再在空闲时段dropDetachPartition,低于1G的小分区,删除后通过count计算分布式表查看数据是否已删除完成。

元数据更新:CK更新本地表,根据用户新加字段类型、修改字段类型、删除字段类型,执行相应DDL SQL on cluster,完成更新,分布式表自动删除并映射新的本地表创建分布式表。

 

2、 数据传输

数据切分:有2种方式,一种离线数据生成一个uuid,hash_key_for_shard可以直接hash这个字段,这种会有一个影响,sql聚合的数据分布在不同的节点,增加IO开销。另一种coalesce(cast(abs(hash(A,B ,离散度高的字段)) as int) %集群分片数,0),A B为索引字段,当索引字段的离散度不高时,增加一个或者多个离散度高的字段,保证所有节点的数据是均衡的,同时命中索引的情况下,数据在一个节点,减少网络开销,提升查询效率。

并发推数:推数前由于hive可能是多分区的情况下,需要重新分区并合并小文件,减少多批次小文件导数sqlContext.sql(sql_inserttable.stripMargin).toDF().repartition(5).saveToClickHouse(dbName = targetdatabase, tableName = s"${targettable}_local", index = Integer.parseInt(shardnum))并发数取集群分片数的1/4,写入线程数"spark.dynamicAllocation.maxExecutors", "4"。这样5个推数任务,同时推数的情况下:任务数5*并发分片数10*写入线程数4/集群分片数40<=15,每个节点同时写入的线程低于15对查询影响较小,多副本的情况下,动态选择负载小的副本集合推数。

异常处理:在hive中正确的数据,ck中可能无法导入,捕获异常数据的同时,打印出来并进行计数,上游优化数据或者舍弃ck无法导入的数据,Counter值,在最后的验证环节提供数据支撑,保证源数据量=ck中数据量+异常数据量。

 

3、 数据验证

数据量检查:推入ck的数据量=源数据量-异常数据量

指标合理值检查:选择需要验证的指标,uv、pv等指标除双11、618期间,增长一般不超过大促峰值,超过阈值告警,上游需检查数据是否正确。

空值检查:当数据量为0推数任务报错,多字段为空时任务告警离线确认。

 

ClickHouse在京东流量分析的应用实践_ClickHouse_03

 

基于Spark开发的CK推数程序,每日新增数据超过数千亿行,峰值导入每分钟数亿行,副本同步一分钟以内,重要数据,多个副本同时推,保证各副本数据一致性。统一服务接入多个应用并提供查询优化、结果合并、安全限流等保障,目前按日多维查询秒级内,查询qps达到30+,服务稳定,0级业务提供独立保障。

 

 

异步物化视图,在原有的分布式表和本地表中把需要去重的字段类型更改为A AggregateFunction(uniq, String),uniq还可以设置为uniqCombined,uniqCombined64,uniqHLL12,uniqExact。根据业务需要选择不同的精度,聚合数据后insert的时候uniqState(A),查询时使用uniqMerge(A),从明细到聚合物化视图,大约可以减少70%的数据量,提高查询性能,进一步提高聚合程度的话,可以设置单指标表,查询时join。

 

2、字典函数

 

ClickHouse在京东流量分析的应用实践_ClickHouse_04

 

字典函数更新时可并发更新,on cluster根据集群配置情况使用,数千万的数据量,采用HASHED()格式,大约需要占用数十G的集群内存,COMPLEX_KEY_HASHED()占用的内存更多, select dictGetString('db.dict_dept','dept',tuple('1')) AS id,dictGetString(' db.dict_id_name','name',tuple(id)) AS name,字典查询结果可以作为参数传入下次字典查询。

 

3、ck刷岗

 

ClickHouse在京东流量分析的应用实践_ClickHouse_05

 

京东集团内数万的采销岗位、组织架构变化,品牌、品类等属性变化,数据库中历史的离线岗位、属性信息不准确,商家和自营Sku关联信息需要实时关联更新,我们采用在ck中明细数据刷岗的方案,流量明细表根据业务需求先进行预聚合,每天大约可以减少70%的数据量,刷岗信息将维表更新到字典函数里,实时加载到内存,以提高刷岗效率,每天数据刷岗时间3分钟,每日可更新数据周期6个月,无需查询时关联,单次查询性能大约提高30%,高并发情况下,大幅提高qps。

 

4、 多活集群

 

Clickhouse vs Doris

ClickHouse在京东流量分析的应用实践_ClickHouse_06

 

 

 统一服务根据各CK集群的负载能力,分发不同比例的查询请求,每个集群设置独立线程池,保证在瞬时高并发的情况,指标熔断、查询熔断保护CK集群,以保证业务的持续稳定运行,集群中目前主要有3种表形式:离线规范化的明细表、离线聚合的预计算表,CK中进行聚合的物化视图,还有字典表、系统表等其他工具表,在多活集群的情况下,集群版本存在差异、多运维团队的情况下。我们建立了三层缓存模型:SQL缓存、接口请求参数缓存、SQL模型缓存,缓存结果存储在JIMDB(分布式Redis)。在缓存都未命中的情况下,下发请求到CK数据源,大促备战过程中,遍历CK中system.querys中的慢查询,更改时间参数缓存模型,遍历常用部门大查询提前缓存查询结果来保证服务在瞬时高并发的情况下,稳定输出数据到实时明细、战报、JDV大屏等0级应用。