Heim > Web-Frontend > js-Tutorial > Hauptteil

Denken und Praktizieren der Front-End- und Back-End-Trennung basierend auf NodeJS (6) Nginx Node.js Java-Software-Stack-Bereitstellung practice_node.js

WBOY
Freigeben: 2016-05-16 16:35:16
Original
2244 Leute haben es durchsucht

Die traditionelle Software-Stack-Struktur von Taobao-Onlineanwendungen ist Nginx Velocity Java, das heißt:

In diesem System leitet Nginx die Anfrage an die Java-Anwendung weiter, die die Transaktion verarbeitet und die Daten dann mithilfe der Velocity-Vorlage auf der endgültigen Seite rendert.

Nach der Einführung von Node.js stehen wir zwangsläufig vor den folgenden Problemen:

Wie sollte die Topologie des Technologie-Stacks gestaltet sein und wie sollte die Bereitstellungsmethode ausgewählt werden, um wissenschaftlich und sinnvoll zu sein? Wie kann der Verkehr nach Abschluss des Projekts so aufgeteilt werden, dass er für Betrieb und Wartung bequem und schnell ist? Wie kann man bei Online-Problemen die Gefahr so ​​schnell wie möglich beseitigen und größere Verluste vermeiden? Wie kann der Zustand der Anwendung sichergestellt und auf der Planungsebene des Lastausgleichs verwaltet werden? Vererbung der Systemtopologie

Nach unserem Denken und unserer Praxis zur Front-End- und Back-End-Trennung (2) - Vorlagenerkundung basierend auf der Front-End- und Back-End-Trennung muss Velocity durch Node.js ersetzt werden, damit diese Struktur entsteht :

Das ist natürlich das ideale Ziel. Allerdings ist die erstmalige Einführung der Node.js-Ebene im traditionellen Stack ein neuer Versuch. Aus Sicherheitsgründen haben wir beschlossen, die neue Technologie nur auf der Artikelsammlungsseite der Favoriten (shoucang.taobao.com/item_collect.htm) zu aktivieren, und andere Seiten werden weiterhin die traditionelle Lösung verwenden. Das heißt, Nginx ermittelt den angeforderten Seitentyp und bestimmt, ob die Anfrage an Node.js oder Java weitergeleitet werden soll. Die endgültige Struktur lautete also:

Einsatzplan

Die obige Struktur scheint kein Problem zu haben, aber tatsächlich warten noch neue Probleme auf uns. In der traditionellen Struktur werden Nginx und Java auf demselben Server bereitgestellt. Nginx lauscht auf Port 80 und kommuniziert mit Java, das auf dem High-Port 7001 lauscht. Nachdem Node.js eingeführt wurde, müssen wir einen neuen Prozess ausführen, der den Port überwacht. Sollten wir Node.js und Nginx Java auf demselben Computer bereitstellen, oder sollten wir Node.js in einem separaten Cluster bereitstellen?
Vergleichen wir die Eigenschaften der beiden Methoden:

Taobao Favorites ist eine Anwendung mit zig Millionen täglichen durchschnittlichen PV, die extrem hohe Anforderungen an die Stabilität stellt (tatsächlich ist die Online-Instabilität eines Produkts inakzeptabel). Wenn Sie dieselbe Cluster-Bereitstellungslösung verwenden, sind nur eine Dateiverteilung und zwei Anwendungsneustarts erforderlich, um die Veröffentlichung abzuschließen. Wenn ein Rollback erforderlich ist, müssen Sie das Basispaket nur einmal ausführen. In Bezug auf die Leistung bietet die Bereitstellung im selben Cluster theoretisch einige Vorteile (obwohl die Switch-Bandbreite und die Latenz des Intranets sehr optimistisch sind). Was die Eins-zu-Viele- oder Viele-zu-Eins-Beziehung betrifft, ist es theoretisch möglich, den Server vollständig auszunutzen. Im Vergleich zu den Stabilitätsanforderungen ist dieser Punkt jedoch nicht so dringend und muss gelöst werden. Daher haben wir uns bei der Transformation der Favoriten für die gleiche Cluster-Bereitstellungslösung entschieden.

Graustufenmodus

Um maximale Stabilität zu gewährleisten, wurde bei dieser Transformation der Velocity-Code nicht direkt vollständig entfernt. Es gibt fast 100 Server im Anwendungscluster. Wir verwenden Server als Granularität, um den Datenverkehr schrittweise einzuführen. Mit anderen Worten: Obwohl Java Node.js-Prozesse auf allen Servern ausgeführt werden, bestimmt die Frage, ob auf Nginx entsprechende Weiterleitungsregeln vorhanden sind, ob Anforderungen für Schatzsammlungen auf diesem Server von Node.js verarbeitet werden. Die Konfiguration von Nginx ist:

location = "/item_collect.htm" {
  proxy_pass http://127.0.0.1:6001; # Node.js 进程监听的端口
}
Nach dem Login kopieren

只有添加了这条 Nginx 规则的服务器,才会让 Node.js 来处理相应请求。通过 Nginx 配置,可以非常方便快捷地进行灰度流量的增加与减少,成本很低。如果遇到问题,可以直接将 Nginx 配置进行回滚,瞬间回到传统技术栈结构,解除险情。

第一次发布时,我们只有两台服务器上启用了这条规则,也就是说大致有不到 2% 的线上流量是走 Node.js 处理的,其余的流量的请求仍然由 Velocity 渲染。以后视情况逐步增加流量,最后在第三周,全部服务器都启用了。至此,生产环境 100% 流量的商品收藏页面都是经 Node.js 渲染出来的(可以查看源代码搜索 Node.js 关键字)。

灰度过程并不是一帆风顺的。在全量切流量之前,遇到了一些或大或小的问题。大部分与具体业务有关,值得借鉴的是一个技术细节相关的陷阱。

健康检查

在传统的架构中,负载均衡调度系统每隔一秒钟会对每台服务器 80 端口的特定 URL 发起一次 <font face="NSimsun">get</font> 请求,根据返回的 HTTP Status Code 是否为 <font face="NSimsun">200</font> 来判断该服务器是否正常工作。如果请求 1s 后超时或者 HTTP Status Code 不为 <font face="NSimsun">200</font>,则不将任何流量引入该服务器,避免线上问题。

这个请求的路径是 Nginx -> Java -> Nginx,这意味着,只要返回了 <font face="NSimsun">200</font>,那这台服务器的 Nginx 与 Java 都处于健康状态。引入 Node.js 后,这个路径变成了 Nginx -> Node.js -> Java -> Node.js -> Nginx。相应的代码为:

  var http = require('http');
  app.get('/status.taobao', function(req, res) {
    http.get({
      host: '127.1',
      port: 7001,
      path: '/status.taobao'
    }, function(res) {
      res.send(res.statusCode);
    }).on('error', function(err) {
      logger.error(err);
      res.send(404);
    });
  });
Nach dem Login kopieren

但是在测试过程中,发现 Node.js 在转发这类请求的时候,每六七次就有一次会耗时几秒甚至十几秒才能得到 Java 端的返回。这样会导致负载均衡调度系统认为该服务器发生异常,随即切断流量,但实际上这台服务器是能够正常工作的。这显然是一个不小的问题。

排查一番发现,默认情况下, Node.js 会使用 <font face="NSimsun">HTTP Agent</font> 这个类来创建 HTTP 连接,这个类实现了 socket 连接池,每个主机+端口对的连接数默认上限是 5。同时 <font face="NSimsun">HTTP Agent</font> 类发起的请求中默认带上了 <font face="NSimsun">Connection: Keep-Alive</font>,导致已返回的连接没有及时释放,后面发起的请求只能排队。

最后的解决办法有三种:

禁用 <font face="NSimsun">HTTP Agent</font>,即在在调用 <font face="NSimsun">get</font> 方法时额外添加参数 <font face="NSimsun">agent: false</font>,最后的代码为:

  var http = require('http');
  app.get('/status.taobao', function(req, res) {
    http.get({
      host: '127.1',
      port: 7001,
      agent: false,
      path: '/status.taobao'
    }, function(res) {
      res.send(res.statusCode);
    }).on('error', function(err) {
      logger.error(err);
      res.send(404);
    });
  });
Nach dem Login kopieren

设置 <font face="NSimsun">http</font> 对象的全局 socket 数量上限:

 http.globalAgent.maxSockets = 1000;
Nach dem Login kopieren

在请求返回的时候及时主动断开连接:

http.get(options, function(res) {
  }).on("socket", function (socket) {
  socket.emit("agentRemove"); // 监听 socket 事件,在回调中派发 agentRemove 事件
});
Nach dem Login kopieren

实践上我们选择第一种方法。这么调整之后,健康检查就没有再发现其它问题了。

Node.js 与传统业务场景结合的实践才刚刚起步,仍然有大量值得深入挖掘的优化点。比比如,让 Java 应用彻底中心化后,是否可以考分集群部署,以提高服务器利用率。或者,发布与回滚的方式是否能更加灵活可控。等等细节,都值得再进一步研究。

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage