mysql - 使用 Nginx 代理 TCP 流(MySQL 和 Redis)

标签 mysql performance nginx redis load-balancing

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

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

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;
  }
}

我有一些问题:

  • logging - how can I know which endpoint is in use, how many times did Nginx retry a particular request?

  • real-time stats - is it possible to get throughput for stream module?

  • from database sharding perspective - is it possible to dispatch request to a sharded database based on some logic apart from $remote_addr?

最后一个问题相当重要,我找到了模块ngx_stream_map_modulengx_stream_split_clients_module但是 $remote_addr 不适合分片,我们可以从 HTTP 部分拦截 cookie 并重用没有任何 header 的流内部分吗?我们可以在流部分注入(inject)Lua代码吗?是ngx_stream_ssl_preread_module这个问题的解决方案,如何使其在不加密的情况下工作?

最佳答案

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

from database sharding perspective - is it possible to dispatch request to sharded database based on some logic apart from $remote_addr?

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

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

此外,这本质上也不会消除应用程序的所有连接处理。在许多情况下,诸如下游不可用之类的错误仍可能传播到客户端。

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

<小时/>

can we intercept cookie from http section and reuse in stream section where we don't have any headers?

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

<小时/>

Can we inject Lua code in the stream section?

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

关于mysql - 使用 Nginx 代理 TCP 流(MySQL 和 Redis),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42847085/

相关文章:

node.js - Node.js 应用程序中两个并发请求混合在一起

ruby-on-rails-4 - 带有运行 Puma 和 Nginx 的 AWS Elastic Beanstalk 的 Rails 应用程序 502

mysql - 使用单列mysql进行全文搜索

mysql - 如何处理MySQL表太多的麻烦?

performance - 如何在 ElasticSearch 中为短语查询启用模糊性

linux - 在 debian vps 上安装了 gitlab-omnibus 8.16 - 现在我该如何到达它?

javascript - 如何将这种特定类型的数据添加到 MySQL 中

mysql - 如何规划具有相同ID的数据库?

objective-c - 相似的代码行,截然不同的性能

php - docker 上带有 Nginx、php 7.4 fpm 和 mysql 8 的 Laravel 6 比 php 7.1 上的 Laravel 4 慢