title: Proxy TCP stream (MySQL and Redis) with Nginx
body: <p>I read about <a href="https://www.nginx.com/blog/microservices-reference-architecture-nginx-fabric-model/" rel="noreferrer">Nginx Fabric Model</a> and it brings my attention to reconfigure how an application communicates to MySQL and Redis. If local Nginx instance can proxy HTTP traffic efficiently and fast, now it can also proxy TCP without worrying about the network, even using database slave as a master in case of emergency and potentially encapsulate database sharding. All the benefits can simplify application configuration and its logic, network (congestion, latency, timeouts, retries) won't be a focus in features development anymore.</p>
  
  <p>I use latest Docker and set of containers: <a href="https://hub.docker.com/_/nginx/" rel="noreferrer">Nginx</a>, <a href="https://hub.docker.com/_/redis/" rel="noreferrer">Redis</a>, <a href="https://hub.docker.com/_/mysql/" rel="noreferrer">MySQL</a>. I tried the following configuration:</p>
  
  <pre><code>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;
    }
  }
  </code></pre>
  
  <p>I have some questions:</p>
  
  <blockquote>
    <ul>
    <li><p>logging - how can I know which endpoint is in use, how many times did Nginx retry a particular request?</p></li>
    <li><p>real-time stats - is it possible to get throughput for stream module?</p></li>
    <li><p>from database sharding perspective - is it possible to dispatch request to a sharded database based on some logic apart from
    $remote_addr?</p></li>
    </ul>
  </blockquote>
  
  <p>The last question is quite important, I found modules <a href="http://nginx.org/en/docs/stream/ngx_stream_map_module.html" rel="noreferrer">ngx_stream_map_module</a> and <a href="http://nginx.org/en/docs/stream/ngx_stream_split_clients_module.html" rel="noreferrer">ngx_stream_split_clients_module</a> but $remote_addr is not suitable for sharding, can we intercept cookie from HTTP section and reuse in-stream section where we don't have any headers? Can we inject the Lua code in the stream section? Is <a href="http://nginx.org/en/docs/stream/ngx_stream_ssl_preread_module.html" rel="noreferrer">ngx_stream_ssl_preread_module</a> a solution for this problem, how to make it work for connection without encryption?</p>