跳到主要内容

· 阅读需 6 分钟
丹坤
守帅

Serverless Devs是一款企业级的,帮助用户管理Serverless应用全生命周期的开发者工具。企业内部有着比较严格的网络管控,比如可以控制下载哪些应用,访问哪些网站,以及浏览记录审计等。这些一般是通过代理服务器来实现。
image.png
Serverless-Devs是一个组件(插件)化的工具。通过热加载的技术,所有的业务能力都是动态加载执行的。意味着所有的组件开发者可以自由的使用自己的喜欢的库和网络进行交互。如果需要实现上述的代理的能力,不太可能case by case 的去做处理,就需要全局的代理的能力。

HTTP 代理服务器搭建

Squid 是一款广泛用于Linux和Unix平台的代理软件,对于我们实验有几个好处

  • 搭建简单
  • 可以方便查看访问日志,易于观察和验证

在CentOS7安装Squid

sudo yum install squid

安装完成后,启动并启用Squid服务

systemctl start squid
systemctl enable squid

验证是否成功,通过status命令查看

systemctl status squid

修改默认配置

打开squid.conf文件

/etc/squid/squid.conf

允许所有的IP进行代理访问

http_access allow all

允许代理HTTPS请求

创建一个自签名的SSL证书

  1. 转至 Squid 服务文件夹车,并创建SSL证书
$ cd /etc/squid
$ openssl req -new -newkey rsa:2048 -nodes -x509 -keyout bump.key -out bump.crt
  1. 将证书文件转换为 DER 格式的受信任证书以便它可以被导入浏览器中
openssl x509 -in bump.crt -outform DER -out bump.der

配置ssl_bump (适用于3.5.x版本)

http_port 3128 tcpkeepalive=60,30,3 ssl-bump generate-host-certificates=on dynamic_cert_mem_cache_size=20MB cert=/etc/squid/bump.crt key=/etc/squid/bump.key cipher=HIGH:MEDIUM:!LOW:!RC4:!SEED:!IDEA:!3DES:!MD5:!EXP:!PSK:!DSS options=NO_TLSv1,NO_SSLv3,NO_SSLv2,SINGLE_DH_USE,SINGLE_ECDH_USE tls-dh=prime256v1:/etc/squid/bump_dhparam.pem

sslcrtd_program /usr/lib64/squid/ssl_crtd -s /var/lib/squid/ssl_db -M 20MB

sslproxy_cert_error allow all

ssl_bump stare all

全局HTTP代理方案调研

http_proxy环境变量

很多软件都识别http_proxy, https_proxy两个环境变量,比如curl ,wget

  • Linux/Unix和macOS配置
export http_proxy=http://192.168.1.2:3128
export https_proxy=http://192.168.1.2:3128

通过终端输入 env 指令验证是否生效
image.png

  • Windows
set http_proxy=http://192.168.1.2:3128
set https_proxy=http://192.168.1.2:3128

通过access.log 验证 是否生效

squid.gif

