将架构的层数从5减少到2


在从事多个开源项目时,有一天,我决定简化生活,并为nginx开发了Upstream模块,该模块帮助我删除了多层体系结构的庞大层。 我想在这篇文章中分享一次有趣的经历。 我的代码可在此处公开获得: github.com/tarantool/nginx_upstream_module 。 您可以从头开始拾取它,也可以从以下链接下载Docker映像: hub.docker.com/r/tarantool/tarantool-nginx

在议程上:

  • 介绍和理论。
  • 如何使用这些技术。
  • 性能等级。
  • 有用的链接。

导论与理论




这就是标准微服务架构的样子。 用户请求通过nginx到达应用程序服务器。 用户与之交互的服务器上存在业务逻辑。

应用程序服务器不存储对象的状态,因此需要将它们存储在其他位置。 您可以为此使用数据库。 并且不要忘记缓存,缓存将减少延迟并提供更快的内容交付。

将其分为几层:

第一层 -Nginx
第二层 -应用服务器。
第三层 -缓存。
第四层 -数据库代理。 该代理对于确保容错并保持与数据库的恒定连接是必需的。
第五层是数据库服务器。

考虑这些层,我想出了如何排除其中的一些层。 怎么了 原因有很多。 我喜欢简单易懂的东西; 我不喜欢在生产中支持大量不同的系统; 最后但并非最不重要的一点是,层数越少,故障点越少。 结果,我在nginx下制作了Tarantool Upstream模块,这有助于将层数减少到两层。



Tarantool如何帮助减少层数? 第一层是nginx,第二,第三和第五层代替Tarantool。 第四层,即数据库代理,现在位于nginx中。 诀窍在于,Tarantool是数据库,缓存和应用程序服务器三合一。 我的上游模块将nginx和Tarantool彼此连接,并使它们能够无缝工作而无需其他三层。



这就是新的微服务的外观。 用户使用Tarantool上游模块向nginx中的REST或JSON RPC发送请求。 该模块可以直接连接到Tarantool,或者可以在多台Tarantool服务器上平衡负载。 在nginx和Tarantool之间,我们使用基于MSGPack的高效协议。 您将在本文中找到更多信息。

您也可以通过以下链接下载Tarantool和nginx模块。 但我建议您通过发行版的软件包管理器或使用Docker映像( docker pull tarantool/tarantool-nginx )安装它们。

Docker映像: hub.docker.com/r/tarantool/tarantool

Tarantool NginX上游模块

二进制软件包: Tarantool-下载

源代码: Tarantool

tarantool / nginx_upstream_module

如何使用这些技术


这是一个示例nginx.conf文件。 如您所见,这是常规的上游nginx。 这里我们有tnt_pass ,它直接tnt_pass nginx放置上游tarantool的路径。

nginx-tnt.conf
 http { # upstream upstream tnt { server 127.0.0.1:3301; keepalive 1000; } server { listen 8081; # gateway location /api/do { tnt_pass_http_request parse_args; tnt_pass tnt; } } } 

以下是文档的链接:

nginx.org/en/docs/http/ngx_http_upstream_module.html
github.com/tarantool/nginx_upstream_module/blob/master/README.md

配置了一堆Nginx和Tarantool,那又如何呢? 现在我们需要为我们的服务注册一个处理程序函数并将其放置在文件中。 我把它放在“ app.lua”文件中。

这是Tarantool文档的链接: tarantool.io/en/doc/1.9/book/box/data_model/#index

 -- Bootstrap Tarantool box.cfg { listen='*:3301' } -- Grants box.once('grants', function() box.schema.user.grant('guest', 'read,write,execute', 'universe') end) -- Global variable hello_str = 'Hello' -- function function api(http_request) local str = hello_str if http_request.method == 'GET' then str = 'Goodbye' end return 'first', 2, { str .. 'world!' }, http_request.args end 

现在考虑使用Lua代码。

我们的Box.cfg {}告诉Tarantool开始监听端口3301,但是它可以接受其他参数。

Box.once告诉Tarantool调用一次函数。

function api ()是我即将调用的函数。 它以HTTP请求作为第一个参数,并返回一个值数组。

我将此代码保存到文件中,并将其命名为“ app.lua”。 您只需启动Tarantool应用程序即可执行它。

$> tarantool app.lua

我们使用GET请求调用函数。 我为此使用“ wget”。 默认情况下,“ wget”将响应保存到文件中。 为了从文件中读取数据,我使用“ cat”。

 $ wget '0.0.0.0:8081/api/do?arg_1=1&arg_2=2' $ cat do* { “id”:0, # — unique identifier of the request “result”: [ # — is what our Tarantool function returns [“first”], [2], [{ “request”:{“arg_2”:”2",”arg_1":”1"} “1”:”Goodbye world!” }] ]} 

性能等级


评估是根据生产数据进行的。 输入是一个大的JSON对象。 这种物体的平均大小为2 Kb。 单服务器,4核CPU,90 GB RAM,OS Ubuntu 14.04.1 LTS。

对于此测试,我们仅使用一个nginx worker。 该工作程序是具有简单ROUND-ROBIN算法的平衡器。 它平衡了两个Tarantool节点之间的负载。 使用分片来缩放负载。

这些图显示了每秒的读取次数。 上方的图表显示了延迟(以毫秒为单位)。



这些图显示了每秒的写入操作数。 上方的图表显示了延迟(以毫秒为单位)



令人印象深刻!

在下一篇文章中,我将详细讨论REST和JSON RPC。

文章的英文版: hackernoon.com/shrink-the-number-of-tiers-in-a-multitier-architecture-from-5-to-2-c59b7bf46c86

Source: https://habr.com/ru/post/zh-CN417829/


All Articles