转载:http://mp.weixin.qq.com/s?__biz=MzI2MDAyOTIyNA==&mid=400642479&idx=1&sn=157c008bdb0290286d5b85cdbf0bed3f&scene=2&srcid=1120jdwydiuq6PBssAsVW2ts&from=timeline&isappinstalled=0#wechat_redirect
根据春哥现场视频整理,如有错漏,属于笔者问题,和演讲者无关。最后10分钟没有整理成文字,请大家期待下周的视频完整版本。
看了两天的视频,一个字一个字打出来的,深感这个演讲分量很重,值得大家细细体会。
内容相当多,大家慢慢看...
------------
大家好,我叫章亦春,我喜欢用agentzh这个名字,我很讨厌别人把我这个首字母a大写,我觉得特别丑,所以大家千万不要大写,这是雷区。
今天主要想和大家分享下or的过去,现在和未来。如果我在其他的it交流会议上面重点介绍我做了什么,或者正在做什么,那么在or这个我们自己的会上面,我就可以放心大胆的说我们将要做什么。
其实最初我只是想自己搭一个个人博客,我不想用wordpress,也不想用其他现成的技术,我想自己用一个轻量级的技术做出来。所以最初只是一个非常单纯的想法。
我的第一份工作是在yahoo中国的搜索部门,我当时有很多很碎的业务,比如搜索结果的相关推荐,或者垂直搜索,还有下拉列表的自动提示,很多这种很碎的功能在搜索部门。于是我们老大让我写一个通用的平台,可以方便的构造这样的接口,给前前端来展现。这些接口可能是吐json这种很简单的API。那个年代,API的概念还是方兴未艾,顺应这个潮流,做了第一版的or,是由我当时最喜欢的脚本语言perl写的。花了很大的精力去优化,因为当时在yahoo使用的生成机器是爬虫淘汰下来的机器,就是连爬虫都觉得很慢的机器,拿给我们跑业务跑生产,所以在用Perl做这种访问量很大的接口时候,很难进行优化。当然我也不断去把越来越多的or功能用c去实现,但是还是很难达到让人眼前一亮的性能要求。所以现实是非常残酷的。
我在yahoo有一个同事,叫chaoslawful,大名叫王晓哲,我很有幸拜他为师,学了很多系统编程方面的东西,因为他是一个很了不起的人,也是一个自学成才的工程师。
在09年的时候,就一直有一个想法,把之前用perl的or进行重写,然后达到一个很高的性能要求。在09年的时候,我和晓哲转到了淘宝,当时加入了量子统计这个数据平台部门,做量子统计这个产品,给卖家提供流量统计、销售统计、广告效果报表的数据分析产品。现在这个产品已经不存在了,是很多年前淘宝的一个产品。它有很复杂的业务逻辑,对性能也有比较高的要求,同时后台的数据量是很恐怖的,淘宝大部分商家的数据都会在这里展现,进行各种维度和搜索的分析。当时,我就想,我既要把or重写了,得到很高效的框架,同时也要和部门的同事一起,把量子统计在这个平台上面构建出来。所以很难得有这个机会,同时也是非常大的一个挑战。我希望在这里尝试一些从未尝试过的、新奇的玩法。所以大家现在看到的or,其实就是在那段时间完成的,09年到2011年,我在淘宝的时间中。同时把量子统计这个web应用进行了非常高效的实现,相比之前PHP实现的老版本,代码量减少了90%,性能提升了一个数量级,包括延时,包括并发。我们后台的一个数据库工程师和我说,之前老板点击一个黄钻卖家的报表,离开工位倒杯水回来,报表还在转,新版的话,啪一下就出来了。所以效果还是非常明显的。只用非常少的机器,就能处理非常复杂的数据库相关的查询,因为它数据源很多,所以这里面有复杂的关系型的融合还有分表的逻辑。
那么,大家可能会觉得,lua作为一个非常简单的语言,来表达很复杂的业务系统,可能会很吃力,事实上,我们在构建这个业务系统的时候,并没有写多少lua代码,但确实是由lua来驱动的。技巧就是我经常鼓吹的一种玩法:设计一种针对业务的小语言,或者说DSL。这个应用背后的数据平台,就是用我自己设计的一种类似关系型的语言来表达的,然后我自己实现的编译器,处理这种业务描述,生成高度优化的lua代码。lua代码生成之后,你会觉得人类是很难写出来的,因为有很多优化,是人很难做对的。对查询的拆分,对查询的优化,所以我又在里面实现了一个中间件,但代码很少,所以我等于把lua语言当做虚拟机的机器语言在使用,业务我是用最适合业务模型的一种表达方式来表达的。这块儿我可以讲很多,可以讲一天。这块儿和or配合起来去使用的一个优势就在于,这个平台框架很轻,没有什么乱七八糟的东西,同时lua语言是一种高度动态的语言,我可以根据需要去做一些魔法般的事情,把它做成我的虚拟机的CPU,来进行代码生成会非常的方便,同时效率也会非常非常的高。后面我还会讲到类似的例子。
我觉得很多时候不用纠结到底使用什么编程语言,更多的应该考虑用业务语言来表达我们的业务。比如团队里面产品经理用犀利的语言把业务描述的很精确,那么他写的这个文档, 已经是这个业务系统本身了。我们写个编译机让它跑起来就行了。大家可以去想一想这个思路。
在2012年的时候,我加入了cloudflare。2011年的时候,我在福州,我不是福州人,很多人认为我是福州人,回老家,其实不是,我们只是随便挑选了一个南方城市,去过一种半隐居的生活,有更多的时间专注于开源项目,特别是or。现在大家看到的很多高级功能,都是在那段时间完成的。在2012年,福州田园生活过了一年之后,就加入了美国的cloudflare公司,这是一个cdn公司。所以我之前在搜索行业、在数据分析行业混了几年,然后到了cdn行业。机缘巧合,这家公司希望用or来构建他们的基础设置。我觉得去美国过类似的田园生活也不错。但我没想到的是or在cdn行业获取了很大的成功,有很多的公司会去使用。这也是我最初没有想到的,我最初想的是web应用,对富客户端或者移动客户端的API,使用or构建是非常合适的。大家之前看到的web引用,其实也是由这些API驱动的,大量使用了ajax这样的技术,像模板渲染、用户交互的控制流逻辑实现都是在浏览器里面完成的,这是一个胖客户端,当时花了很多精力去搞IE6,所以又写了很多javascript,还是很辛苦的。
最开始我们考虑把lua嵌入到nginx当中,也是在淘宝的时候,晓哲老师给我建议了这样一个技术方案,我觉得靠谱。我最早的改写方案是基于apache去写c module,但是apache的代码看得我有些云里雾里,所以在晓哲老师的建议下,开始把工作重心放在nginx上面。这时候可能知道nginx的同学也不是很多。nginx的请求有多个不同的处理阶段,在不同的阶段,我们可以插入一些lua代码,插入自己的逻辑,进行一些控制或者事件记录。当然最常用的就是content_by_lua,这个是用or做完整外围应用的一种玩法,刚才很多同学已经演示了,可能对于cdn,对于动态均衡器来说,他就不会用content_by_lua,而是用nginx自己的proxy_pass这样的反向代理模块,而且会去使用access_by_lua和rewrite_by_lua这样一些在更早阶段执行的hook去加入自己的一些逻辑。我开始的时候写了一些resty的lua库,可以在lua层面做一些代码的复用。然后社区的热心用户贡献了很多resty库,特别是今天上午演讲的Aapo同学,贡献了非常多的resty库,这些都是让我很振奋的事情。在做这些库的时候,我有一个愿望,就是他们都是相对独立的,尽量之间不要有相互依赖,这样可以确保一个清晰的结果,lua的优点就在于他的简洁明快。
刚才提到三个应用场景,API Server,还有HTTP Proxy,这个在CDN行业用的比较多。Web Application,这个相对少一些。这个和nginx本身的使用方式有关。有些同学可能没法接受把nginx本身作为Web Application的容器或者server,但这是我的初衷。
在发展的过程中,or秉持的是兼容并包的思想,我们并不排他。出于nginx在整个web stack中位置的特殊性,我们可以很方便的和现有的技术进行融合,比如PHP、Python、go、nodejs,我们在网关这个层面,所以我们可以同时和其他后端应用并存,虽然我还是更倾向于更纯净的方案,但事实上,在or社区里面,我们的用户来自各个社区,Ruby、Python甚至java,所以我很高兴看到不同语言社区的同学,把他们自己社区的文化,一些看待问题考虑问题的方法,能够带到我们社区里面来,扩展我们的思路。我们也鼓励各种混合的使用方法,至少对于现存的系统来说,我们的迁移可以一块一块的进行,当然用户认证的这个逻辑需要优先迁移到nginx这个层面。这种玩法也是我最初没有想到的。我最初用nginx,是看中它http、io事件处理模型这块的实现,大家最最最为经典的用法是把nginx最为前面的网关,后面用fcgi去连API server,或者proxy_pass去做反向代理。那么在这种结构下,or更有机会去做更多的事情,融合现有更多的业务。
我自己也用过这种技巧,在量子的时候,有一个实时统计的引擎,有很复杂的线路协议,当时我在做业务迁移的时候,因为很严格的上线的时间点,所以没有时间去完成一个非阻塞性能很高的实时引擎客户端,所以我简单的用Perl实现了一个客户端,虽然我很仔细的实现了,但其实不行,扛不住,成为整个系统的瓶颈。在上线之后,有了更多时间之后,我写了一个纯c的nginx module,来进行非阻塞通信。刚才我讲用perl,用c,其实并不是我直接用perl,用c去实现,而是用了一个写程序的程序的技术。这个实时数据库的维护者,也是我的同事,他维护了一篇非常漂亮的文档,用来详细讲解线路协议的每一个主要方面。我一看到这个文档,我灵机一动,这个文档就是我的客户端的实现。我写了一个Perl脚本去自动分析这个文档,把里面的数据,里面的结构,全部抽出来,变成一个数据结构,自动生成Perl实现,自动生成c的实现。事实上,我还让它自动生成了测试集,测试也可以自动生成。在这个过程中,我发现他文档中的一些笔误,因为毕竟是人写的,而我的分析器尝试把它当做程序来运行的时候,就会发现很多细节问题。所以文档真的很重要,重要到你可以用文档来生成任何东西,包括实现,包括测试,中文的,英文的,葡萄牙文的各种人类的文档都可以。这是一种很有意思的思路。这也使得你的业务和具体实现无关,在任何一天,你都可以换掉下面的实现,而不用动上面的实现代码。像刚才我举的那个例子,我可以很惬意的把Perl实现换成c实现,其实我只是写了一个模板。前段工程师可能很熟悉这种模板的技术,我们一般会使用模板来生成HTML和CSS,但是你有没有想过,我们可以用模板生成任何东西,包括你的程序本身,为什么不呢?所以我使用写程序的程序的技术的时候,我恰恰是用了那种通常是生成HTML的模板引擎,当然更复杂的代码生成器,还是需要专门的代码生成器技术。这个说远了,我的意思是说,这种兼容并包的哲学,可以打开我们的思路,我们不必局限于lua这个语言,nginx这个东西,其实我们只是根据需要,把很多我们需要的块拼接起来,而并没有任何的排他或者任何宗教信仰式的极端主义的倾向。
在设计整个or的过程中,我们还是有几个比较清晰的目标。第一个目标首先是简单,simple。这也是我为什么不喜欢很多java框架的原因,就是一定要简单,不需要的东西一定不能存在。然后要小巧,这点我也是很执着的一个事情,我算是半个ops,运维人员的背景出身,所以我希望我在机器上面跑的程序能够小巧,以至于能够完全控制整个代码机,在出问题的时候,可以自己去分析,自己去追踪,乃至自己去修复,而不管出问题的组件处于软件系统的哪个位置,所以这个有点偏执,但是这样可以让我晚上睡个好觉,因为我不再惧怕任何诡异问题,因为本来也就没有什么诡异问题。第三个就是要快,这是我在yahoo和淘宝工作的最直接的感触。后来到了cloudflare也是类似的情况,其实现在的互联网环境变得如此的拥挤,就是看上去很不起眼的东西,往往就能吸引到很多流量,有很高的性能要求,而给我们的机器,通常不尽如人意,yahoo当时爬虫淘汰下来的机器是一个极端例子,但也能说明问题,所以要快。如果一个程序跑的还不如我收工干活来的要快,那么为什么还要写程序呢?最后一个目标是一定要灵活。这也是我非常看重脚本语言的一个方面,静态语言有很多优点,但是我希望在做业务的时候,我的手是足够灵活的,可以做任何我想做的事情,而不会受到很多不必要的束缚。这一点,在座的脚本程序员都会深有体会。有时候,我并不希望实现语言给我太多的限制。
那么,很重要的一点,就是要实用主义。我们并不追求很花哨的学院派的概念,虽然作为业务爱好还是很有裨益的,但是对于工程的实践来说,实用主义应该是放在第一位的。首先要把活干了,也得得到一个足够高效、足够健壮、足够优美的一个系统。优美是最高境界。那么or就是实用主义的产物。我希望我们继续贯彻这个方针,保持实用主义者的称号。
还有一个很重要的,就是开源工作者很看重的:有趣。我们假设开源是一个编译器,它有优化选项,-Ofun,我们是针对乐趣进行优化。这一点看上去是和实用主义原则冲突,其实不然。因为对于一个工程师来说,最有意思的莫过于自己的技术,自己搭建的系统,自己设计的方案,能够在线上跑的非常好,能够服务越来越多的用户,这是非常大的一个乐趣。对开源工作者来讲,他也希望自己的代码能够跑在尽可能多的公司的服务器上,能够收到尽可能多的用户的感谢信。这个你想,在一天干活最痛苦的时候,突然收到一封来自世界另一个角落的用户的感谢信,字里行间洋溢着一种感激,一种欣喜,那你这一天立马就会变得非常美好。所以,要让乐趣变成我们工作的主旋律,而不要让工作变成一种负担。这也是我在做or的时候,希望我自己,以及每一位参与开发或者普通使用的用户,都能去做到的一件事情。我们会看到在一些社区里面,很容易产生一种愤怒,比如说有某个用户问了一个很小白的问题,或者出言不逊,诸如此类的,很容易让人变得毛躁起来。我希望这种消极情绪能够尽量的消极乃至没有,因为我还是希望世界能多一些美好,多一些正面的积极的情绪,对我们每个人也会更好一些。
那么我们有一个正在不断成长的社区,我每天花费你们没法想象的时间,去处理用户的邮件和补丁,有新特性,有bugfix。会用各种语言去写,有时候会忘了正在用什么语言,可能前半截用的中文,后半截用的英文,有时候也会出现混乱的情况。360的几位哥们儿,温铭、院生、艾菲他们也自己开了一个qq群,我不在那个群里面,因为我很久不用qq了。然后github上面也会有很多issue和pull request,当然一般的讨论还是希望能够在邮件列表里面,这样可以方便通过搜索引擎进行检索。那么现在我们还有了会议,让原本只知道web ID的朋友,能够看到真人,很多朋友只认识他们的github ID,或者email里面的nick,而不知道他们长什么样子。其实很多人和我想像多年的样子完全不一样,都是很正常的,还好没有性别和我想像的不一样。
我很希望去写一本书,那么360的温铭他们的团队已经开始写一本叫做《OpenResty最佳实践》的书,我自己脑袋里面也会有一些想法,我们可能会合作去合著一本书,这都是可以去讨论的。我脑袋里面那本书叫《programming OpenResty》,希望能够把我这么多年来,做or的一些感悟和心得,能够写下来。这样也省的我在邮件里面,翻来覆去的重复一些很基本的东西,也能让更多的人受益。
包管理一直是社区里面呼声很高的一个功能。我也希望or官方提供包管理这样的东西,我们可以很方便的上传、分享、安装自己或者他人的lua resty模块,lua库,或者基于or的应用程序和工具,都可以通过这个统一的工具链。大家熟悉的比如说,nodejs的NPM,Perl的CPAN,ptyhon的PIP, Ruby的gems,有很多现有包管理工具,我们可以去参考。我们设计还没有定型,我只是给大家看下我脑海里面很粗糙的想法。这个名字不太好起,我跟温铭,跟院生他们商量,我觉得目前最好的名字是iresty,但还是稍微有点儿长,像PIP、NPM都是三个字母。iresty.org这个网站,我们可以检索所有lua resty的库,或者driver,比如需要ZooKeeper、MongoDB这样的客户端库的时候,就可以先在这个网站上进行搜索。没有的话,或者没有合适的话,你可以去着手开发,这样可以避免重复劳动,也可以鼓励大家的协同。
命令行工具也会叫iresty,如果大家有更好的想法, 可以在邮件列表或者qq群,告诉我们。现在是一个雏形的想法。我们可以去 install 一个库,可以删除卸载这个模块。我比较坚持的一点是,模块名字前面要求加上github ID,这样可以避免其他社区包管理里面常见的一种抢坑的问题,就是我这个东西还没做出来,我先抢这个坑,别人就不能注册这个名字了。我希望像github一样,鼓励大家不在名字空间上面去争夺,像guthub一样鼓励大家去fork,去自己定制,但是还是希望尽量去协作,但我不希望协作是强制的。也可以去search,这些基本功能是需要的。
我还希望有一个命令行的文档,可以看到标准模块和安装模块的格式化的文档。这样省的我们在网上搜索,那也挺费事的。在终端里面可以看到,这比较符合我们UNIX程序员的习惯。当然不仅能查看库的文档,模块的文档,还可以查看nginx lua或者nginx里面某个配置指令的文档,我也希望能做到这一点,这样所有的文档查找都能通过一个命令行工具来进行,甚至你终端支持颜色的话,显示出来的文档是彩色的。
resty这个工具已经实现了有一段时间,可能有些同学还不知道。这是一个很简单的or命令行,你可以用-e选项去执行一行代码,你可以使用几乎所有的or里面暴露的标准API,你也可以指定一个文件,用or实现一些命令行的工具。我们注意到这个工具也可以用于一些在线的分析,比如说同一份业务代码,即可以作为服务跑在nginx里面,同时也可以在命令行里面,供运维人员去快速检查一些当前生产数据的状态,所以这也会非常有用。还有同学会用这个工具做单元测试,因为本质上这个resty工具,自己启动了一个没有脑袋的nginx,这个nginx不会监听任何东西,只是一股脑的从头执行到尾,然后退出。
我们刚才说到irsety包管理工具,会同时支持lua库和or应用,我希望有更多的or应用可以通过iresty install 就可以装上,就可以运行。
我们可能会对LuaRocks有限性的兼容支持,而且我个人对LuaRocks不是特别的喜欢。所以我希望or有自己的包管理系统。同时标准Lua世界的库,由于各种原因,没有考虑or的阻塞和非阻塞的问题,它没有使用or提供底层的原语接口,比如说socket接口,所以这些库通常会阻塞nginx的事件循环,造成并发的严重下降。
还会有更多官方的二进制发布包。比如说我们现在正在做的windows的二进制发布包,里面有一个32位的windows版本,刚才360的同学们也讲到,他们维护了一个windows的分支。现在计划是把他们的优化工作,融合到官方的windows版本中来。我现在这个是非常简单的,并不适合做生产,只适合在windows上面做开发,有人有这样的需求,虽然他们最后的生产环境是Linux或者BSD。 我现在的windows版本是用MinGW GCC来编译的,我希望最终使用微软的工具链来编译,以获得最好的性能,和最少的依赖项。还会有主流的Linux发行版本的仓库,这样大家升级是apt-get update一下。这些工作都是近期会重点做的事情。我还希望iresty.org网站上传的lua模块和应用,能自动生成二进制各个发行版的安装包,这也是个很cool的feature。
还有一个大家呼声很高的特性,就是让nginx成为一个一般的TCP server,而不仅仅是http server,我们就可以去做更多的事情。那么nginx最新提供的stream子系统就可以做到这一点。我们会有基于这个子系统的lua模块和echo模块。echo模块已经完成开发,大家可以在github上面去查看,lua模块也正在开发过程当中,它会拥有和现有的nginx http modlue相同的lua API,所以你们的很多应用和库,可以不加修改的运行在一个新的子系统上面。
类似的,我们会有UDP server,其实我很想看到的一点,是基于or的DNS name server,我觉得这是一个很有意思的应用。
下一个,模板。上午Aapo老师介绍过他自己写的lua-resty-template,我自己也有我的一些想法,就是lua-resty-tt2(jemplate)。作为一个Perl程序员,我非常热爱Perl里面tt2这个模板语言。它其实跟Perl没有太多关系,Perl社区的一个大神,他写了一个jemplate这个工具,可以把tt2生成为独立的、可以在客户端运行的JavaScript,这就意味着同一份模板,即可以跑在服务端,也可以跑在客户端,这是一个非常有趣的想法。这得益于这个模板语言既不是Perl,也不是lua,也不是JavaScript,而是它自己的一种小语言,足够简单但有足够强大。我曾经用一个脚本语言实现了一个比较完整的x86反汇编器,就是通过这个模板。所以这块也是我想去尝试的官方模板引擎库。当然,如果大家有兴趣,也可以去移植Python里面常见的模板语言到or的场景下,那么Python原有的应用可以更容易的迁移到or,模板文件至少不用动。
大家注意我微博的话,可以看到我很多时间花在Streaming Regex这个正则引擎上面,这是一个从零实现的正则引擎。web世界很难离开正则,因为总会遇到各种文本处理,对于CDN来说尤为如此,因为我们需要对请求进行很复杂的模式匹配,不管是WAF,还是CDN的规则的调度分发,还包括对响应体的一些正则替换,去掉或者删除一些东西,比如把电子邮件地址替换成它对应的图片,这些都需要很强大的正则引擎,支持流式处理,可以分块来进行匹配,这样的引擎是永远不会往后回溯的,我处理一块扔掉一块,再处理下一块,用O(1)的内存来处理任意长度的数据流。这个libsregex还在开发当中,我做了一些尝试和实践,最新的是基于确定性有穷自动机(DFA)来实现的。我觉得这里面有一些算法的创新,我也跟PCRE JIT的作者有过沟通,他也很关注这个项目,很早就主动和我联系,让我有些受宠若惊。所以我很高兴通过这个项目,吸引了一些正则这个领域举足轻重的人物的注意和帮助。他们会问需不需要帮助啊,或者说你的这个算法好有意思啊,你教教我好不好,我们一起讨论一下。这些互动是非常非常宝贵的,这也会打破公司的边界甚至国界,这是开源带给我们的好处和乐趣。我还写了一个nginx的模块,用正则在响应体里面做替换,它现在效率不太好,但是它实现了这个想法,它现在是确定性有穷自动机的算法,所以比较慢,和RE2的一般情况一样慢,我需要像PCRE JIT一样性能级别的引擎。最新的libsregex里面的DFA引擎,在平均情况下可以达到PCRE JIT甚至更高的效率,最坏的情况下,也能和RE2或者比RE2更好。Intel在今年10月份开源了一个做了7年的正则库,叫HyperScan,也是值得去参考的,只不过它的语义和Perl,和PCRE的差别更大一些。但它的优点是至少可以处理上万个正则的流式匹配。
另外lua-resty-pegex也是我想做的一个库,我其实并不想把社区可以做的事情都做完,我只是捡一些我特别想做的库。一旦有了iresty之后,标准库和非标准库的边界已经不是那么清晰了。pegex是Perl里面我非常喜欢的用于语法分析的引擎,可以用于构造编译器,小语言,写程序的程序,我们需要这种分析机构造器去实现小语言的编译器,让计算机认识我们定义的语法,认识我们某个同事写文档的格式或者惯用语,那么让计算机懂得这个文法,我们就需要另一种小语言,来描述这种小语言的语法,那么这些工具就可以把描述变成实现,让计算机能够理解我们想象的语言的语法。语义分析可能会更复杂一些,因为没有这种自动化工具,但实现起来也没有那么复杂。编译原理应该是我计算机专业学习当中,让我受益最大的一门课。在这里领域的很多想法,不仅适用于我们常见的gcc、java这样的全功能的工业级别的编译器,也适用于小巧的,只有几百行、几千行自己实现的小语言的编译器。
基于这种小语言的思路,我希望or可以提供更多的小语言,让大家可以去接受、去摆弄这样的一些想法。我脑海里面的 Edge 语言就是这样一个例子,它是为CDN行业里面典型的业务模型、业务逻辑来设计的,可以很方便的通过基于规则的语法来表示很复杂的过滤规则、分发规则、WAF的防火墙规则,用一种统一的方式来表达我们的意图,而不是去表达一种实现。那么我们的编译器就有机会在更高的层面上进行业务的语义分析,来写很了不起的全局优化。比如说,我们有100个规则,都需要对URI进行正则检查,我们自己实现的优化器,可以把规则里面对URI的模式,合并成一个自动机,这样我们只用对URI扫描一遍,而不是100遍。所以这样就打开了我们优化的可能性。
(这里举了一个例子来说明,大家可以看视频来理解)
我很想看到的一件事情是or有一个官方的WAF平台,现在开源的一些解决方案,至少我觉得可以做的比它更好。包括cloudflare正在线上使用的WAF,我觉得也可以做的更好。我希望最好的WAF应该是开源的,而且是or里面的。对于WAF来说,是一个很经典的DSL的例子,我们使用一种小语言,比如刚才的 Edge 语言,也可以扩展到WAF场景,动作可能是reject、pass、打分,分值达到某个程度之后reject,返回一个403,完成一个capture来进行验证。
我觉得特别有趣的一种玩法是从DSL生成高度优化的Lua代码。这样就可以发挥包括LuaJIT在内的组件的威力,对于JIT编译器来讲,Lua代码分支越少,越简单,越有可能生成最高效的机器指令,同时我们因为使用了编译的方法,我们抽象本身的开销可以在编译期,在上线之前完成。我们最后上线的时候,是生成的非常小巧的lua代码,没有什么运行时开销,也没有什么依赖项。魔法都可以在编译期完成,这是一种脱去抽象本身开销的很好的思路。现在很多web框架,是在运行时进行抽象,那么会导致在线时候,内存和CPU的损耗很大,因为你引入了很多层次,这些开销是运行时的开销。这一点也可能不是上线之前,也可能是在一些特殊的配置端口,比如说CDN的配置界面上面,我们会做编译,通过一些复制的方式,比如KT,推送到全球各个网络的各个节点,我们可以推送lua字节码。在CDN的场景下,等价于于我们为每一个客户,高度定制了一个CDN软件。这样如果你的CDN配置很简单,那么生成的CDN软件就非常简单。
我们社区常常会吸引到其他社区,包括redis社区的邮件,比如redis社区的一个哥们儿就发邮件和我讨论stateful这个概念,这个我也是从他那里听说的。所以有一些很有趣的协议和方法,当然每一种协议都有自己的折中和自己的应用场景。我希望后面or能在这方面多做一些尝试,各个or之间形成更加默契配合的关系。同时能给请求引入状态,这个状态可以在同一机房的不同节点传递,甚至是跨机房,在全球节点之间传递。这些都是可以玩的一些东西,也会有它们各自的应用场景。
semaphore是一个很重要的特性,它可以用于ngx_lua轻量级线程之间的同步,其实就是线程同步里面的信号量。酷狗音乐的同学一直在开发这个功能,已经有一些很不错的成品了。我还在review过程当中,希望能尽快融合进主干,这个可以避免使用sleep的方法进行同步,损耗可以下降非常多。这个×××江同学的分享里面也会提到。
酷狗音乐的×××江同学还实现了基于list的共享内存的类型支持,可以用redis风格的接口对共享内存进行队列操作,这个也会有非常有趣的应用场景。
我自己也很想拿Shm-based databases来练手,在or里面来实现一个内存数据库,没有持久化,或者有限持久化支持的数据库。关系类型的,或者其他类型的,时间序列类型的。
init_by_lua一直不支持cosockets,我希望这个能增加支持。在nginx启动的时候,在外部的tcp或者udp服务里面拿一些数据,这个还是非常有用的。那目前需要在每个worker里面做一些比较恶心的初始化同步工作。
我们需要有更好的cosockets。cosockets仍然像经典的socket同步的使用,但它是非阻塞的,不会阻塞任何操作系统线程。我们有一些内存是分配在nginx的内存池里面,我希望可以避免这种分配,更适用于推送的场景,很多下游长连接保持非常长时间的场景。
UDP或者gram socket需要一个bind()方法,这样我们可以进行双向的服务发现,服务推送之类的东西。
cosockets连接池,我希望能够基于它做一些后端的并发控制,当超过这个连接池容量的时候,可以对connect请求进行排队,而确保后端不会因为并发数太多而损失吞吐量,即使是redis,如果给他并发太高的话,吞吐量也会直线下降。
ngx.connection 这是一个比较新的东西,和cosockets平行。我希望能够提供一个fd,也就是文件描述符,这个fd可能是其他c库实现的,我们可以把fd注册到nginx的事件循环里面,然后可以去同步非阻塞的等待nginx事件循环里面的事件,比如说read、write。这种模式的好处在于我们可以结合luajit的ffi,很方便的整合现有的第三方的支持非阻塞IO的c库,比如postgres的libpq,而不用lua的cosockets去重写这样的库。这个也是能够改变or生态系统的一个特性。幸运的是,这个特性实现起来很简单。而且github上面已经有了一个pull request,叫做wait for fd,有兴趣的同学可以一起参与讨论,一起研究。
balancer_by_lua这个刚刚开源,你可以用lua来定义自己的负载均衡器,可以在每个请求的级别上去定义,当前访问的后端的节点地址、端口,还可以定制很细力度的访问失败之后的重试策略。如果我是重试还是不重试,重试失败后去重试哪个节点,都可以在每个请求的力度上进行lua编程。这对于很多反向代理风格的业务来讲,是一个很重要的特性。
(这里又是一个例子,建议大家看视频)
SSL现在也很热门,大家为了安全起见,都往HTTPS迁移。 ssl_certificate_by_lua 可以让你通过lua严格去控制下游的ssl握手的过程。比如使用什么ssl,使用什么证书,让不让它握手,都可以在这个环节插入自己的代码来完成。比如cloudflare的ssl网关就是利用这个特性来实现的。