分布式链路追踪系列番外篇二(Spark Job优化记)
最近在使用Jaeger提供的Spark Job时出现了OOM的问题,特记录一下优化过程
问题介绍
如下,我司采用Jaeger+Opentracing的解决方案来搭建我司的全链路追踪系统,但是目前的Jaeger缺失对链路数据的分析。目前提供的就是一个Spark Job来计算服务间的依赖关系。
如下图,图中的DB,我司采用的是Elasticsearch,而且为了减少Spark环境的维护工作以及资源的消耗,我们使用了Jaeger官方提供的jaegertracing/spark-dependencies,就直接在单机上跑Spark Job。在上线初期,数据量不大,一直运行良好。但是随着接入的系统越来越多,数据量变得越来越大,导致最近几次跑Spark Job经常OOM,所以就有了今天这篇文章。
OOM
解决方案
OOM的常用解决方案,很简单就是加内存。确实我们也试着加了内存去跑。一开始只配置了4G的内存,后来配置了10G内存去跑,也还是不行。那是不是还需要加内存去跑呢?其实我们知道一直加内存一定是可以搞定的,实在不行的话,我们还可以使用几台机器搭建一个Spark集群来搞定,反正加内存,堆机器就肯定可以搞定。
然后现实预算是这样的
预算
所以,我们能不能使用最小的代价把这件事搞定了。
于是我们就去github上使用蹩脚的英语去骚扰作者了,有啥既省钱又方便的解决方案吗?然而作者一般的建议放集群上跑。
没办法
这纯粹是意淫啊,我并没有去开源项目上骚扰作者,我也建议不要一有问题就去问开源作者,首先自己要思考解决方案,然后实在不行的话抱着试一试的想法去提问。
那怎么办呢?
我们可以切换一个思路,既然是因为数据量太大导致OOM了,那我们能不能减少数据量去跑任务呢?于是就开始一顿猛操作,发现有以下几个解决方案
-
1.给官方提PR,支持在Spark Job中配置查询语句(缩小数据量)
es读取Spark数据可参考es-spark,es-spark 处理逻辑可参考ElasticsearchDependenciesJob -
2.使用ES的reindex功能,讲一小时内的数据量导入到一个新的索引。具体参考elasticsearch官方文档 reindex
-
3.使用alias + filter功能。给原索引在1小时内的数据加一个别名。
具体参考elasticsearch官方文档 aliases
方案比较
第一种方案,如果不是很着急而且作者也同意的话也算是一个比较经济实惠而且优雅的解决方案。但是就是时间长一点,而且需要一定的源代码修改能力。
第二种方案,要稍微牺牲一点ES的资源,就是额外多索引一份数据给Spark Job,并且需要管理额外的索引和别名。也算可以接受。
第三种方案,既不需要消耗额外的资源,也不需要修改官方代码,只需要管理别名,配置一下Spark Job就可以了。总体来说是目前最优的解决方案。
所以,我们选择方案三:使用alias + filter
实战
如果对ES的别名机制还不太了解的小伙伴,建议先看一下ES的官方文档。简单来说别名就像是数据库中的视图(view)。
Spark Job优化
步骤一:给原索引加上别名
如下,我们给2019-08-13索引14点到15点的数据加上了别名,实际操作的时候需要加上定时任务,每天都需要给新生成的索引加上别名。可以使用es官方提供的curator来管理定时任务。
POST /_aliases
{
"actions" : [
{
"add" : {
"index" : "jaeger-span-2019-08-13",
"alias" : "hour-jaeger-span-2019-08-13",
"filter": {
"range": {
"startTime": {
"gte": 1565676000000000,
"lte": 1565679600000000
}
}
}
}
}
]
}
步骤二:修改Spark Job配置
修改Spakr Job的ES_INDEX_PREFIX配置
ES_INDEX_PREFIX=hour
注意这里的hour就是上面别名的前缀。实际Spark Job在执行的时候实际获取的索引名称规则是${ES_INDEX_PREFIX}-jaeger-span-yyyy-MM-dd。所以这里ES_INDEX_PREFIX设置为hour
步骤三:管理所产生的依赖索引别名
当跑完上面的任务的时候,新生成的依赖索引名称是hour-jaeger-dependencies-2019-08-13,然而默认的依赖索引应该是jaeger-dependencies-2019-08-13,索引需要给新生成的索引添加别名。
当然如果你们是自己获取的依赖关系,然后自己去画依赖图(官方的依赖图不够好)的话,那么就可以改变一下索引就可以了,如果使用的是自带的依赖图的话,那就需要管理一下别名。我司就是直接自己画的依赖图,所以不需要加别名,直接获取就好。
优化方案注意点
- 该优化方案的前提是依赖关系不怎么变化或者能接受依赖关系比较大的延迟。所以我们可以根据1个小时的数据中的依赖关系来表示一整天的依赖关系。
- 选取的时间段一定要是业务相对而言比较频繁的时候,不然容易导致确实部分服务的依赖。如一些运维使用的系统,正常在上班时间使用得较多,所以要尽量选取自己公司流量不大的系统的业务高峰期,流量大(C端业务)的系统不用管,肯定会有数据的。
- 如果比较难以选择一个时间段来保证所有的系统都会有业务发生,那么就需要多个时间段来跑任务,然后使用定时任务来合并依赖结果