- AWS用不起,各种GPU云都用不起
- Mac Book不能运行
tensorflow-gpu
- GPU笔记本太重不想来回搬动,用起来没有Mac舒服,没有retina屏
- 希望在任何地方能用自己的Mac Book连到GPU笔记本上的jupyter notebook
在本地的mac上开一个服务,所有的请求(包括http
和websocket
),都用hws _(higher order websocket,高阶websocket)_传输到ECS服务器,然后ECS服务器通过hws转发到公司GPU笔记本。
Mac本地运行一个nodejs服务
src/remote.js
,ECS运行一个nodejs转发服务remote-server.js
,GPU笔记本也在本地运行一个nodejs服务src/native.js
首先要有nodejs环境,直接去node官网下载安装即可。然后git clone
,npm i
,npm如果没速度,或许你需要cnpm
git clone https://github.com/Plasmatium/nbBridge
cnpm i
有两件东西需要配置,ECS的nginx.conf和传输两端的conf.json
按照如下格式配置,密码和url根据自身情况更改:
{
"REMOTE_HWS_URL": "ws://your/ECS/websocket/path",
"LOCAL_HWS_URL": "ws://your/native/websocket/path",
"INTERNEL_PORT": "YOUR_INTERNEL_PORT",
"KEY": "pwd_with_16_char",
"IV": "iv__widh_16_char",
"AGL": "aes-128-cbc"
}
按照如下格式配置,只是部分配置,其他部分具体请参照nginx文档。其中YOUR_INTERNEL_HWS_SERVER
和上述INTERNEL_PORT
相关,比如INTERNEL_PORT
设为8765,那么YOUR_INTERNEL_HWS_SERVER
设为http://localhost:8765
# higher order websocket
location /your/ECS/websocket/path {
proxy_pass YOUR_INTERNEL_HWS_SERVER;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_read_timeout 300s;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
error_log off;
access_log off;
}
注:两端和ECS都需要放好
conf.json
- 在GPU本上首先启动服务:
node src/native.js
- 登陆ECS,启动nginx,启动node服务:
node src/remote-server.js
- Mac上启动node服务:
node src/remote.js
http请求相对websocket简单:Mac请求 -> ECS转发 -> GPU本响应 -> ECS转发回来 -> Mac浏览器收到响应并渲染页面
- 在mac上,请求http,比如http://localhost:8080
- 生成一个
uuid
,将上面请求的响应对象res
存储在一个响应池中,key是uuid
。 - 将上述请求中的
headers
,body
,originalUrl
,以及上述uuid
打包压缩加密为sendData
。 - 用hws发送
sendData
到ECS - ECS转发hws的内容到GPU笔记本上
- GPU本解码解包,获取到
headers
,body
,originalUrl
,uuid
,伪装headers
成为本地请求,将originalUrl
改成jupyter notebook
的url,比如将http://localhost:8080
改成http://localhost:8888
,然后将headers
,body
发送到该url
- GPU本收到上面第7步的request之后,以为是本地机器请求
jupyter notebook
,会发送响应response
,包括headers
,status
,body
- 将上述
headers
,status
,body
, 以及上面request中的uuid
一起打包压缩加密为respData
,用hws发送到ECS上 - ECS转发respData到本地Mac电脑上
- Mac解包解码,获得
headers
,status
,body
,uuid
- 在request步骤1里创建的响应池中,通过
uuid
找到该请求的响应对象res
- 用
res.status
和res.send
,将上述第3步解码出来的headers
,status
,body
发送到Mac上浏览器,一个完整的请求->响应链至此结束。
websocket相对复杂些,需要将上下行链路小心翼翼串起来,具体是上家websocket的
onmessage
里使用对的下家websocket的send
- Mac浏览器发出创建websocket请求到Mac本地
ws://localhost:8080,
含有headers
,originalUrl
- 生成
uuid
,连同上一步获得的headers
,originalUrl
一起打包压缩加密,通过hws发送到ECS - 用上述
uuid
,以及浏览器创建在本地的ws,存入到ws池中,uuid
作为索引 - ECS通过hws转发这个加密包到GPU本
- GPU本解包解码获得
originalUrl
,headers
,uuid
- 通过上一步的
originalUrl
,headers
,创建websocket,并用uuid
作为索引存放在ws池里
- 浏览器发出ws的message,将
event.data
, 发出这个信息的ws
对应的uuid
一起打包压缩加密,通过hws发送到ECS - ECS用hws转发这个加密包到GPU本
- GPU本解包解码,获得
event.data
和uuid
, 通过uuid
找到ws池中的ws对象,用该ws发送event.data
到jupyter notebook
服务器 jupyter notebook
做出回应,会触发上述uuid
对应的ws的onmessage
方法。在此方法中,打包回应的event.data
,连同uuid
一起打包压缩加密,通过hws发往ECS- ECS上用hws转发该加密包到Mac上
- Mac解码解包,获得
event.data
,uuid
,通过该uuid
找到ws池中对应的ws,用该ws发送event.data
,浏览器将会收到数据并渲染(该ws即浏览器创建在Mac上的websocket)