使用Java NIO实现服务器软件需要建议

6
我正在尝试计算我需要构建的服务器的负载。
我需要创建一个服务器,其中一个SQL数据库中注册了一百万个用户。在一周内,每个用户大约会连接3-4次。每次用户上传和下载1-30MB的数据,可能需要1-2分钟的时间。
当上传完成后,它将在几分钟内被删除。(更新文本中删除了计算错误)
我知道如何制作和查询SQL数据库,但在这种情况下需要考虑什么?
4个回答

5
你需要的是Netty。它是一个使用NIO编写的API,提供了另一种事件驱动模型,而不是传统的线程模型。 它不使用每个请求一个线程,而是将请求放入队列中。使用此工具,您可以每秒处理高达250,000个请求。

1
会推荐Netty:相当不错。比人们预期的要稍微复杂一些,但功能齐全。 - Femi
"Will second Netty" 是什么?NETTY2? - Erik
+1 我喜欢Netty,并且在我看来,它比Java sockets和Java NIO更容易使用和更强大。 - alpian
@Erik:对不起,请问在哪里提到了? - Houcem Berrayana
1
@Erik,定义: sec·ond /'sekənd/ 动词:正式支持或认可(提名、决议或其提出者),作为采纳或进一步讨论的必要前提。 - willjcroz

4

一开始我认为这么多用户需要一个非阻塞的解决方案,但我的计算表明我不需要,我是对的吗?

在现代操作系统和硬件上,每个连接一个线程(thread-per-connection) 的I/O比非阻塞I/O更快,至少在连接数达到极限之前是这样。然而,对于将数据写入磁盘,NIO(通道和缓冲区)可能会有所帮助,因为它可以使用DMA并避免复制操作。

但总的来说,网络带宽和存储空间也是您在此应用程序中的主要考虑因素。


@Michael Borgwardt 很好的观点,谢谢。看起来Netty是最好的选择。幸运的是,硬件和带宽方面我没有任何限制。我有两个月的时间来制作服务器。您有任何关于书籍、示例或代码样本的建议吗? - Erik
1
@Erik:实际上我的观点是,使用Netty来复杂化你的设计是没有必要的。使用经典的线程IO应该就可以了。 - Michael Borgwardt
@Michael Borgward 我认为NIO更好,因为唯一的目的是让用户从硬盘保存/加载文件。没有计算,没有等待。只需进出交付或获取文件。所以你真的认为如果我确保有4台使用SSD磁盘的服务器计算机,我可以使用David Flanagan的方法吗?负载均衡计算机 - Erik
@Erik:你的线程将需要处理大量数据。我肯定会使用像Tomcat这样的已建立的服务器组件,而不是从书中使用示例代码。 - Michael Borgwardt
@Erik: Tomcat是基于每个连接一个线程的模型的服务器。与从头开始构建自己的服务器相比,它的优点在于它是成熟的、经过测试和调优的代码,并基于广泛使用的标准,因此您可以使用第三方组件(例如安全性)。与Netty相比的优势在于它是一种更简单的编程模型,更多的开发人员熟悉它(几乎每个Java开发人员都有Servlets的经验)。而且,正如我所说,它的性能可能也更好。 - Michael Borgwardt
显示剩余4条评论

4
我正在使用Netty处理类似的情况。它运行良好!以下是使用Netty的起点:
public class TCPListener {
    private static ServerBootstrap bootstrap;

    public static void run(){
        bootstrap = new ServerBootstrap(
                new NioServerSocketChannelFactory(
                        Executors.newCachedThreadPool(),
                        Executors.newCachedThreadPool()));

        bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            public ChannelPipeline getPipeline() throws Exception {
                TCPListnerHandler handler = new MyHandler();
                ChannelPipeline pipeline = Channels.pipeline();
                pipeline.addLast("handler", handler);

                return pipeline;
            }
        });

        bootstrap.bind(new InetSocketAddress(9999));  //port number is 9999
    }

    public static void main(String[] args) throws Exception {
        run();
    }
}

和MyHandler类:

