Apache Kylin Hadoop队列拆分方案设计与反思


作者: 康凯森

日期: 2016-12-11

分类: OLAP


本文首先叙述了我实现Kylin的Hadoop队列拆分的整个过程,所有的反思和总结都在最后。

背景

Kylin已经在美团点评的各大业务线广泛使用,目前已有20+ Project,200+ Cube。为了便于资源统计和成本计算,我们需要将目前构建cube使用的单一hadoop-kylin队列拆分为各业务线的Hadoop队列。 (我们的Hadoop集群和HBase集群都启用了基于kerberos的安全认证。)

需求分析

为了实现队列拆分这一目标,我们需要实现两个需求:

  1. 我们Kylin服务使用的hadoop-kylin用户可以提交Hive作业,MR作业到各业务线的Hadoop队列。
  2. 可以在project粒度配置各project的Hadoop 队列信息,并实现cube > project > server的配置优先级。

方案设计

对于需求1,前期在没有分析需求,认真思考的情况下就决定采用impersonate方案,因为是小伙伴推荐的方案,也是启用kerberos的安全认证时最正统,最常见的方案,在我们团队内部也广泛使用。impersonate简单来说就是用hadoop-kylin用户impersonate(冒充)成各业务线的Hadoop用户(像hadoop-waimai),然后再由hadoop-waimai用户提交MR作业到自己的Hadoop队列(像root.hadoop-waimai.etl)。

对于需求2,分为2步,首先需要在project元数据中增加配置信息,其次需要实现cube > project > server的配置优先级。

方案排期

对于两个需求,我首先查看了cube 扩展配置的相关代码,大概确认了需求2的实现思路和方式,感觉把握比较大。对于需求1的impersonate方案的相关概念和实现方式我并不清楚,所以决定先实现需求1,再实现需求2,然后再整合两个需求。

需求1实现 impersonate方案

所谓的impersonate方案就是当Hadoop集群启用基于kerberos的安全认证时,我们可以设置一个超级用户,然后这个超级用户就可以假冒成其他的Hadoop用户提交MR作业。

impersonate的代码实现十分简单,主要是调用UserGroupInformation.doAs。具体到Kylin中,我们在提交Hive SQL,MR job, 读写HDFS文件,访问HBase集群前都需要进行impersonate。我较快地实现了此方案。 但存在以下问题:

  • 社区版的Hive通过命令行没法直接impersonate这也意味着我的改动无法提交到Kylin社区。 在我们公司内部可行是因为我们团队修改了hadoop-common的代码,使得Hive在提交MR作业前都会进行impersonate。
  • 需要在HBase集群为impersonate后的代理用户赋予权限
  • 需要将目前的hadoop-kylin用户替换为超级用户
  • 无法提交到Kylin社区,意味我们代码的维护成本变高

需求1实现 在Yarn中为Hadoop-kylin用户赋予其他队列的提交权限

由于需求1的impersonate方案实现存在以上问题,主要是无法提交到社区,而且改动的文件较多(虽然许多都是1行改动),导致代码的维护成本较高。 所以这个方案在要上线前被小伙伴否决了,当时我的内心当然是拒绝的

之后小伙伴提醒到我们的目标只是实现hadoop队列拆分,所以只需要在Yarn中为hadoop-kylin用户赋予其他队列的提交权限就可以了。当时听到这个建议我愣了一下,和Yarn的小伙伴确认后我的内心更是崩溃的

此方案的实现是十分简单的,因为kylin本身支持cube粒度覆盖MR作业配置参数,所以我只需要实现支持cube粒度覆盖Hive参数。我在半天内就实现了此方案的开发,测试。

需求2实现 增加project粒度配置并实现配置优先级。

首先给project本身增加配置是十分简单的。至于实现cube > project > server的配置优先级思考了几种方案,可行的两种方案是:

  1. 在cube初始化时就获取project的配置。
  2. KylinConfigExt中获取具体的配置时再去获取project的配置。

