将webserver部署到公网(使用阿里云服务器)
阿里云轻量应用服务器介绍
这里我是用的是阿里云进行部署,阿里云推出的相关产品包括 云服务器 ECS 和轻量应用服务器。阿里云的指引和说明我觉得还是比较清楚详细的,适合新手。
先来介绍相关的一些名词:
- 云服务器 ECS(Elastic Compute Service,弹性计算服务)是阿里云提供的一种基础云计算服务,类似于虚拟机。它可以通过互联网进行访问并且具有高度的灵活性和扩展性。
- VPC(Virtual Private Cloud,虚拟私有云) 是一种可以让用户在公有云上创建一个独立隔离的网络环境的服务。VPC提供了类似于传统数据中心的网络管理功能,但在云中实现。
- 安全组:类似于防火墙,用户可以设置安全组规则来控制对 ECS 的访问。
那么这两者有什么区别?如何进行选择?
贴出阿里云官网给出的介绍:选轻量应用服务器or云服务器ECS?一图帮你彻底区分-阿里云开发者社区
简单来说,轻量应用服务器 适合个人开发者、学生,针对的应用场景轻量级且访问量较低,可以快速上手,经济实用,同时资源有限,支持的功能也更少;后者支持和可以自定义的功能更多更加灵活,可以覆盖绝大多数的业务场景(如大数据分析,深度学习等)。对于我们这个项目来说,使用前者就够了。
创建轻量应用服务器
我创建的服务器基本配置如下:价格是 67 R/月
创建好以后,设置密码。
永久修改云服务器主机名
打开 /etc/hostname
文件:
sudo nano /etc/hostname
将文件中的内容修改为你想要的主机名即可。
或者使用hostnamectl
命令来更改主机名,这种方法会自动更新相关配置文件。
sudo hostnamectl set-hostname [new_hostname]
重启系统以确保主机名在所有会话中生效:
sudo reboot
重启后检查主机名:
hostname
使用密钥对远程登录云服务器
管理密钥对(Linux):阿里云 SSH 密钥对是一种安全便捷的登录认证方式,用于在 SSH 协议中进行身份验证和加密通信。为轻量应用服务器绑定密钥对后,服务器会自动禁止使用用户及密码登录。
创建并绑定密钥对:
系统将自动下载密钥信息(文件后缀名为
.pem
)至本地主机,密钥仅有这一次下载机会,请妥善保管。
我将下载后的.pem
文件保存在/keypair
文件夹下面,命名为myWebserver.pem
修改私钥文件权限:
chmod 400 ~/keypair/myWebserver.pem
使用 SSH 远程连接 Linux 服务器:([] 中的内容自行替换)
ssh -i [~/path_to/x.pem] root@[服务器公网ip]
执行上面的指令后,可能提示:
The authenticity of host ‘xxxx’ can’t be established.
…
Are you sure you want to continue connecting (yes/no/[fingerprint])?
这是首次连接时的正常安全检查,输入 yes
即可。
成功连接后,显示:
Welcome to Alibaba Cloud Elastic Compute Service !
基本操作:
查看目录内容:ls -a
查看系统版本:uname -a
查看磁盘使用情况:df -h
查看内存使用情况: free -h
使用 exit
或者 Ctrl + D
断开远程链接。
将 Webserver 部署到远程服务器
本地主机连接远程服务器以后,更新系统软件包:
sudo apt-get update # 更新软件包列表
sudo apt-get upgrade # 升级所有已安装的软件包
安装 C++ 编译工具:
sudo apt-get install build-essential
安装数据库开发包:
sudo apt-get install libmysqlclient-dev
将本地服务器项目传输到远程服务器。
scp -r [/path/to/your/webserver_project] root@[ip]:/home/root/
因为我把我的项目上传到了 github ,所以这里我直接通过 git 克隆项目到远程服务器上了。
# 远程服务器安装 git
apt install gitgit clone https://github.com/bhu619/myWebserver.git
克隆完了以后,还要像之前在本地部署时一样,配置数据库,参考我的另一篇文章:0. 配置安装
配置好数据库以后,别忘记在 myWebserver
中的 main.cpp
文件中修改密码:
编译:
sh ./build.sh
编译通过以后,在阿里云服务器上启动 Web 服务器,让它监听公网 IP 地址:
./server &
&
符号表示将该命令放到后台执行,这样你可以在不占用当前终端的情况下运行程序。终端会返回该进程的 PID。
查看后台进程:jobs
web 服务器跑起来以后,通过公网 ip+端口号访问一下:
http:://[ip]:[port]
别忘了,我们的默认端口号是 9006
。
http 错误码为 502,即“502 Bad Gateway”,通常表示服务器在作为网关或代理时,从上游服务器收到无效响应。猜测是云服务器防火墙设置的原因,找到如下位置,新建防火墙模板即可。
应用防火墙模板后,重新进入服务器,成功~。
设置开机自启动
在云服务器上将数据库和 Web 服务器设置为开机自启动。
设置 MySQL 数据库开机自启动
确保 MySQL 已安装并且可以启动:
sudo systemctl start mysql
通过创建 Systemd 服务设置 MySQL 服务为开机自启动:
Systemd 是一种 Linux 系统初始化系统和服务管理器,它的主要功能是用于启动、停止和管理系统服务。取代了传统的 SysV init 系统。
sudo systemctl enable mysql
设置 Web 服务器开机自启动
我们的 Web 服务器没有内置服务文件,你可以创建一个 Systemd 服务文件,并将它设为开机自启动。
sudo nano /etc/systemd/system/mywebserver.service
填写服务文件基本配置内容:
[Unit]
Description=My Custom Web Server
After=network.target[Service]
ExecStart=/root/myWebserver/server
Restart=always
User=root
WorkingDirectory=/root/myWebserver[Install]
WantedBy=multi-user.target
刷新 Systemd
配置:
sudo systemctl daemon-reload
启用 web 服务器开机自启:
sudo systemctl enable mywebserver
检查是否设置成功:
systemctl is-enabled mywebserver
启动服务:
sudo systemctl start mywebserver
检查服务状态(确保服务正常启动):
sudo systemctl status mywebserver
这样设置完以后,每次重启云服务器,webserver 都会开机自启动了。
域名
现在可以通过 公网 IP 地址 + 端口号的方式访问 web 服务器了。
- 公网 IP 地址指定了互联网上的唯一一台主机;
- 端口号表示这台主机上运行的一个应用程序或者服务。
通常我们访问一个网页不是通过 IP 地址+端口号这种形式来访问的,而是通过域名的形式,域名其实就是 IP 地址的字符串形式, 当用户在浏览器中输入域名时,域名系统(Domain Name System, DNS) 会将域名解析成对应的 IP 地址,从而定位到服务器并加载网页内容。
阿里云也支持域名购买服务:万网-阿里云旗下品牌
注意,这里有的域名只是首次购买便宜,后期续费就会比较贵了,所以不要单纯只看首年价格,除非你确定之后不打算续费了。
我购买的是.cn
英文域名,首年 15 ,之后续费的话是三十几。
首次使用的话,还需要完成实名认证,域名过户等操作,这里等待审核需要花费一点时间。
审核完成后,就可以把域名添加到服务器并等待域名解析了。域名备案请在实名认证成功后,等待至少 3 天信息同步后操作,备案成功后域名才可以对外提供服务。
为域名配置 SSL 证书
阿里云提供个人免费办的 SSL 证书申请。
使用域名和端口号访问 WebServer
因为应用程序在非标准端口(9006)上运行,不能直接访问 http://bhu619.cn
。因此,可以在访问时显式指定端口号:
http://bhu619.cn:9006/
这样,浏览器会自动解析 bhu619.cn
域名并指向 IP 地址 xxx.xxx.xxx.xxx
,再加上端口号 9006
,最终访问 xxx.xxx.xxx.xxx:9006
上的 Web 应用程序。
配置反向代理以隐藏端口号
如果希望使用指定端口(例如 80 , 443 或 9006) 访问应用程序,而不显示端口号,可以在服务器上配置一个反向代理(如 Nginx 或 Apache):
安装 Nginx(假设使用 Nginx):
sudo apt update
sudo apt install nginx
配置反向代理: 打开 Nginx 配置文件 /etc/nginx/sites-available/default
或新建一个配置文件,将 bhu619.cn
的请求代理到 localhost:9006
。
在 /etc/nginx/sites-available/
目录下创建一个新配置文件 bhu619.cn
:
sudo nano /etc/nginx/sites-available/bhu619.cn
在文件中添加以下内容,将所有来自 bhu619.cn
的请求代理到 localhost:9006
:
server {listen 80;server_name bhu619.cn www.bhu619.cn;# 将请求转发到本地的 Web 服务端口(例如 9006)location / {proxy_pass http://127.0.0.1:9006;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;}
}
配置说明:
listen 80;
:监听 80 端口(HTTP 默认端口),这样用户可以直接通过http://bhu619.cn
访问而无需指定端口。+listen 80;
:监听 80 端口(HTTP 默认端口),这样用户可以直接通过http://bhu619.cn
访问而无需指定端口。server_name
:指定此虚拟主机的域名。+server_name
:指定此虚拟主机的域名。proxy_pass http://127.0.0.1:9006;
:将请求转发到localhost:9006
,即 Web 服务的实际端口。+proxy_pass http://127.0.0.1:9006;
:将请求转发到localhost:9006
,即 Web 服务的实际端口。proxy_set_header
:用于设置一些请求头信息,帮助服务器识别客户端的真实 IP 地址和请求来源。+proxy_set_header
:用于设置一些请求头信息,帮助服务器识别客户端的真实 IP 地址和请求来源。
通过创建符号链接将新配置文件添加到 sites-enabled
目录,以启用该站点:
sudo ln -s /etc/nginx/sites-available/bhu619.cn /etc/nginx/sites-enabled/
使用 nginx -t
命令来检查配置文件的语法是否正确:
sudo nginx -t
重启或重新加载 Nginx,使配置生效:
sudo systemctl reload nginx
现在,打开浏览器,访问 http://bhu619.cn
。Nginx 会将该请求转发到 localhost:9006
,不需要在 URL 中显式指定端口号。
但是目前我还没有进行网站备案,所以还是无法访问。。。
压力测试
webbench 的下载和配置参考:压力测试
./webbench -c 4821 -t 5 http://127.0.0.1:9006/
这个命令的目标是在短时间内模拟大量客户端连接,以评估服务器在高并发下的响应性能。
-c 4821
: 这表示模拟 4821 个客户端同时向目标服务器发送请求。这是并发客户端的数量。-t 5
: 表示压力测试的持续时间为 5 秒。
Speed=400128 pages/min
:
- 每分钟请求的页面数是 400,128 个,服务器在测试期间表现良好,处理请求的速率很高。
- 页面数表示服务器响应的 HTTP 请求数量。
746726 bytes/sec
:
- 每秒钟传输的数据量为 746,726 字节。这是测试期间服务器处理的总字节数除以总时间(以秒为单位)的结果。
- 可以理解为数据传输的吞吐量。
Requests: 33344 succeed, 0 failed
:
- 总共成功处理了 33,344 个请求,且没有请求失败,所有请求都得到了成功响应,没有超时或错误的情况。
./webbench -c 4822 -t 5 http://127.0.0.1:9006/
遇到如下报错:
problems forking worker no. 4821
fork failed.: Resource temporarily unavailable
这是因为系统无法为第 4821 个工作进程创建新的子进程,通常由于系统资源不足导致。
可能的原因:
- OS 对每个用户或每个会话的最大进程数量有限制,使用
ulimit -u
查看当前限制:
因此性能瓶颈并不是出现在这里。
- 内存或者 CPU 资源不足:使用
top
指令或者htop
指令(用于监控系统性能的常用命令行工具)查看系统资源使用情况:
在 Linux 系统中,top
或 htop
等工具显示的 CPU 使用率是基于单个核心的百分比。一个核心的使用率上限是 100
,我使用的云服务器核心数为 2,理论上的总体 CPU 使用率上限是 200%。截图显示 Web 服务器进程的 CPU 使用率超过 100%,这表示它在大量占用一个核心,且部分使用了另一个核心的资源。此外,系统的平均负载 Load average
在 5 分钟和 15 分钟内分别达到了 13.20
和 11.09
,这是一个非常高的负载,远超过 2 核 CPU 的承载能力,这表明系统过载。当系统的负载平均值较高时,表示有更多任务在等待 CPU 资源,即 Web 服务器需要处理的请求数量超过了系统的处理能力。
之前我们有提到过线程池和数据库连接池的大小如何确定:[如何在设计时确定线程池的大小] [如何在设计时确定数据库连接池的大小],简单来说:
线程池 = 数据库连接池 = N c p u × 2 线程池 = 数据库连接池 = N_{cpu} × 2 线程池=数据库连接池=Ncpu×2
实际使用时,我们需要匹配 CPU 和内存资源 以及 线程池和数据库连接池 的大小,避免线程频繁切换带来的额外开销。我们将线程池和数据库连接池的大小降低为 4,重新试试:./server -s 4 -t 4
实际我在我的 8 核(4CPU,每个 CPU 有 2 个内核)虚拟机上测试服务器,~~也只能支持 8100 左右的最大并发请求数量。~~增加了最大文件描述符数量以后,可以支持 20, 000 以上的并发。
结果是并没有多大区别,依旧只能跑最多 4800 左右的请求。。 我在虚拟机和云服务器上修改最大线程数,结果对性能并没有明显的改变,修改日志模式,触发模式,对性能的影响都不大。
其他压测软件
Apache Benchmark
ab
(Apache Benchmark) /əˈpætʃi/
是一个轻量级的命令行工具,用于对 Web 服务器进行简单的负载和压力测试。它可以快速评估服务器在高并发请求下的性能。
安装:
sudo apt-get install apache2-utils
ab
命令的基本格式如下:
ab [options] URL
以下是一些常用的 ab
命令选项:
-n [requests]
:
总请求数,表示 ab
将发送的请求数量。例如,-n 1000
表示发送 1000 个请求。
-c [concurrency]
:
并发请求数,表示同时执行的请求数量。例如,-c 50
表示每次并发 50 个请求。 [Range 0…20000]
-t [seconds]
:
测试持续时间,以秒为单位。例如,-t 30
表示持续 30 秒的测试。
-H [header]
:
添加自定义的 HTTP 头部信息。例如,-H "Accept-Encoding: gzip"
,可以模拟请求时的 HTTP 头部。
-p [file]
:
指定一个文件,包含要发送的 HTTP POST 数据。
-T [content-type]
:
设置请求的 Content-Type
,通常与 -p
结合使用,例如 -T "application/json"
。
-A [username:password]
:
设置基本认证的用户名和密码。
-k
:
启用 HTTP Keep-Alive,默认情况下每次请求会关闭连接,而 -k
则保持连接。
例如,如果你想对本地服务器的端口 9006
上的进行压力测试,可以运行:
ab -n 10000 -c 50 http://127.0.0.1:9006/
结果显示:
This is ApacheBench, Version 2.3 <$Revision: 1843412 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/Benchmarking 127.0.0.1 (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requestsServer Software:
Server Hostname: 127.0.0.1
Server Port: 9006Document Path: /
Document Length: 49 bytesConcurrency Level: 50
Time taken for tests: 7.751 seconds
Complete requests: 10000
Failed requests: 0
Non-2xx responses: 10000
Total transferred: 1120000 bytes
HTML transferred: 490000 bytes
Requests per second: 1290.20 [#/sec] (mean)
Time per request: 38.754 [ms] (mean)
Time per request: 0.775 [ms] (mean, across all concurrent requests)
Transfer rate: 141.12 [Kbytes/sec] receivedConnection Times (ms)min mean[+/-sd] median max
Connect: 0 5 67.7 0 1025
Processing: 0 9 193.3 1 6720
Waiting: 0 9 193.3 1 6720
Total: 0 14 243.3 1 7744Percentage of the requests served within a certain time (ms)50% 166% 175% 180% 190% 195% 298% 499% 5100% 7744 (longest request)
报告解读
一、工具信息
版本及版权:使用的是 ApacheBench 工具,版本为 2.3
二、测试目标信息
被测试服务器:服务器 IP 地址为 127.0.0.1(本地回环地址),服务器软件未明确给出具体名称,主机名为 127.0.0.1,端口号为 9006。
测试的文档:文档路径为 “/”,文档长度为 49 字节。
三、测试配置信息
并发级别:设置的并发级别为 50,即同时发起请求的数量为 50 个。
四、测试结果总体情况
请求完成情况:总共完成了 10000 个请求,其中失败请求数为 0,所有请求都成功完成。
数据传输量:总共传输的数据量为 1120000 字节,其中 HTML 传输量为 490000 字节。
五、性能指标情况
每秒请求数(吞吐量):平均每秒能够处理 1290.20 个请求(Requests per second),这是衡量服务器处理请求能力的一个重要指标,数值越高表示服务器在单位时间内能够处理的请求越多。
每个请求的处理时间:平均每个请求的处理时间为 38.754 毫秒(Time per request,mean),这反映了从客户端发起请求到收到完整响应所花费的平均时间。
平均每个并发请求的处理时间为 0.775 毫秒(Time per request,mean, across all concurrent requests),这个指标从并发角度看每个请求的平均处理耗时。
传输速率:接收端的传输速率为 141.12 Kbytes/sec,表示数据从服务器传输到客户端的平均速度。
六、连接时间分析
连接阶段:连接阶段的最小时间为 0 毫秒,平均时间为 5 毫秒,标准差为 67.7 毫秒,中位数为 0 毫秒,最长连接时间为 1025 毫秒。
处理阶段(包含等待时间):处理阶段的最小时间为 0 毫秒,平均时间为 9 毫秒,标准差为 193.3 毫秒,中位数为 1 毫秒,最长处理时间为 6720 毫秒。这里的处理时间包含了服务器等待资源、执行相关业务逻辑等的时间,等待时间与处理时间的统计数据相同,说明在整个处理过程中等待是主要的耗时部分。
总时间:从发起连接到完成处理的总时间,最小为 0 毫秒,平均为 14 毫秒,标准差为 243.3 毫秒,中位数为 1 毫秒,最长总时间为 7744 毫秒。
七、请求在不同时间内完成的百分比
50% 的请求在 1 毫秒内完成。
66%、75%、80% 的请求也都在 1 毫秒内完成。
90% 的请求在 2 毫秒内完成。
95% 的请求在 4 毫秒内完成。
98% 的请求在 5 毫秒内完成。
100% 的请求在最长 7744 毫秒内完成(即最慢的那个请求所花费的时间)。
记录我的压测结果
在 8 核 CPU 虚拟机中,使用 Apache Benchmark 测试,上万是没什么问题的,测试一下服务器的极限:设定请求总数为 20000,并发请求为 20000,10s 内完成 13, 975 个请求,说明 10 秒内服务器无法处理所有请求,到达极限以后需要延迟请求处理;
设定请求总数为 20000,并发请求为 14000,14s 内完成 46,689 个请求,表明服务器在超过预期时间的情况下,仍然保持稳定,处理了额外的请求。
设定请求总数为 20000,并发请求为 18000,10s 内完成 18,912 个请求,几乎达到了设定的 20,000 个请求目标。由于 -t 10
限制的测试时长,服务器在 10 秒内并未能完全完成 20,000 请求,但接近完成。
说明这个 web 服务器在我的虚拟机中,短时间内最高支持大约 18000 的并发负载。
虽然能够处理 18,000 的瞬时并发连接,但如果需要长期维持该并发量,建议进行更长时间的测试以确保稳定性。
阿里云上也支持大约 14, 000 的短时并发:
在压测云服务器时,发现这样一个现象,短时支持的并发量可以很高(14000),但是长时间的并发量就很低了(大约就 100 ),这是为何?这是许多系统在高并发测试中常见的现象:短时间内能承受高并发负载,但长时间持续高并发时性能下降。导致这种情况的原因可能涉及多个方面,比如短时间高并发可以使用缓存、临时内存这种系统资源,但是随着时间增加,这类资源会被耗尽,又比如并发连接没有及时关闭,连接堆积也会导致请求响应变慢(毕竟线程池和数据库连接池就这么大),这也就是为什么需要做一个定时器来处理非活动连接。
这也是后续可以考虑优化的地方:设置合理的资源回收机制、优化系统参数(系统最大文件描述符、最大进程)、防止内存等资源泄漏。
后续
- 为了确保安全访问,考虑为
bhu619.cn
配置 SSL(HTTPS)
总结
以上配置完成后,用户可以通过 http://bhu619.cn
或 https://bhu619.cn
(如果启用了 HTTPS)访问 Web 服务器,Nginx 会将请求反向代理到 localhost:9006
,从而隐藏了实际端口。