基础设施:数据中心的服务器,操作系统 - Debian Squeeze,Web 服务器 - Apache 2.2.16
情况:
我们的客户每天都在使用实时服务器,因此无法测试调整和改进。因此,我们希望将实时服务器上的入站 HTTP 流量实时复制到一个或多个远程服务器。流量必须传递到本地 Web 服务器(在本例中为 Apache)和远程服务器。这样,我们可以调整配置并在远程服务器上使用不同的/更新的代码来进行基准测试并与当前实时服务器进行比较。由于客户端结构的原因,目前 Web 服务器除了 80 和 443 之外还监听大约 60 个其他端口。
问题:如何实现到一台或多台远程服务器的复制?
我们已经尝试过:
- agnoster duplicator - 这将要求每个端口打开一个会话,但不适用。(https://github.com/agnoster/duplicator)
- kklis 代理 - 仅将流量转发到远程服务器,但不将其传递给本地网络服务器。(https://github.com/kklis/proxy)
- iptables - DNAT 仅转发流量,但不会将其传递给本地 Web 服务器
- iptables - TEE 仅复制到本地网络中的服务器 -> 由于数据中心的结构,服务器不在同一网络中
- 在 stackoverflow 上针对“使用代理复制 TCP 流量”问题提供的建议替代方案(https://stackoverflow.com/questions/7247668/duplicate-tcp-traffic-with-a-proxy) 均未成功。如前所述,TEE 不适用于本地网络之外的远程服务器。teeproxy 不再可用(https://github.com/chrislusf/tee-proxy) 并且我们在其他地方找不到它。
- 我们添加了第二个 IP 地址(位于同一网络中)并将其分配给 eth0:0(主 IP 地址分配给 eth0)。将此新 IP 或虚拟接口 eth0:0 与 iptables TEE 功能或路由结合使用失败。
- 针对“Debian Squeeze 上重复传入 TCP 流量”问题提供的建议替代方案(Debian Squeeze 上重复传入 TCP 流量) 失败。cat|nc 会话(cat /tmp/prodpipe | nc 127.0.0.1 12345 和 cat /tmp/testpipe | nc 127.0.0.1 23456)在客户端每次请求/连接后都会中断,没有任何通知或日志。Keepalive 并没有改变这种情况。TCP 包未传输到远程系统。
- 使用 socat 的不同选项进行额外尝试(方法:http://www.cyberciti.biz/faq/linux-unix-tcp-port-forwarding/,https://stackoverflow.com/questions/9024227/duplicate-input-unix-stream-to-multiple-tcp-clients-using-socat) 和类似的工具均未能成功,因为提供的 TEE 函数只会写入 FS。
- 当然,通过谷歌搜索这个“问题”或设置也没有成功。
我们现在没有选择了。
有没有办法在使用 IPTABLES 时禁用 TEE 功能的“本地网络中的服务器”的强制执行?
通过不同使用IPTABLES或者Routes能达到我们的目标吗?
您是否知道有其他可用于此目的且经过测试并适用于这些特定情况的工具?
是否有其他 tee-proxy 来源(据我所知,它完全符合我们的要求)?
提前感谢您的回复。
----------
编辑:2014 年 5 月 2 日
下面是 Python 脚本,它可以按照我们需要的方式运行:
import socket
import SimpleHTTPServer
import SocketServer
import sys, thread, time
def main(config, errorlog):
sys.stderr = file(errorlog, 'a')
for settings in parse(config):
thread.start_new_thread(server, settings)
while True:
time.sleep(60)
def parse(configline):
settings = list()
for line in file(configline):
parts = line.split()
settings.append((int(parts[0]), int(parts[1]), parts[2], int(parts[3])))
return settings
def server(*settings):
try:
dock_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
dock_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
dock_socket.bind(('', settings[0]))
dock_socket.listen(5)
while True:
client_socket = dock_socket.accept()[0]
client_data = client_socket.recv(1024)
sys.stderr.write("[OK] Data received:\n %s \n" % client_data)
print "Forward data to local port: %s" % (settings[1])
local_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
local_socket.connect(('', settings[1]))
local_socket.sendall(client_data)
print "Get response from local socket"
client_response = local_socket.recv(1024)
local_socket.close()
print "Send response to client"
client_socket.sendall(client_response)
print "Close client socket"
client_socket.close()
print "Forward data to remote server: %s:%s" % (settings[2],settings[3])
remote_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
remote_socket.connect((settings[2], settings[3]))
remote_socket.sendall(client_data)
print "Close remote sockets"
remote_socket.close()
except:
print "[ERROR]: ",
print sys.exc_info()
raise
if __name__ == '__main__':
main('multiforwarder.config', 'error.log')
使用该脚本的注释:
该脚本将多个配置的本地端口转发到另一个本地和一个远程套接字服务器。
配置:
在配置文件port-forward.config中添加如下内容:
错误消息存储在文件“error.log”中。
该脚本将配置文件的参数进行拆分:
用空格拆分每个配置行
0:要监听的本地端口
1:要转发到的本地端口
2:目标服务器的远程 IP 地址
3:目标服务器的远程端口
和返回设置
答案1
这是不可能的。TCP 是全状态协议。用户端计算机参与连接的每个步骤,它永远不会响应试图与其通信的两个独立服务器。您所能做的就是收集 Web 服务器或某个代理上的所有 http 请求并重放它们。但这不会提供实时服务器的确切并发性或流量状况。
答案2
根据您的描述,GOR 似乎满足您的需求。 https://github.com/buger/gor/“实时重播 HTTP 流量。重播从生产到暂存和开发环境的流量。”?
答案3
Teeproxy可用于复制流量。用法非常简单:
./teeproxy -l :80 -a localhost:9000 -b localhost:9001
a
生产服务器b
测试服务器
当你在 Web 服务器前放置 HAproxy (带有roundrobin
) 时,你可以轻松地将 50% 的流量重定向到测试站点:
/------------------> production
HAproxy / ^
\ /
\---- teeproxy -.....> test (responses ignored)
答案4
我正在尝试做类似的事情,但是,如果您只是想模拟服务器上的负载,我会考虑使用负载测试框架之类的东西。我以前使用过 locust.io,它在模拟服务器上的负载方面效果非常好。这应该允许您模拟大量客户端,并让您使用服务器的配置,而不必经历将流量转发到另一台服务器的痛苦过程。