public class MyHandler extends SimpleChannelUpstreamHandler {
    @Override
    public void messageReceived(
        ChannelHandlerContext ctx, MessageEvent e) {


        try {
            String remoteAddress = e.getRemoteAddress().toString();
            ChannelBuffer buffer= (ChannelBuffer) e.getMessage();
            //Now the buffer contains byte stream from client.

        } catch (UnsupportedEncodingException ex) {
            ex.printStackTrace();
        }

        byte[] output; //suppose output is a filled byte array
        ChannelBuffer writebuffer = ChannelBuffers.buffer(output.length);
        for (int i = 0; i < output.length; i++) {
            writebuffer.writeByte(output[i]);
        }


        e.getChannel().write(writebuffer);
    }

    @Override
    public void exceptionCaught(
            ChannelHandlerContext ctx, ExceptionEvent e) {
        // Close the connection when an exception is raised.
        e.getChannel().close();
    }
}

@Farshid Zaker 谢谢,除了明显的 Apache 网站,我应该从哪里开始学习 Netty?我知道有不同品牌的 Netty,容易入门的阅读材料是什么? - Erik
@Farshid Zake 谢谢,我看到它似乎很容易。我在考虑NIO机制。如果我的所有用户都不相互交互,只需要文件系统、SQL访问,没有单例或静态变量。我应该使用哪种类型的NIO方法呢? - Erik
@Farshid Zake 如果我想要加密呢?加密登录和所有发送/接收的文件都要加密。我猜我可以让发送者加密和压缩文件。但是 SQL 登录部分,有没有 Netty 库可以用来实现? - Erik
我已经在客户端和服务器两端实现了加密。我不知道这种方法是否适合您。无论如何,我已经在Netty之外实现了加密机制。 - Farshid Zaker
@Farshid Zaker,听起来不错。你说你在类似的场景中使用了Netty。能详细介绍一下吗?平均有多少个连接?我一直想要向您具体询问关于Netty的问题(还没有阅读相关资料)。如果所有东西都在一个线程上运行,那么每个连接的用户如何完成工作呢? - Erik
1
有时候没有任何人连接!而有时候大约有100个设备(是的,设备不是用户!)连接。下个月将增加到几百个。在测试情况下,它支持1000个并发连接。 顺便说一句,谁说所有东西都在单个线程上运行? - Farshid Zaker

3
重要的是要记住,大多数用户不会在每天的每个小时均匀地访问系统。您的系统需要在一周中最繁忙的小时内正确执行。
例如,在一周中最繁忙的一个小时内,所有上传的1/50都会完成。在最繁忙的时间段,每个上传可能达到30MB,总共为1.8TB。这意味着您需要具备支持此功能的互联网上传带宽。即4 Gbit/s的互联网连接,计算方式为:1.8 TB/hour * 8 bits/byte / 60 min/hour / 60 sec/min。
如果您只有1 Gbit/s的连接,则会限制对服务器的访问。
另一个需要考虑的因素是上传文件的保留时间。如果每个上传平均为15 MB,则每周将获得157 TB或每年8.2 PB(8200 TB)的数据量。您可能需要大量存储空间来保留这些数据。
一旦您花费了大量的资金购买互联网连接和硬盘,购买几台服务器的成本就微不足道了。您可以使用Apache MIMA,但是单个具有10 Gbit/s连接的服务器可以轻松支持1 GB,并且可以使用任何软件。
单个PC/服务器/笔记本电脑可以处理1000个I/O线程,因此300-600个线程并不多。
问题不在于软件,而在于您选择的网络/硬件。

1
感谢@Peter Lawrey。我编辑了我的问题以提供更多细节。我的客户遍布全球,但欧洲和美国可能会在查询方面给我峰值,因为他们拥有更好的数据计划带宽。我与一个服务器大厅签订了合同,提供所有计算机,并可以快速扩展。 - Erik
1
@Erik,你可能会发现磁盘IO是一个问题。50 MB/秒相对容易,但125 MB/秒(对于1 Gb)和500 MB/秒(对于4 Gb上传)将需要多个后端数据存储系统。 - Peter Lawrey
1
如果您每月读写150 TB,那么总共是300 TB。亚马逊将对此IO速率收取约30K美元/月的费用。这些文件是否可以压缩,因为如果可以,这将有助于降低成本? - Peter Lawrey
@Peter Lawrey,谢谢您的建议,我已经向我的服务器提供商转达了您的想法,让我们看看他们对此有何回应。顺便说一下,我住在瑞典。感谢您的观点。 - Erik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接