【问题标题】:Proxy TCP stream (MySQL and Redis) with Nginx使用 Nginx 代理 TCP 流(MySQL 和 Redis)
【发布时间】:2021-02-02 22:01:05
【问题描述】:

我读到了Nginx Fabric Model,它让我注意到重新配置应用程序与 MySQL 和 Redis 的通信方式。如果本地 Nginx 实例可以高效、快速地代理 HTTP 流量,那么现在它也可以代理 TCP 而无需担心网络,甚至在紧急情况下使用数据库从机作为主机,并可能封装数据库分片。所有好处都可以简化应用程序配置及其逻辑,网络(拥塞、延迟、超时、重试)将不再是功能开发的重点。

我使用最新的 Docker 和一组容器:NginxRedisMySQL。我尝试了以下配置:

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log info;
pid        /var/run/nginx.pid;


events {
  worker_connections  1024;
}

stream {
  upstream redis {
    # prefer first server but limit connections
    server 172.17.0.8:6379 weight=2 max_conns=1;
    server 172.17.0.3:6379;
  }

  upstream mysql {
    # use second server in case of failure
    server 172.17.0.4:3306;
    server 172.17.0.5:3306 backup;
  }

  server {
    listen 6379 so_keepalive=on;
    proxy_pass redis;
  }

  server {
    listen 3306 so_keepalive=on;
    proxy_pass mysql;
  }
}

我有一些问题:

  • 日志记录 - 我如何知道哪个端点正在使用,Nginx 重试了多少次特定请求?

  • 实时统计 - 是否可以获得流模块的吞吐量?

  • 从数据库分片的角度来看 - 是否可以根据某些逻辑将请求分派到分片数据库 $remote_addr?

最后一个问题很重要,我找到了模块ngx_stream_map_modulengx_stream_split_clients_module 但是$remote_addr 不适合分片,我们可以从HTTP 部分截取cookie 并重用我们没有任何标头的in-stream 部分?我们可以在流部分注入 Lua 代码吗? ngx_stream_ssl_preread_module是这个问题的解决方案吗,如何让它在不加密的情况下进行连接?

【问题讨论】:

  • 是的,来自 Nginx 核心团队成员的电子邮件。日志记录:使用 $upstream_addr 扩展 log_format,仅通过 Nginx Plus 进行实时统计,MySQL sharding
  • 你可以回答你自己的问题。
  • 这个问题很复杂,你最好把它分成三个不同的问题。

标签: mysql performance nginx redis load-balancing


【解决方案1】:

我认为 Nginx 不能用于您尝试使用它的目的。虽然它可用于代理 tcp 流或对其进行负载平衡,但它不一定了解其中的协议和请求结构。所以回答你的问题:

从数据库分片的角度来看 - 是否可以基于 $remote_addr 之外的某些逻辑将请求分派到分片数据库?

不是真的。它不能根据内容将不同的 Redis 请求或 MySQL 查询从单个连接路由到不同的服务器,因为这些东西到 nginx 只是一个它无法读取的流。它在流启动期间为其分配一个目的地,并确保所有来回的数据包都到达相同的目的地,仅此而已。

例如,在您链接的 MySQL 分片文章中,它执行 mysql 命令提示符以运行单个查询并检查节点名称。每次运行时,它都会建立连接、运行查询并断开连接。因此,每次执行此操作时,新连接都会由 nginx 路由到另一台服务器。但是,如果您要在同一个 mysql 命令提示符实例上运行相同的查询两次,它会给您相同的节点名称。还值得注意的是,这是使用 MySQL Galera,它是 MySQL 的多主配置,它在自身内部处理读写路由,允许像这样的任意客户端查询路由。 redis 就不是这样了。

此外,这也不会从本质上摆脱应用程序的所有连接处理。在许多情况下,错误(例如下游不可用)仍可能传播到客户端。

您可以使用它来简化应用程序的配置,但是,它也可能只是将复杂性推到本地 nginx 配置中。所以这可能是也可能不是实际的好处。


我们可以从 http 部分截取 cookie 并在我们没有任何标头的流部分中重用吗?

可能不会。 HTTP 标头不会传递到数据库连接,因为它们是根本不同的协议,因此即使 nginx 可以读取流,它也无法使用。


我们可以在流部分注入 Lua 代码吗?

这是可能的,但需要一个能够解析应用程序协议的 Lua 模块,例如 Redis 和 MySQL 的有线协议。但正如我之前提到的,在连接中路由请求(即使您可以在 nginx 中检测和路由它们)从数据库/一致性的角度来看,这些并不一定很简单,我真的不建议这样做。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-07
    • 2021-03-11
    • 1970-01-01
    • 2018-11-04
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 2013-05-17
    相关资源
    最近更新 更多