我们可以看到配置了http_proxy 环境变量,在本地执行 curl -i [http://www.aliyun.com/serverless](http://www.aliyun.com/serverless) 能够自动代理到代理服务器中。
不过可惜的是Nodejs并不能自动识别这个环境变量

http.Agent

http.Agent 主要是为 http.request, http.get 提供代理服务的,用于管理 http 连接的创建,销毁及复用工作。http.Agent默认使用 http.globalAgent 作为代理,每次请求都是“建立连接-数据传输-销毁连接”的过程,如果我们想让多个请求复用同一个 connection,则需要重新定义 agent 去覆盖默认的 http.globalAgent。基本所有Nodejs 生态的网络请求的库,都支持Agent模式

got

https://github.com/sindresorhus/got/blob/main/documentation/tips.md#proxying

import got from 'got';
import {HttpsProxyAgent} from 'hpagent';

await got('https://sindresorhus.com', {
agent: {
https: new HttpsProxyAgent({
keepAlive: true,
keepAliveMsecs: 1000,
maxSockets: 256,
maxFreeSockets: 256,
scheduling: 'lifo',
proxy: 'https://localhost:8080'
})
}
});

httpx

https://github.com/JacksonTian/httpx

const proxy = require('proxy-agent');
const httpx = require('httpx');

httpx.request('http://www.baidu.com/', {
// pass a http proxy agent
agent: new ProxyAgent("https://yourproxy:123")
});

axios

https://github.com/axios/axios

proxy: {
protocol: 'https',
host: '127.0.0.1',
// hostname: '127.0.0.1' // Takes precedence over 'host' if both are defined
port: 9000,
auth: {
username: 'mikeymike',
password: 'rapunz3l'
}
}

但是很遗憾,在Serverless Devs生态中用到了基本上述的所有的库。不太可能逐一进行修改。

全局代理

本质上所有的请求都是使用下面几个原始的API

const httpGet = http.get;
const httpRequest = http.request;
const httpsGet = https.get;
const httpsRequest = https.request;

所以只需要在程序初始化之前,将http.get 替换为 http.get({agent: proxyAgent}),而这个这个其实就是 我们自己实现统一代理的Agent。global-agent 这个库已经帮我们做了相应的封装
下面是一个简单的Demo示例

const httpx = require('httpx');
const globalAgent = require('global-agent');

globalAgent.bootstrap();
global.GLOBAL_AGENT.HTTP_PROXY = "http://192.168.1.2:3128";
global.GLOBAL_AGENT.HTTPS_PROXY = "http://192.168.1.2:3128";

process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;


httpx.request('http://www.aliyun.com/activity').then((response) => {
response.pipe(process.stdout);
response.on('end', () => {
process.stdout.write('end');
});
}, (err) => {
console.log(err)
// on error
});

通过观察Squid代理的 access.log,验证结果代理是生效的

参考资料

  1. ssl bump 配置

https://support.kaspersky.com/KWTS/6.1/zh-Hans/166244.htm
https://foamzou.com/2017/09/23/squid-proxy-with-ssl-bump/

  1. nodejs全局代理

https://www.npmjs.com/package/global-agent

· 阅读需 4 分钟
丹坤
守帅

在FaaS 的世界中,Nodejs和Python是绝对的王者。Python在运维,AI以及数据处理方面有着非常广泛应用场景。而Nodejs备受前端开发者的青睐。前端的天职是专注于提供更好的用户体验,对服务器运维,高并发,弹性扩展等领域接触不多。有了FaaS后,前端同学只需要专注应用的开发。由于Nodejs应用一般应用在Api Server的web场景。根据网页打开3s打开原则,接口一般要求在1s之内返回,否则整体用户体验会比较糟糕。所以优化启动速度就成了重中之重。

什么是冷启动

谈到FaaS,永远绕不开一个关键词 冷启动,冷启动犹如过街老鼠,各个Serverless的文章都在谈到如何优化冷启动。但是正是由于有了冷启动,我们才能享受FaaS的各种红利。

冷启动带来的好处

拿Nodejs举例,我们知道Nodejs是单线程的模型,这样的架构非常脆弱,一旦主线程有异常或者耗时操作,整个应用就崩溃了,同时也无法很好的利用操作系统的多核能力,提供更好的性能。Nodejs社区提供了cluster 方案,实现了经典的master-worker的架构一方面更好的利用CPU多核能力,另一方面如果某个worker进程崩溃了,Master进程立即重新fork出新的Worker进程,保证服务的稳定性。很多Nodejs应用都会安装 pm2 这样的进程管理工具,例如egg.js 框架通过egg-cluster提供了进程管理的能力

+---------+                 +---------+
| Worker | | Master |
+---------+ +----+----+
| uncaughtException |
+------------+ |
| | | +---------+
| <----------+ | | Worker |
| | +----+----+
| disconnect | fork a new worker |
+-------------------------> + ---------------------> |
| wait... | |
| exit | |
+-------------------------> | |
| | |
die | |
| |
| |

有了FaaS后,就不需要使用上面的cluster模型了。
我们可以看到,每个request请求,FaaS平台都会新建一个单独的新的实例(instance)进行处理
所以多个请求之间并不会发生任何共享和抢占的行为,当然不会因为上一个用户请求异常造成下个用户不可用的情况,也保证了服务的高可用。
image.png

冷启动带来的问题

我们在来详细看下在FaaS平台,Nodejs应用是如何启动的

· 阅读需 2 分钟
丹坤

准备工作

分支及代码

  1. https://github.com/alibaba/nacos 仓库的develop分支 fork到自己的github仓库。
  2. clone到本地,并且新建自己的特性分支进行开发

项目结构

Nacos admin 的代码主要是下面几部分

console-ui工程

通过命令tree -I 'node_modules|dist' -L 1查看项目结构

├── README.md
├── build
├── package-lock.json
├── package.json
├── public
├── src
├── test
└── tsconfig.json

开发

前端技术栈

开发 & 调试

Nacos使用Java进行开发,需要安装Java环境,Maven构建工具等

启动后端服务

# build 构建jar包
mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U
# 以单机的形式启动
./distribution/target/nacos-server-${version}/nacos/bin/startup.sh -m standalone

可以在 ./distribution/target/nacos-server-${version}/nacos/log/start.out 查看启动日志 如果启动成功可以看到下面的界面:

访问 http://127.0.0.1:8848/nacos 可以进入控制台。用户名/密码为 nacos/nacos

至此后端服务启动完成,如果需要 关闭后端服务 执行 ./distribution/target/nacos-server-${version}/nacos/bin/shutdown.sh 即可

启动前端服务

$ cd console-ui  # 进入前端目录
$ npm i # 安装依赖
$ npm start # 本地启动

本地启动或自动打开8000端口: