我正在尝试决定如何设计一个 Netty 应用程序,我认为有一些不寻常的要求。基本上有一个客户端发起请求。该请求翻译成英文是“递归地在目录/whatever/下获取一堆小文件,关于这些文件,我只能告诉你它们的名称在 AAAAAAA.bin 和 CCCCCCC.bin 之间”。
因此,服务器需要接受请求,并开始扫描服务器端的一些目录,并开始快速将所有这些小文件传回。性能很重要,但确保我收到 AAAAAAA.bin 和 CCCCCCC.bin 之间的所有文件也很重要。
那么让客户端和服务器本身基本上是异步的会是一个好的设计吗?换句话说,客户端启动对话,发送请求,并简单地接收到一个确认 UUID token 或其他东西,然后服务器开始收集文件(可能每个线程一个),联系客户端,并将一个文件交给它使用 UUID?我在想客户端可以定期询问服务器“你是否完成了与 UUID token /sometoken/匹配的请求的流传输?
我不太确定这将如何配置,因为客户端和服务器都将启动对话。或者,也许其他人有更好的设计理念?同样,性能(从请求发起到完成所有文件传输的总时间)至关重要。
谢谢!
最佳答案
假设您完全控制协议(protocol)(即您不限于 HTTP),那么可能是这样的
- 客户端连接到服务器并发送目录请求。如果客户端正在重新启动中止的传输,则会发送带有来自 2 的 token 的请求
- 服务器使用此传输的唯一 token 进行响应。如果传输正在重新启动,它会使用 1 中的 token 进行响应。
- 服务器识别这次传输的所有文件,给每个文件一个唯一的 ID,并将文件集与来自 2 的 token 相关联(可能想在生成 token 之前找出文件)
- 对于每个文件,服务器都会发送一条消息,其中包含文件长度、唯一文件 ID、文件(以及任何其他信息,例如文件名)。服务器尽快发送每个文件,不等待 5 的确认。
- 客户使用唯一的文件 ID 确认收到的每个文件。
- 发送最后一个文件后,服务器发送“传输完成”消息。
所有上述通信都通过单一 channel 进行。重要的一点是您正在异步传输文件和接收确认,从而减少网络延迟。
如果您有很多文件,我不会为每个文件使用一个线程。也许是一个线程池,其中每个要发送的文件都被添加到一个作业队列中,或者每个唯一的目录都被添加到作业队列中并且一个线程一次处理一个目录。您可能需要同步对 channel.write(..) 的调用。我还假设客户端可以乱序接收文件。
实际上,我一开始只会用一个线程来读取文件。一旦它可靠地工作,看看是否有多个线程可以让您通过保持网络繁忙(即不等待读取下一个文件)来提高性能。
当写入 channel 时,我可能会写入包含文件详细信息(唯一 ID、足够小的文件数据、必要时的文件名)的对象,然后有一个编解码器可以将对象转换为 channel 缓冲区/从 channel 缓冲区转换。
根据您的具体情况,客户端可以打开多个到服务器的连接,您可以将连接分配给特定的文件读取线程,从而避免任何 channel 同步问题。您可能会通过这种方式获得一些性能提升,但最有可能的是,您只会看到连接之间共享的可用带宽。
关于java - 大量小额传输的Netty App设计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11727315/