说明
我还是比较喜欢把文章放在这个专题下,虽然这次的话题其实是个综合性的。
内容
1 理想架构
我一直在构建一个理想的数据处理系统,但这个过程不是自顶向下,一次设计完毕的。而是在不断的实践、反思和推倒重建汇总不断更新的。
或者说,我们对于理想架构的表现会有一些标准和期待,这些标准和期待会形成一套相对固定的设计理念。在工程中,我们会依据可用工具/材料来进行合理的搭配,或者是升级改造,但这套理念是相对固定的。
我曾经因为业务的需要,翻出了5年前的项目代码,发现处了当时所用的工具不同,但内部的核心结构(相对复杂的一个处理)和后来是完全一致的。在两个相距很远的时间点,在我看来产生了奇迹般的重合,所以我相信关于数据处理的核心理念是有可能保持一致的。这件事的意义在于证明:设计的最终目标是可以确定的,有一个稳定的方法和要求。
但是对于IT行业来说,内容太多了,更新速度也非常快。即使我们有很好的想法,但受限于知识以及当时可用工具的限制,我们很难在一开始提出一个完美的方案。甚至从具有专业性开始,我研究了至少5年吧,也只是愈发觉得前路遥远。
比较幸运的是,我觉得即使是当前水平,我也可以构建具有相当能力的系统,足够实用。并且预计在未来的5年内,这个系统的核心能力仍然是可以线性提升的。特别是在chatgpt出来以后,搭建理想系统的可能性、速度都提升了很多,它真是一个划时代的工具。另外,在硬件上整个行业也在以较快的速度前进,摩尔定律似乎仍然有效。
综上:
- 1 实现理想架构是完全可能的,或者说,满分100,考到90分是可行的
- 2 仍然会有不断新的工具、知识跳出来,这些新的东西会部分推翻设计,要重建
- 3 时代有红利,做这件事是很有希望的。从实用的角度,5年左右,系统就可以进化的足够强大。从工具的角度,可能再加5年。
2 实现方法
人工智能需要先人工,才智能
虽然我觉得玩语言游戏不是很好的习惯,但在"人工智能"这四个字上可以例外。关于人工智能的起名其实也有很多历史故事,最终大家接受了"人工智能"这样的称呼(普及率在60%以上吧)还是很有道理的。
- 1 对于普通人,足够抽象,但是又很好记忆
- 2 对于开发者,还是有很多提示的,怎么去做这个抽象的东西
我自身的经验来看,一开始先不要想太高级,先迅速的把一个有用的过程搞出来。例如建模,可能是一个很长的流程,先用最简单,但是最笨的方法去做一遍。然后想想,哪些东西是可以抽象出来,让理解和操作更简单的,也不要想太多,然后再去做。然后,循环往复...
一直到,你的确已经烦透了这件事,占用的时间让你觉得完全不值得,然后你做一个自动化,这就是智能。
因为做得多才能了解的透,因为思考的多,才会有更好的办法,因为不断的优化和实践,才能得到可靠的结果。这个和卖油翁练本事很像,做得多就好;但是又有一点不像,就是要抽象给计算机。
托马斯·阿尔瓦·爱迪生说:天才是百分之一的灵感,加百分之九十九的汗水;但那1%的灵感是最重要的,甚至比那99%的汗水都要重要。
说重复就是99%的函数,而智能来自1%的灵感,如果没有灵性(产生灵感的概率),做人工智能也难有大前途。但是对于有灵性的人来说,汗水就是不可忽略的成功因素了。
不过处在一个时代的开头,只要去做了就不会亏,这又是另一个话题了。
3 重复实例
最近恰好有一个实例,我希望对其进行改进。计划用一年多的时间,分两个阶段,把它推到一个稳定、智能的版本。
首先,已经有一个可以运行的丐版服务。
第一阶段,我计划三次迭代:
- 1 第一次迭代:不做改进,只是将所有的流程清晰化,将相关文档进行整理和集中管理、增加交互部分
- 2 第二次迭代:针对其中的IO、部署组件进行优化 ==> Using Graph
- 3 第三次迭代:对核心的变换组件、控制组件进行优化 ==> Using Graph
整个的内容会非常长,我打算这次只将第一次的内容摘要写出来
本次实例的工作是准实时的获取数据,然后进行处理,最终以短信通知结束。
3.1 结构
从结构组件上,需要两个ADBS和一个APS来完成任务。这个结构可以说是相当简单了,比我之前设想的要精简的多。
3.2 ADBS01
创建过程还是有点麻烦的,虽然我已经做了大量的集成。但是这个流程还是很长。
- 1 数据库服务。如果在机器上开始新的服务,需要分配一个端口,启动docker服务,做好端口透射,然后再进行服务注册(这样在可以在全局被自动连接)
- 2 创建项目。声明项目名称、数据库服务、Redis/Mongo的服务地址、ADBS任务批次及执行间隔时间等配置。在给到配置后,ADBS对象可以生成项目文件。
- 3 执行创建。在进行git同步之后,用ADBS提供的命令可以创建ADBS的库、队列等,并且可以启动持久化服务进行试运行,然后再进行调通测试这些。确保ADBS已经在指定位置运行,并进入就绪状态。
3.3 ADBS01调试
- 1 增量处理。调试sniffer(读取数据)和worker(透传数据)。
- 2 存量处理。按同样的数据规范,直接发往入队列。
ADBS01完成可以形成分钟运行的实时数据库。
3.4 ADBS02 调试
ADBS02会从ADBS01的out中获取数据,然后进入队列。再交给ADBS Worker执行模型预测,这次没有走AETL。
ADBS Worker是模型打分,这个相对固定,未来如果 有新版本的模型还可以灵活挂接。
ADBS02完成了数据的读取和打分输出。
3.5 APS 策略
策略在指定起点之后就会自动读取数据,进行断点执行。最终的信息也是由APS发出。
3.6 需要改进/增补的内容
Add01 RedisOrMongo: 以Redis为缓存(热数据),Mongo作为备份(冷数据) - Pending
这个又需要在前端提供一个页面,注册新的工作空间,来确保Redis不会产生冲突。有些临时的工作空间可以不必注册,这样用完就可以自动释放(例如以TEM_开头的,这些数据也不会进入Mongo)。
RedisOrMongo提供两种模式:
- 1 提供Redis的便捷访问,但不进一步缓存到Mongo
- 2 除了Redis的访问,还自动存到Mongo
这个组件对我的系统运行和设计特别重要,单纯的Redis有了,单纯的Mongo也有了,但是两者之间的桥梁没搭。现在常见的问题是,一些程序直接和Mongo交互,存日志啥的,零零碎碎的交互太多,其实这不是Mongo擅长的。当然就日志而言,LogStash是另一个话题。这个问题暂时也不是啥问题,反正系统能承受。
比较重要的点是元数据保存。在目前的设计中,大量的依赖元数据,这些元数据是由非常多的节点产生的,而且还时不时会发生变化,对于这些大量的零碎的元数据保存、读取,还是需要Redis的。从内存的使用、元数据的持久化和分析又需要使用Mongo,所以这两者必须搭配起来。
当然,除了Redis和Mongo,很多元数据是可以保持在本地文件的,这样可以减少不必要的交互。只要提供一个类似"Flush"的方法,在必要的时候把本地元数据冲掉就可以了。
Add02 NetworkxAndMongoAndNeo4j: 以nx作为本地子图管理和构造,图信息将传送给Mongo,然后再同步到Neo4j - Pending
第一步先考虑用nx来表达,构建一张子图,或者说一个工作空间内部的关系。后面的内容我不关心,只是需要一点时间来打通。
我相信,对于复杂的问题,通过图来解决一定是最佳的方案。
我试图用图来表达ADBS的创建依赖和过程,发现这的确是一个有点麻烦的东西。我写了10个点,仍然只是一小部分。所以我觉得甚至可以再切分成更小的子图。每个子图应该不超过10个点。
Add03 DataQuanlity 数据质量探查 - Done
针对数据源可能出现的质量问题,制定简单的标准,至少先能有个预警。
在我的场景中,如果是整条记录丢失,问题倒还不大。特别怕有一个字段丢了,或者为0,或者单位乱了,这种是比较可怕的。虽然目前似乎还好,但是要预防这种情况出现。
标准:
- 1 检查缺失
- 2 检查0
- 3 检查量级差:10,100两种
Add04 SMS 短信通知 - Done
既然通知不可避免,就要做一个相对简洁一点的方法来发送短信。
将一个短信对象存在redis中,这个倒不必依赖mongo。
约定什么是事件和冷却时间,最终是按照事件来发送短信的,所以限制也是按照事件来限制。
模式:
- 1 当收到某个短信发送动作时,去检查redis缓存对象( ttl=86400)
- 2 如果缓存对象不存在,那么发送信息,【更新短信主体的事件字典以及发送时时间戳】
- 3 如果缓存对象存在,才进一步判断事件,如果事件不存在,那么【更新短信主体的事件字典以及发送时时间戳】
- 4 如果缓存对象存在,那么判断当前时间和上一次的时间,是否满足冷却时间要求,如果是,那么【更新短信主体的事件字典以及发送时时间戳】,如果不是,仅做一个简单的运行时提示
这个模式相对简单,我打算用图来进行一下描述,逐步的将图融入到程序设计中。
4 收获、问题与总结
首先重复这么一个过程是正确的,因为中间的过程环节点太多了。我甚至发现了一块丢失的代码,最后也没法补回。
然后从头到尾,进行实现的同时记录日志,在下一次重复的时候可以做的很快。过程中我发现第一次的确做的非常粗糙,一如既往。所以接下来需要继续重复,提炼。
发现的问题反而是业务层面的,我发现新标的的袋外表现明显弱了,不知道是什么问题。既有可能是数据问题(规模过小),也可能是模型问题(但是我做了结构退化,也没改善),当然也有可能是标的本身的问题。
总结:
- 1 迅速再横向的扩大标的实验范围,规模大优先
- 2 按照这次的操作日志迅速重复操作,提炼(按我的性格,肯定会再优化)