按照新的方法,对老的版本进行升级。还是按照最简化的方式进行提升。
老版的结构如下:
当时还是考虑使用Redis的简单消息队列来缓冲请求,然后处理的服务是按照流程的思路设计的。
整体上的运行效果还是不错的,比较符合设计时的需求,但是在进行拓展时就不太方便了。总体上我感觉流程式的方法都有点“死板”,这种封闭的特点部分的能够保持高度稳定(既然难于修改,那么也就不会有额外的变动);但是在应对需求上,还是对象式的方法比较好。
流程式的设计非常锻炼人的深度思考能力:有点像潜水,练得多了,潜的就深。但是无论一个人怎么强,都会有一个自然的上限,脑力的上限。所以尽量达到一个极限,然后将50%~80%的能力作为一个模块逻辑复杂度的上限。通过结构的设计,将这些模块级联起来,从而形成一个远超人类逻辑上限的工程。模块的基础逻辑上限更高,就有利于实现指数倍差异的复杂系统(差异不是5和6,而是5的n次方和6的n次方),我想这就是流程式锻炼的意义。这是题外话了,不过也说明流程式并不利于浅而广的业务应用,对象式更为合适。
新版的结构如下:
先说新版要面对的需求:
第一个变化是输入增加了两个可选参数:
这两个参数就对应了模型迭代和数据脏的问题:每开发一个新的模型,就在接口中新增一个允许的模型。类似的,可以增加多个版本的规则集来处理数据。
第二个变化是将Redis队列替代为Mongo的CAP collection。
CAP可以像队列一样,当数据到达指定的条数或者存储空间时丢弃老数据。这样就不用担心数据一直膨胀。但是CAP似乎有个缺点:再额外增加字段似乎不允许了。在这个应用中,应该是没有关系的 — 接口启用后字段不会改变。
请求会存在Buffer的request_in下面,不同model_ver和rule_ver的请求放在不同的collection里面。 一个完整的query还是之前的四个字段:task_for, rec_id作为记录的联合主键,functiong_type对应了对象所提供的实体类型,data则是要处理的数据。
因为模型比较大,所以为每个版本的Worker(手动)启动一个Worker,Worker会去Buffer中寻找调用对用模型的所有集合(通过名称),看看是否有需要待处理的任务。具体的Ruleset可以通过集合的名称确定。
处理的结果会存在OprLog.Result里(输出缓存),也同时返回给目标库。
这个变化带来的用处是:
第三个变化是Worker每次处理会写入日志。
目标是我的广域网集群,我把所有的Worker日志都存在这里。当然,每个worker会采用try的方式去进行这个广域网读写。
这样做的目的: