BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

如何把全世界的Web浏览器连成一个超级计算机?

| 作者 Ben 关注 0 他的粉丝 ,译者 Martin 关注 0 他的粉丝 发布于 2018年3月15日. 估计阅读时间: 11 分钟 | GMTC大前端的下一站,PWA、Web框架、Node等最新最热的大前端话题邀你一起共同探讨。

黑客Ben尝试了一个非常大胆的想法,通过WebSocket将全世界的Web浏览器连接在一起,组成一个“超级计算机”,并利用这个超级计算机解决分布式问题。以下内容翻译自作者的博文。

写在前面

我们将讨论一个具有争议性的话题——如何从网站访客的浏览器中“偷”走计算资源。目前有很多讨论是关于如何利用浏览器来挖掘数字货币的,但我不想加入到这些话题的讨论当中,我只是想探讨一种有效利用计算资源的方式。

Web浏览器执行代码的能力越来越强大。JavaScript的发展、WebAssembly的出现、对GPU访问能力的提升和线程模型的演变,这些因素组合在一起,让浏览器与计算机一样具备了强大的计算能力。随着浏览器数字货币挖矿机的崛起,我也在思考这样的一个问题:如何把全世界的计算资源整合成一个单独的实体——一台由网站访客的浏览器组成的超级计算机。

就像普通的计算机集群一样,这台超级计算机的所有计算节点在协调之下共同解决一个问题。但与普通的计算机集群不同的是,这些计算节点时临时性的(随着网站访客的来来去去),而且它们之前无法彼此对话(没有跨站点的请求)。

这是我想到的一个例子:

右边是超级计算机控制服务器。左边是访问某个网站的浏览器,它是这个超级计算机中的一个节点,上面还显示了它的CPU指标。

这个超级计算机要解决的问题是找出某个给定哈希值的原始值。从图上可以看出,总共有23个节点参与了计算,计算并比对了380,204,032个哈希值,其中美国的访客贡献了50%的处理能力。

代码实现

这里主要用WebSocket技术在服务器和计算节点之间建立持久连接。这些连接用于协调节点的行为,从而让它们成为相互协作的实体。WebSocket可以传输代码和协作消息,让一切都成为可能。

WebSocket的出现戏剧性地改变了Web客户端的行为。客户端连接到网站上,先执行预先定义好的JavaScript,等建立起WebSocket连接之后,就可以执行其他任意JavaScript脚本。

下图右边是超级计算机控制服务器,左边是接收动态指令的Web客户端。

如果一款App使用了WebView,JavaScript就可以直接跑到App中,也就是说,通过WebSocket传输的代码可以跳过WebView,直接进入App的领地。

下图右边是超级计算机控制服务器,左边是接收指令的Web App。可以看到,指令直接渗透到了App层。

剩下的就没有什么新鲜的了。App可以通过C&C协议(Botnet Command and Control)获取指令,网页在初次加载之后就可以动态获得JavaScript脚本,而WebSocket具有真正的动态性(不像Ajax的轮询拉取模式),可以跨多浏览器和设备运行,而且对运行环境有完全的访问权限。

所以,我们完全可以通过WebSocket向计算节点传输指令代码,当然也可以用来传递消息,实现分布式协调。

Crackzor.js

六年前,我基于OpenMPI开发了一款分布式密码破解器(http://ben.akrin.com/?p=1424),叫作crackzor。密码破解是一个非常典型的分布式问题,说起来很简单,就是通过排列组合字符猜出密码。我使用JavaScript重写了crackzor,使用WebSocket替代了OpenMPI。

不过,每一个分布式问题都是不一样的,crackzor并不是解决所有问题的良方。crackzor的魔力在于它的灵活性,它把一个字符排列组合空间拆分成很多个块,再把这些块分摊给计算节点。在给定了要解决的问题以及迭代的起始和结束位置之后,节点就可以开始工作,不需要再为它们提供字符排列组合,这样就不会出现网络带宽瓶颈问题。

第一个问题:如何最大程度利用节点的CPU

JavaScript默认使用的是单线程模型,代码通过WebSocket传送到客户端,默认情况下只使用了CPU的一个核。而现今的大部分计算机CPU都是多核的,所以,我们要想办法把这些CPU都利用起来。

于是救星出现了——Web Worker。HTML5提供了这一特性,极大简化了多线程的实现。不过,我们还需要解决一个问题。Web Worker文档告诉我们要从文件加载脚本文件,但我们的代码是通过WebSocket传输过来的,并驻存在内存中,所以我们无法直接通过指定脚本文件的方式来执行代码。

我们通过把代码包装成一个Blob对象来解决这个问题:

var worker_code = 'alert( "this code is threaded on the nodes" );'
window.URL = window.URL || window.webkitURL;
var blob;
try {
    blob = new Blob([worker_code], {type: 'application/javascript'});
} catch (e) {
    window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder;
    blob = new BlobBuilder();
    blob.append(worker_code);
    blob = blob.getBlob();
}
workers.push( new Worker(URL.createObjectURL(blob)) ) ;

第二个问题:在节点间分配任务

WebSocket服务器承担了后续的大部分协调工作,它需要跟踪节点的接入和退出,以及某个节点是否在执行计算任务,并在有可用节点时给它们分配任务。

服务器需要一直处于运行状态,处理来自节点的连接。不过,这台超级计算机可能每天需要解决不同的问题。为此,我写了一个函数用来读取文件,并执行文件中的代码。这个函数通过一个进程来调用。

function eval_code_from_file() {
    if( !file_exists("/tmp/code") ) {
        console.log( "error: file /tmp/code does not exist" ) ;
    } else {
        var code = read_file( "/tmp/code" ) ;
        code = code.toString() ;
        eval( code ) ;
    }
}
 
process.on('SIGUSR1', eval_code_from_file.bind() );

有了这个函数,下一次我就可以杀掉旧进程,然后使用新进程加载新代码。这要归功于JavaScript的灵活性,这种灵活性让我们可以在任意时刻运行任意代码,只要对运行环境有完全的访问权限。

要给节点分发任务也很简单,只要让客户端在连接到服务器时注册一个回调函数,然后在回调函数里执行代码即可。比如:

客户端:

var WebSocket_client=io.connect("http://WebSocket_server.domain.com"); 
WebSocket_client.on( "eval_callback",function(data){data=atob(data),eval(data)}.bind() ) ;

服务器端:

client_socket.emit( "eval_callback", new Buffer("alert('this code will run on the client');").toString("base64") ) ;

到目前为止:

  1. 所有的临时节点(网站用户的Web浏览器)连接到WebSocket服务器上
  2. 通过进程信号让WebSocket服务器执行新的代码
  3. 新代码中包含了节点需要解决的新问题
  4. 新代码告诉WebSocket服务器如何协调节点
  5. 一旦某个节点解决了问题,接着处理下一个问题

现在我们知道了如何利用Web浏览器来构建一台超级计算机。出于多方面的考虑,比如可读性、安全性和复杂性方面的问题,我不想把我的代码全部都公开出来。不过,如果有人感兴趣,可以联系我,我很乐意分享跟多的想法。

更多小建议:

  • 在拆分任务时,任务不能太大。因为节点都是临时性的,如果任务太重,极有可能发生中断。大部分Web浏览器会拒绝执行或终止执行太耗资源的代码,而小任务可以在几秒钟之内就完成,不会被打断。
  • 使用JavaScript实现MD5:https://gist.github.com/josedaniel/951664
  • 记录节点解决问题所使用的平均时间,把运行缓慢的节点排除在外,以免影响“超级计算机”的整体性能。

原文链接:http://ben.akrin.com/?p=5997

感谢郭蕾对本文的审校。

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

用webRTC和webSocket来配合实现可会更好 by 孟 德斌

用webRTC和webSocket来配合实现可会更好

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

1 讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT