cjuexuan / mynote

237 stars 34 forks source link

XQL和Spoor的一些实践经验 #65

Open cjuexuan opened 4 years ago

cjuexuan commented 4 years ago

起因

转眼间在我司呆了快4年了,从最开始做XQL(数据计算平台),到后来做Spoor(监控系统),到现在在数据平台这一块做XQL,Panda(调度系统),Unicorn(数据可视化)等,最近到年底了总要总结总结这些年做过的XX系统,所以就有了这篇文章,今天这篇就讲一下XQL和Spoor的一些实践,后续有时间再把Panda和Unicorn的一些实践经验也整理下。

XQL的一些实践经验

XQL 是我司内部使用多年的数据计算平台,每天产生上亿的Spark task和PB级别的数据读取,任务数占到整个公司数据计算任务的70%。

16年做XQL的时候是从0到1的过程,XQL对外交互并不复杂,对用户的核心功能就是用户提交SQL,我给他跑出来,对于SDK来说也是做了大量的封装,所以我们可以很容易的重构而不用担心对用户产生影响,从UI交互来说呢,XQL是我做的这些系统里最简单的,从开始的只有黑框提交,到后续支持本地浏览器的多窗口,再到后来支持多workspace和tab,风格都一直没产生什么变化。 这个系统的重心是和用户诉求直接相关的, 对于用户来说,希望的是我们性能足够好,尽快的跑完,这里提取成目标就是性能要好,性能要好最简单的方式可能就是设计成一个可横向扩展的架构,然后不满足需求的时候就加点机器呗,但是机器都是要钱的,按照我们dalao精益求精的心态(还是qiong),希望我们尽可能的优化引擎的性能。 所以我们在这里就主要走了两条路,一条路是优化,优化的难度其实是比较高的,所以我们也只能是把一些比较关键的问题通过修改开源系统的源代码的方式去优化掉,另一条路就是治理了,在这一块上我们花了更多精力,因为这一块的出效果会比较快,我们对整个流量做了细粒度的拆分,然后做了一套比较复杂的路由算法来满足用户的诉求,我们也通过大量的监控数据来找到我们系统的流量高峰和低谷,做了一些弹性扩容,这样可以保证我们峰值的一个系统健康度,并且在流量低谷将机器释放出来做其他事情。另外林子大了,我们人力也有有限,所以这个时候就要上一些规则来限制用户的不合理使用,比如用户可能处于有意或者无意会跑一些大的sql,但是你不能一刀切的说完全不能跑,毕竟中台还是服务于业务的,这种情况下有几种可能:

  1. 你让他跑,但很浪费资源
  2. 你不让他跑,影响了小伙伴的工作

这个问题就变得棘手了,不过好在有成熟的其他业务模型我可以直接拿来用,比如积分体系,在我们日常用的app有些是把他的权益和他的积分进行了关联的,比如同样一件事情积分高的人可以做但积分底的人就不能做,做事情可能会扣掉用户的积分。于是我们做了一个积分体系,当用户跑了一些我们认为比较浪费的sql的时候会对他进行一些扣分,如果分不够了就只能让他的领导进行审批了,另外我们也有每个部门的资源消耗来和部门进行虚拟结算,这样可以宏观的解决掉用户的一些问题

总结下:

  1. 优化,对核心的一些路径进行优化
  2. 细化: 对流量进行场景拆分和隔离,细化资源使用
  3. 生态化: 利用一些成熟的业务模型,比如积分等进一步加强对用户的管理,提高整体的资源使用率,驱使用户提高计算的ROI

我们在做中台类系统的时候上线不代表结束,那只是刚刚开始,后续要用产品思维、运营思维、数据思维来治理好整个生态,这样才能让大家用的开心。这些年也见过一些系统他们的开发者在上线之后一直停留着堆积功能的情况,对用户的真正诉求没有很好的挖掘,最终做出来的效果当然也很难令人满意了

Spoor的一些实践经验

Spoor目前是一个通用的监控系统,目前的量级大概是每天百亿级别的metric事件。

spoor大概是17年6月开始做的,起初只是做一个spark的metric采集,后来做成了一个通用监控告警服务,并且已经不局限于大数据这一块,目前spoor在我司的推荐在线服务中也被广泛的使用, 每天也有百亿级别的监控数据产生,不过目前系统已经交给我司大数据基础设施团队在维护了。做spoor的时候我们还是充分的利用了大数据的技术,在指标采集通道这一块我们大量使用了kafka,然后通过spark struct streaming进行预计算,再将指标放到存储中去,存储早期我们用的是es,由于性能问题我们后续又换成了clickhouse,目前整个系统也在线上稳定跑了2年多时间了,19年7月左右我基本把整个系统交接给兄弟团队了在spoor开发过程中我得到的一些成长是:

  1. 由于spoor是一个中间件项目,量又比较大,在实现过程中有性能细节需要去注意,比如序列化和反序列化这一块我们是实现了自定义的序列化协议,在传输过程中,我们也利用kafka和spark streaming的partition特性减少shuffle,利用spark struct streaming的state做预计算,提前聚合,来提高查询的性能。另外由于客户端在用户jvm中托管,为了避免旁路系统对用户产生影响,我们也支持了热部署和开关等常见的功能
  2. 用户在使用spoor的过程中主要是对一些指标监控,而metricType的多样性会导致api过于复杂,用户不易理解,另一方面api是用户直接调用的,显然用户希望的是稳定,所以我们在开始就力求设计一套功能很丰富的api让用户调用,并且简化他们的理解,这里我主要参考了RedisTemplate的Api设计,把操作抽象到类似ValueOperations的对象中,所以我们就提供了counterOps,histogramOps,timeHistogramOps等各种操作类,入口尽量简单,而不是把所有的方法都直接平铺在api的调用入口,另外我们也提供了通用的注解来简化用户调用
  3. 后续随着业务的扩展,我们发现es不能满足我们的性能需求了,这个时候我们就把目光放到了clickhouse中,经过调研发现clickhouse能满足我们需求,我们就做了一段时间的双写和生产的查询流量复制,最终平滑的迁移到了clickhouse中,而且由于我们架构中有基于kafka的metric channel,所以整个过程对用户完全透明

简单总结下: 在中间件类项目中,系统的稳定和高效是第一要务,另外我们也要注重api设计的可扩展性和易用性。对于旁路的中间件项目一定要做好系统保护,关键时候不要影响到业务

fywxin commented 3 years ago

老陈,你好! XQL是先按application 预先在yarn里面申请了指定的资源量,所有sql复用这些应用节点,类似数据库连接池,不知我的理解是否正确。 我想请教下,这种情况下,该如何获取 每次客户端提交sql 使用的 cpu 占用时长与内存大小 呢,想了解下你们是怎么解决的,非常感谢~

cjuexuan commented 3 years ago

@fywxin XQL是类似连接池的机制,是走的预先申请,至于每个客户端的占用,我们目前是这样计算的,假设一个XQL实例允许允许n个任务,当前只有一个任务,任务1运行,那么这个任务独占全部引擎的资源,执行到x秒后,进来一个新的任务2,那么从x秒开始,任务1和任务2各占50%,如果y秒后,任务1结束,那么任务2就独占资源,占用100%,再过z秒后,任务2结束, 对于任务1来说,就是x秒的独占,和y秒的50% 对于任务2来说,就是y秒的50%和z秒的独占

fywxin commented 3 years ago

@fywxin XQL是类似连接池的机制,是走的预先申请,至于每个客户端的占用,我们目前是这样计算的,假设一个XQL实例允许允许n个任务,当前只有一个任务,任务1运行,那么这个任务独占全部引擎的资源,执行到x秒后,进来一个新的任务2,那么从x秒开始,任务1和任务2各占50%,如果y秒后,任务1结束,那么任务2就独占资源,占用100%,再过z秒后,任务2结束, 对于任务1来说,就是x秒的独占,和y秒的50% 对于任务2来说,就是y秒的50%和z秒的独占

感谢老陈分享这个思路