在公司我采用了方案2。方案1其实是我最初想到的方案,没有采用的原因是我起初认为在cube初始化时必须知道cube相应的project但是在cube初始化时cube还没有添加到相应的project

最终在社区实现的方案是1。原因是我在Apache Kylin PMC 李扬的提醒下才意识到我们并不需要在cube初始化时就获取cube相应的project,我们只需要在relaod cube的时候获取cube相应的project就可以

关于此需求实现的相关讨论,具体思路和代码可以查看 KYLIN-2180:Add project config and make config priority become "cube > project > server"

反思1 凡事一定要先搞清概念

如果我一开始对hadoop队列,作业提交等概念都有清晰,正确的理解,知道只要有权限的hadoop用户就可以向相应的hadoop队列提交作业,我可能一开始根本就不会考虑impersonate方案。

其实我们每个人的知识体系都是基于对所有概念的理解。引用李笑来的一段话来总结:

衡量一个人是否聪明,其实很简单:

1. 看他的操作系统里有多少必要、正确、清晰的概念;

2. 看他的操作系统里那些必要、正确、清晰的概念之间,有多少必要、正确、清晰的关联。

显然基于李笑来的理论,每个人的聪明显然是可以习得的,而不是天生的

反思2 勿忘初心(时刻不忘记最初目标)

在我们工作生活中,经常会有这样的情况:我们的目标是解决问题A,然而我们发现解决问题A需要先解决问题B,解决问题B需要先解决问题C·····

有时间需要先解决2,3个问题可能是比较正常的,但是如果我们的目标问题本身只是个小问题,我们的方案却需要先解决2,3个甚至更多问题的时候,我们就需要反思我们的思路或方案是否合理,是不是我们走远了,有没有更简洁的方案能够直接解决我们的目标问题。

反思3 跳出思维定式

在我还没有进行队列拆分前,我脑子里就被印上了这样一个错误的概念impersonate方案可以实现队列拆分,实现队列拆分就需要impersonate

在实现kylin的配置优先级时,我想当然的觉得cube在初始化时就需要知道cube相应的project。

在生活中,我们某个时间段专注于某个领域,某个问题,视野就会有限,思维也会逐渐形成定式。 所以我们和他人的讨论交流是很有必要的,有时即使是他人的一句无心之语,都有可能让我们“醍醐灌顶”。即使是一个人独立工作,当我们毫无头绪时,也可以暂时放下,过段时间就可能会有新的灵感和思路。

反思4 避免沉没成本的影响

所谓的沉没成本的影响是,当我们为一件事付出了很多后,即使我们明明知道这件事已经不值得做了或者做错了,但是我们不愿我们之前的付出付诸东流,就将这件错误的事情继续下去

当我已经完全实现的impersonate方案被否决时,开始时我的内心是不愿放弃的,不愿自己的付出被否认。觉得放弃这个方案就意味着我是错的,意味着我浪费了时间和精力。

后来想了想。谁都会犯错,每个人都是在一步步的试错中成长起来的。否定自己过去错误的想法,并不代表否定自己。关键是当事实已经告诉我们的确错了的时候,我们要勇于放弃,即刻改正,并从中总结经验教训

总结

Apache Kylin的Hadoop队列拆分有多种方案实现,主要是如何选择简洁的,易于维护的,和社区兼容的方案,最终的相关代码其实十分简单。最终我们要将每个业务线的队列拆分,也只需要在project页面增加如下两个配置,可以很方便的灰度测试,逐个project上线。 屏幕快照 2016-12-11 下午2.16.05.png-58.8kB

致谢和相关资料

感谢Apache Kylin PMC 李扬、大月的建议和Review。

KYLIN-2180:Add project config and make config priority become "cube > project > server"

KYLIN-2095: Hive mr job use overrided MR job configuration by cube properties 在我改变需求1的方案后,发现社区已经实现了这个功能,但是个人感觉cube的HiveJob覆盖Hive的相关配置在JoinedFlatTablegenerateHiveSetStatements中实现更简单和更合理。


评论