搜索的Lua之旅

简介:

一、上路

SP(Search Planner) 作为搜索入口,其对高并发,低延时的性能的要求决定了动态型语言很难满足要求,所以从设计起,就决定使用C++/C语言去实现。使用C++/C优点很明显,性能优秀,表达能力极其强大,唯一的限制只有程序员的能力,但是,世界上的事情大致如此:过于厉害的事物,一般都不易驾驭,开发效率低,发布过程周期长,这一定程度上制约了SP的业务发展,那么问题来了,怎么在不牺牲性能的前提下,提高SP的开发效率,同时让SP具备快速上线,最好热部署的功能呢?

二、旅途


我们首先想到是用脚本去替代现在使用C++实现的业务逻辑,通过对SP的现有架构环境分析来看,对这个脚本定位是,首先功能上要求不会太高,但是必须方便与C/C++集成。SP的核心功能仍用C++等语言编写,但为了满足各种功能组合,需要的是一个比C++这种语言简单的,轻量级的,容易学习和使用的,性能又不错的语言。 最好是业界有大量产品使用,得到了实际验证。Lua就是这样的一门语言。

Lua语言特性:
* 可以很方便的和用C/C++编写的逻辑互相调用
* 麻雀虽小但五脏俱全,可以支持很多高级语言才有的特性,比如gc
* 学习成本低,基本上,懂点编程都知道怎么编写Lua
* 性能好, 消耗的计算机资源不多

在定下加脚本呢语言后,我们开始考虑架构问题了,是重构?还是架在现有架构下,扩展脚本特性?重构的成本代价很高,而且重构后,未必会对现有的SP架构有更好的益处,另一方面,重构为以Lua为主角的架构,对未来应用的扩展性也带来潜在的限制和挑战。更何况,现有的SP架构,是基于Processor Chain的链式处理结构,这种设计本身就非常灵活,并且可很好的扩展。

于是,我们脑海有这样的思路,整个环境还是现有的C/C++,当请求过来,会经过一条长长的处理链路,链路上每个节点代表一个业务的处理逻辑,这个处理节点可以是一个引擎的访问,也可以是一个数据包的解压缩,当如果这个节点是通过Lua脚本来实现的话,那就加载一个Lua虚拟机来去运行。运行完后,继续处理下一个节点。

好了,思路大体确认下来了,我们开始深入一些细节问题,看看这个玩意到底可不可以无缝地集成到SP呢?那么,首先我们需要理清SP是一个怎样的运行环境,SP是一个典型的多线程执行环境,通俗讲就是,一个请求一个线程,一个线程一条执行链路。所以我们希望这个Lua虚拟机能够穿梭在不同线程之间,在这个多线程环境生存下来,然而,很不幸,随着对Lua的深入研究,我们发现Lua虚拟机是不能同时被多个线程同时访问!它是线程非安全的!OMG!!那它是怎么做到并发呢!协程!这又是什么玩意!学过Go或者Erlang的同学应该对这个概念不陌生,协程,好东西呀。。。

“BUT!!!你要我们将目前的多线程环境改为协程!臣妾做不到呀!!!宝宝心里很苦!宝宝 。。。选择退而求其次,既然做不到同时访问,那么串行访问。。。”

“啪啪啪!老子给你300个线程,你TMD告诉我这个300个线程要排队执行!!!”

“那。。。一个线程一个Lua虚拟机”

“啪啪啪!一条链路10个Lua处理节点,300个线程!就是10*300=3000个虚拟机,你TMD告诉我一个SP要用3000个虚拟机!你咋不上天啊!啊!啊!”

不用串行,又不想那么多虚拟机,那就是池子(pool)。怎么设计这个池子,首先,我们对这个池子有两个基本动作,从池子快速取出(take)一个虚拟机,用完了,我们还需要归还这个虚拟机,迅速放回(put)这个池子里,这两个动作能不阻塞最好不要阻塞,其次,我们需要能随时控制池子大小,如果访问频繁的话,能加大池子容量,如果访问低谷,能缩减容量(销毁池子里的一些虚拟机),我们开始搜寻什么样的数据结构满足这样的要求。Java的Concurrent包(java.util.concurrent)是个好东西呀,包里面的数据结构的设计非常精良,值得借鉴,其实,LinkedBlockingQueue就是这样数据结构,我们最后参考了这个设计,用C++实现了一版(稍微做了改动,我们采用环式的队列模型)。

好,有Lua 虚拟机池,解决了内存和性能问题,我们再深入一点,我们希望Lua和C++能协同工作起来,他们之间的一些东西希望能共享,并且统一管理,但是,Lua有自己的变量和内存管理,而且Lua对内部自己的对象是有GC(Garbage Collect)的,是可以自动回收,但是C++不同,和绝大部分的基于虚拟机的语言或者脚本语言不同,在C++里new出的对象,是需要程序员自己管理,需要跟踪它的整个生命周期,试想一下,这样new出的对象如果传给Lua,然后在某一刻被Lua自动回收(你完全不知道它什么时候被回收),但是在C++环境又在引用它,访问已被销毁的对象!Bang!!!

有什么可以解决呢?引用计数!我们在C++和Lua之间建立一套简易的跨环境GC,基本原理是,当new出一个对象,同时初始化这个对象的引用计数,如果这个对象被赋予一个局部变量时候,而不管这个变量是C++局部变量,还是Lua的local变量,引用计数自增1,当局部变量跳出scope时候,引用计数自减1,只有当引用计数为0,也就是没有变量再引用这个对象时候,对象才会销毁。这种设计简单,性能也最好,不过这个有存在交叉引用问题,要求程序员对类的设计不要存在交叉引用,缓解此类问题,可以引入弱引用的概念,只是增加了设计的复杂性,但要根本解决这个问题,需要引入类似Jdk的gc机制,非常复杂,很幸运的是,引用计数对于SP已经足够了。

