gpt4 book ai didi

java - 每秒 100 万次远程函数调用

转载 作者:行者123 更新时间:2023-11-30 11:35:34 27 4
gpt4 key购买 nike

我想实现每秒 5-1 百万次远程函数调用。假设我们有一台开始计算的 Central 计算机,还有一台执行计算的 Worker 计算机。实际配置中会有很多Worker计算机。

假设我们的任务是计算一个[(random int from 0 to MAX_VAL)*2], PROBLEM_SIZE 次的总和非常幼稚的原型(prototype)是

worker :

//The real function takes 0.070ms to compute.
int compute(int input) {
return input * 2;
}

void go() {
try {
ServerSocket ss = new ServerSocket(socketNum);

Socket s = ss.accept();
System.out.println("Listening for " + socketNum);

DataInput di = new DataInputStream(s.getInputStream());
OutputStream os = s.getOutputStream();
byte[] arr = new byte[4];
ByteBuffer wrap = ByteBuffer.wrap(arr);

for (; ; ) {
wrap.clear();

di.readFully(arr);
int value = wrap.getInt();
int output = compute(value);

wrap.clear();
byte[] bytes = wrap.putInt(output).array();
os.write(bytes);
}

} catch (IOException e) {
System.err.println("Exception at " + socketNum);
e.printStackTrace();
}
}

中央:

void go(){    
try {

Socket s = new Socket(ip, socketNum);
s.setSoTimeout(2000);
OutputStream os = s.getOutputStream();
DataInput di = new DataInputStream(s.getInputStream());

System.out.println("Central socket starting for " + socketNum);

Random r = new Random();

byte[] buf = new byte[4];
ByteBuffer wrap = ByteBuffer.wrap(buf);

long start = System.currentTimeMillis();
long sum = 0;

for(int i = 0; i < n; i++) {
wrap.clear();
int value = r.nextInt(10000);

os.write(wrap.putInt(value).array());

di.readFully(buf);
wrap.clear();

int answer = wrap.getInt();
sum += answer;
}

System.out.println(n + " calls in " + (System.currentTimeMillis() - start) + " ms");
} catch(SocketTimeoutException ste) {
System.err.println("Socket timeout at " + socketNum);
}

catch (Exception e) {
e.printStackTrace();
}

如果 ping 为 0.150 毫秒并且我们运行 1 线程 Worker 和 1 线程 Central,则每次迭代将花费 ~0.150 毫秒。为了提高性能,我在 Worker 和 Central 上运行了 N 个线程,第 n 个线程监听端口 2000+n。每个线程停止后,我们总结结果。

基准

首先,我在我同事的学校网络中运行了上面的程序。其次,我在两个 Amazon EC2 集群实例上运行它。结果差距很大。

CHUNK_SIZE = 100_000 在所有运行中。

伙伴网络:

我认为 3 年前它是可用的顶级配置 (Xeon E5645)。我相信它针对并行计算进行了大量优化,并且具有简单的 LAN 拓扑,因为它只有 20 台机器。

操作系统:Ubuntu

平均 ping:~0.165 毫秒

N=1 total time=6 seconds 
N=10 total time=9 seconds
N=20 total time=11 seconds
N=32 total time=14 seconds
N=100 total time=21 seconds
N=500 total time=54 seconds

亚马逊网络:

我在同一个放置组中启动的两个集群计算 8 超大型实例 (cc2.8xlarge) 上运行该程序。

操作系统是一些amazonian linux

平均 ping:~0.170 毫秒。

结果有点令人失望:

N=1 total time=16 seconds 
N=10 total time=36 seconds
N=20 total time=55 seconds
N=32 total time=82 seconds
N=100 total time=250 seconds
N=500 total time=1200 seconds

每个配置我都运行了 2-4 次,结果都差不多,大部分是 +-5%

Amazon N=1 结果是有道理的,因为每个函数调用 0.170 毫秒 = 每秒 6000 次调用 = 每 16 秒 100_000 次调用。 Fellow 的网络 6 秒实际上是令人惊讶的。

我认为现代网络每秒的最大 TCP 数据包约为每秒 40-70k。对应N=100,time=250秒:N*CHUNK_SIZE/time = 100 * 100_000packets/250sec = 10_000_000packets/250sec = 40_000packets/second。

问题是,我的 Fellow 的网络/计算机配置是如何做到如此出色的,尤其是在高 N 值的情况下?

我的猜测:将每个 4 字节的请求和 4 字节的响应放入单独的数据包是一种浪费,因为有大约 40 字节的开销。明智的做法是将所有这些微小的请求集中起来,比如 0.010 毫秒,并将它们放在一个大数据包中,然后将请求重新分配到相应的套接字。可以在应用程序级别实现池化,但似乎 Fellow 的网络/操作系统已配置为执行此操作。

更新:我玩过 java.net.Socket.setTcpNoDelay(),它没有改变任何东西。

最终目标:我使用非常大的树来近似具有数百万个变量的方程。目前,具有 200_000 个节点的树适合 RAM。但是我很想近似方程,它需要具有数百万个节点的树。这将需要几 TB 的 RAM。算法的基本思想是采用从节点到叶子的随机路径,并沿路径改进值。当前程序是 32 线程的,每个线程每秒执行 15000 次迭代。我想将它移动到每秒迭代次数相同的集群中。

最佳答案

您可能希望启用 Nagle 算法:wikipedia entry .

这里有一个关于禁用它的链接可能会有帮助:Disabling Nagle's Algorithm in linux

关于java - 每秒 100 万次远程函数调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15026384/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com