序
菠菜很少讲框架,因为在菠菜看来,框架只是一个让开发更快的工具。接触广告系统的框架后,发现有一种新的编程思路,可以最大程度的解耦逻辑块,支持数百甚至数万个逻辑。让我们一起来看看吧。

框架的起源
我们常见的后端框架看起来像RESTful。一个接口对应一个控制器中的一个方法,然后这个方法会做相应的逻辑处理,但是逻辑不会特别复杂。而一个广告系统的一个界面,往往一开始就有几十个逻辑,后续需要不断优化广告收入的时候,就会发现几十个逻辑变成了100个以上,然后更多,那么如何支撑过多的逻辑就成了重中之重。
结构
好了,事不宜迟,马上开始介绍框架,如下图:
首先,这个框架是基于Http的。框架中Api的概念其实是相当明显的。一个Api对应一个接口,比如竞价接口、广告展示通知接口等。HTTP中path的第一段是api的名字,比如Api1的名字是bidding。具体代码如下:
对于一个Api,有两个部分,一个是Proto,一个是Ploy,如下图所示:
普罗托呼吸装置
负责解析主协议并返回协议的组织。为什么一个Api需要多个原型?原因是同一接口不同调用方的具体协议格式会有所不同。虽然协议格式不一样,但是经过Proto解析后都是统一的请求数据格式。
那么在请求的时候如何表示不同的协议呢?那就是利用Http中的第二段path,比如request /bidding/baidu/、/bidding/alibaba/,分别对应图中的Proto1和Proto2。具体代码如下:

策略
这是我们要一直写下去的逻辑。通过刚才的流程图你其实可以感受到一些。这个框架的目的是打破逻辑,把它变成一个接一个的策略。我们之前的聚合逻辑是根据功能和代码可读性来划分的。通过这种分解逻辑的方式,让每个策略集中在一个最小粒度的逻辑上,如下图所示:
在实践中,尤其是当一个Api中有上百个逻辑时,这种反汇编模式大大提高了每个小逻辑的可维护性。
Proto和Ploy之间的数据交换
Proto和Ploy,Ploy和Ploy需要一种方便简单的数据交换方式来协同工作。实现Proto时,需要实现两个方法,如下图所示:
前面提到了Request,需要最终将不同的请求协议格式转换成一个内部统一的格式。
会话是数据交换的关键,可以认为是一个HashMap,存储所有中间数据,编码也会根据会话形成返回数据。
那么在实现Ploy的时候还需要实现一个方法,如下图所示:
Ploy还使用会话来交换数据。此外,Request是只读对象,不能写入。

小流量试验
对于逻辑密集型服务,Ploy的小流量测试非常重要。菠菜简单介绍了如何基于这个框架做小流量实验,以及如何统计小流量的结果。如下图:
ExpPloy负责Ploy所有小流量实验的决策。假设ExpPloy在配置文件中知道10%的流量需要用新的策略实现,而90%的流量需要保持不变。然后ExpPloy使用随机算法计算这个请求是否达到10%并保存在会话中。XPloy将在Session中得到决策,并根据决策结果调用a或b。
最后
希望这篇文章能给你在实现逻辑密集型服务时多一种选择。也期待大家的建议,讨论,共同成长!