好,既然业务用Lua脚本实现,开发效率提高了,那我们能不能更激进一点,让Lua脚本的部署更加快速,最好做到热替换!!对,你没听错,热替换!换句话说,有什么办法可以直接将更新的脚本推送到200多台SP机器,并且告知它们“脚本有更新,请重新加载”。稍微想一下,就能得出这样的一个结论,我们需要一个推送平台,它能够和SP保持长链接,并且能够把更新消息实时推送过去。Bingo!Diamond!!

三、终点

我们把想法画成图,就是这样



Lua代码存在Diamond上,每个Lua文件代表一个处理逻辑,App.lua表示总控逻辑的代码,QP.lua 表示处理QP请求的Lua代码等等,当这些代码有变更,SP的Diamond工作线程会监听到这个变更,并开始初始化Lua虚拟机并新建一个代表该Lua代码的虚拟机池,跟这个Lua代码有关的新请求都将从这个池取出,旧的池子将被标记为待清除,虚拟机池的Lua虚拟机按需创建,并通过一个环形的链式串联起来,不同虚拟机池又通过一个大的链路串联起来,组成一个更大的池子,这个大池子由专门的一个线程来管理,它会负责跟踪大池子里面的每个虚拟机池的运行情况而动态调节池里的虚拟机数量,同时销毁掉被标记为待清除的池子。

当请求过来,分配一个请求工作线程(Request Worker Thread),线程会流经Processor链路,如果链路上某个Processor是被注册为Lua,则从虚拟机池取出相应的一个Lua VM,运行完后,放回池里。

其实,除了上面的processor节点可以用lua写,processor节点与节点的拓扑逻辑也是通过lua来生成的,这么说,除了一些CPU密集的计算仍保留C++,只要你脑洞够大,可脚本化的地方可以无处不在。再结合diamond的推送,一个可热替换、无需重启、灵活的脚本化的SP就这么诞生了。

 

目录
相关文章
|
数据可视化 图形学 UED
3dMax2023序列号密钥激活补丁
3D Max 2023已经正式发布了,由Autodesk公司开发的一款专业高效的三维制作软件,集三维建模、动画和渲染三大功能于一体,目前广泛应用于工业设计、建筑设计、三维动画、广告、影视、多媒体制作、游戏、辅助教学以及工程可视化等领域。我还是比较习惯用2023的版本。Autodesk 3ds Max 2023激活补丁分享!
9681 0
|
缓存 NoSQL Java
Spring Boot项目中热点场景详解(万字总结)
Spring Boot项目中热点场景详解(万字总结)
|
人工智能 Cloud Native 前端开发
Bolt.diy 测评:从零部署到创意实践的全流程体验
本文详细介绍了阿里云解决方案中的Bolt.diy工具,一款基于AI的开源全栈开发平台。通过自动部署方式,用户可快速体验其多模型适配、全栈开发等功能。文章涵盖从开通服务到部署应用的具体步骤,并结合实际案例展示了生成网页的效果与局限性。尽管Bolt.diy能显著提升建站效率,但在复杂需求处理和稳定性上仍有改进空间。建议优化代码生成实时查看、预览异常处理等问题,并增加更多学习资源以帮助用户更好地设计Prompt。
1229 43
|
编解码 Cloud Native 算法
通义万相:视觉生成大模型再进化
通义万相是阿里云推出的视觉生成大模型,涵盖图像和视频生成。其2.0版本在文生图和文生视频方面进行了重大升级,采用Diffusion Transformer架构,提升了模型的灵活性和可控性。通过高质量美学标准和多语言支持,大幅增强了画面表现力。此外,视频生成方面引入高压缩比VAE、1080P长视频生成及多样化艺术风格支持,实现了更丰富的创意表达。未来,通义万相将继续探索视觉领域的规模化和泛化,打造更加通用的视觉生成大模型。
|
9月前
|
人工智能 开发框架 Java
Java+AI 的终极结合!JBoltAI 框架助力企业快速落地 AI 应用
JBoltAI是专为Java技术栈打造的企业级AI应用开发框架,破解传统系统接入AI成本高、周期长、稳定性差等难题。深度融合主流大模型与向量数据库,提供脚手架代码、场景案例、系统课程与专属支持,助力Java团队快速实现AI转型,让AI应用开发更高效、更稳定、更易落地。(238字)
397 0
|
人工智能 搜索推荐 测试技术
人们如何使用ChatGPT
OpenAI发布《人们如何使用ChatGPT》论文,揭示截至2025年7月,周活用户超7亿,70%对话为非工作用途。三大主要场景为实用指导、信息查询与写作,其中写作是工作核心,占工作相关消息42%。用户互动以“询问”为主,占比49%,增长最快且满意度高。年轻用户(18-25岁)贡献近半消息,性别差距已缩小,女性用户过半。低收入国家增速快,高学历者更用于工作。编程仅占4.2%,情感类交流占1.9%。报告指出,ChatGPT正从生产力工具转向日常生活助手,创造广泛社会价值。
846 2
|
SQL Oracle 关系型数据库
各种JOIN的区别
各种JOIN的区别
1287 2
|
监控 负载均衡 安全
Elasticsearch 集群某一节点修改 IP 后无法启动问题复盘
Elasticsearch 集群某一节点修改 IP 后无法启动问题复盘
|
存储 缓存 算法
go vendor module
go vendor module
|
Java Linux Docker
CentOS7 Docker 安装,配置国内镜像
CentOS7 Docker 安装,配置国内镜像
3515 2

热门文章

最新文章