胡思乱想

有时候觉得嘴太笨,很多事情不能很好的讲清楚所有的想法。那么就写下来吧,免得忘记什么。
一、软件功能专业化
这可能是最难的一件事情。每个软件,都有一个它最专注的领域。比如,Oozie解决了数据任务/数据之间的依赖;plumber解决了离线数据交换问题,saltstack解决了运维领域的分布式命令执行+配置文件管理。随着运行在运行在该软件上的业务逐渐变多,软件总有一些场景是满足不了的,比如plumber暂时解决不了实时抽数。比如这样抽象,plumber数据交换,无非包含两部分功能,1.数据读取 2.数据写出。 逻辑没错,但现有的程序架构支持起来很困难。如果对软件原来的功能有错误的抽象,就会对软件原来的架构和用户造成很大的困扰。软件功能的抽象,不能脱离该软件要解决的问题所在的领域。

二、抽象的粒度
由于业务逻辑和性能都会随着业务的开展出现瓶颈,那就会把软件的一部分功能增强。比如为了增强抽数的性能,buffalo就不得不抽象出一种plumber任务。但plumber抽数单机性能总会有瓶颈 比如分库分表的抽取,那么就不得不将单机任务变成分布式任务。那么问题就来了,是应该让buffalo把抽数逻辑拆成分布式的呢,还是让plumber本身升级架构变成一个分布式服务呢?这个呢,就看上述“软件功能专业化”怎么理解了。或者说,大家应该怎么如何抽象软件功能。争论的焦点肯定会集中在观点一:“数据交换是plumber的事情,buffalo本身并不关心实现逻辑”和观点二“buffalo本身就是在编排数据/任务之间的依赖关系,plumber 本身只要关心调度拆分出来的子任务就好了” 这两点上。 归根结底,是要定义buffalo的plumber任务的粒度问题上;当然,这也是在从另外一个层面在反应buffalo对任务(task)的定义。现状是,buffalo对数据任务的处理是粗粒度的,也就是说,一个数据表是分几步、依赖哪些数据计算出来的并未太细致的关心。这时候,如果你倾向于观点二,那就会让buffalo对任务(task)的抽象这个事情上陷入一种矛盾的境地。所以,将plumber服务化、分布式化是一个根据当前buffalo调度任务的粒度决定的。

然而,有些任务引擎是数据依赖的,并不是依赖任务的,是细粒度依赖的。比如Oozie。本身两种抽象粒度并无好坏之分,只是适用场景不同而已。一个集群上出现两个任务编排引擎就会出现诸多问题,比如任务共享、数据依赖问题上。那如何解决这种问题呢?问题其实还在于抽象的粒度。本身粗粒度可以抽象出是由几个细粒度的任务组合出来的。按照这种抽象的方式,又要解决多个任务引擎造成的问题,就不得不对原先的buffalo做一定的架构升级【如图】。
scheduler
其实,还是在抽象。只不过,把tasknode多定义几种类型出来而已。NN负责总体任务调度,每种类型的tasknode负责自身任务调度和调度粒度问题。这样抽象之后,带来的好处非常明显,既解放了原本buffalo需要支持不同的任务粒度、任务类型的难题;又解决了原先任务不能共享的问题。这其实并不是什么新思想,yarn本身就是这么搞的YARN应用场景、原理与资源调度。这本身实现起来可能并没有想象中复杂。因为tasknode 可以抽象成这几个接口。1.接受任务 2.运行任务 3.返回运行结果 4.返回任务执行日志。

三、服务接口化
软件和软件之间总要交互,在交互这个层面,他们应该是平等的。如果不平等,一个服务就会对另外一个服务有侵入性。比如,“buffalo本身就是在编排数据/任务之间的依赖关系,plumber 本身只要关心调度拆分出来的子任务就好了” 这种观点,其实是把tasknode(plumber) 这种级别的服务节点降级成一个原生的tasknode的脚本任务,为了解决性能问题,buffalo就不得不承担原本不属于它的职责。所有的任务都可以用脚本的方式运行,但是所有的交互都是要多经过一层过滤,流程一长,很多实现就变味儿了。靠很长的流程来解决问题,本身就是一种不积极进取的表现。其实就是架构模型不够精简,接口抽象粒度太糙。要解决这种问题,本身很简单,将(二)中抽象出来的四种接口公布出来,所有跟数据任务相关的服务都可以实现她们,变成一个buffalo服务的子服务(tasknode),这样,调度系统就具备了无限扩张的能力。

那么,如何集成各个服务的接口呢?
一旦软件和然间之间具备了平等的关系,使用服务接口就变成了一种很自然的方式。每个服务都公布自己的接口,每个服务都解决了某一个专业化领域的问题,这样,一旦某个软件要涉及到另外一个领域的功能,通过调用各个服务的接口把问题分解到各个软件或者服务来完成就可以了。比如,“自动上线”这个软件,首先呢,它要解决的是运维领域上线这件事情。对其做抽象,包含1.配置文件管理 2.软件包管理 3.文件分发 4.命令分布式执行 5.权限审批 6.上线日志审查 等功能。这么多功能,背后其实映射着很多个专业领域的服务。集成这些小服务之后,再加上该领域内特有的处理逻辑,就变成了上线这样一个服务。领域内的逻辑,本身就是服务本身的一部分。

服务执行的结果如何被另外一个服务获得呢?
其实就是分两种方式1.A服务执行完了主动通知B服务 2.B服务不断的轮询A服务是否执行完任务了
比如,我有另外一个服务特别关心订单任务执行的结果,我该通知它呢?1.我通过buffalo接口不停的去询问它的执行状态
2.写个脚本,配个子任务通知另外一个系统。

四、服务产品化
对于一个服务,可大可小。大的可以做成一个分布式的系统,小得呢,可以变成一个脚本。以前上线的时候,每个开发人员自己写上线脚本,怨声载道。运维的服务能力需要不断的提升,提升的最好的结果就是把服务能力变成一种解决方案,一种能直接使用的产品。是产品,就得讲究点逻辑和人性化。逻辑有很多种抽象的角度,其实很多时候没有对错,只有场景和取舍。讲逻辑,就得最重每个领域内的特定知识。讲人性化,就得尊重用户,就是有没有真的做到客户为先。 如果没有真正的自己编写过上线脚本,不了解每个细节,然后做抽象,很有可能过于抽象了。功能不是实现了就可以的,还要讲究用的爽不爽,扩展成本高不高,安全性好不好等各种各样的细节。

拿上面“服务执行的结果如何被另外一个服务获得呢?”这个问题的第二种方式来举例,对于第2中方式,有没有更友好的办法?如果你用过github,你应该知道webhook。如果你知道qiniu 的文件上传流程,你也会知道技术细节处理带来的质的改变。

五、如何提升开发效率
有时候争吵服务要不要产品化背后的一个原因是,没有开发资源。其实资源远没有那么紧张,是流程太复杂。

发表评论