FastAPI 上传和下载文件的基准测试

使用 FastAPI 实现了文件的上传和下载,部署服务使用了 uvicorn 和 gunicorn+uvicorn 两种方法。

基准测试工具使用的是 wrk

服务器 CPU 40核,内存 256G,操作系统 Ubuntu 20.04,Python3.9

测试流程

使用的测试图片 health.jpg (256kb)

生成测试数据

生成通过 HTTP POST 发送二进制数据的文件。

python make_http_postdata.py make health.jpg postdata
file: /home/wjj/test/postdata
boundary: gouchicao0123456789

创建用于 wrk 的 lua 脚本:postfile.lua

wrk.method = "POST"
local f = io.open("postdata", "rb")
wrk.body   = f:read("*all")
wrk.headers["Content-Type"] = "multipart/form-data; boundary=gouchicao0123456789"

部署 FastAPI 应用 uvicorn uvicorn app.

Install Python3.9 in Ubuntu20.04

问题

基于之前安装 Python3.8 的经验,运行下面的命令就可以成功安装 Python3.9 和 pip,但是这回失败了。

sudo apt install build-essential python3.9 python3.9-dev -y
sudo ln -s /usr/bin/python3.9 /usr/bin/python
curl https://bootstrap.pypa.io/get-pip.py | sudo python -
Traceback (most recent call last):
  File "/home/lnsoft/wjj/get-pip.py", line 33324, in <module>
    main()
  File "/home/lnsoft/wjj/get-pip.py", line 135, in main
    bootstrap(tmpdir=tmpdir)
  File "/home/lnsoft/wjj/get-pip.py", line 111, in bootstrap
    monkeypatch_for_cert(tmpdir)
  File "/home/lnsoft/wjj/get-pip.py", line 92, in monkeypatch_for_cert
    from pip._internal.commands.install import InstallCommand
  File "<frozen zipimport>", line 259, in load_module
  File "/tmp/tmpcw3afq6v/pip.zip/pip/_internal/commands/__init__.py", line 9, in <module>
  File "<frozen zipimport>", line 259, in load_module
  File "/tmp/tmpcw3afq6v/pip.zip/pip/_internal/cli/base_command.py", line 15, in <module>
  File "<frozen zipimport>", line 259, in load_module
  File "/tmp/tmpcw3afq6v/pip.zip/pip/_internal/cli/cmdoptions.py", line 23, in <module>
  File "<frozen zipimport>", line 259, in load_module
  File "/tmp/tmpcw3afq6v/pip.zip/pip/_internal/cli/parser.py", line 12, in <module>
  File "<frozen zipimport>", line 259, in load_module
  File "/tmp/tmpcw3afq6v/pip.zip/pip/_internal/configuration.py", line 26, in <module>
  File "<frozen zipimport>", line 259, in load_module
  File "/tmp/tmpcw3afq6v/pip.zip/pip/_internal/utils/logging.py", line 27, in <module>
  File "<frozen zipimport>", line 259, in load_module
  File "/tmp/tmpcw3afq6v/pip.zip/pip/_internal/utils/misc.py", line 39, in <module>
  File "<frozen zipimport>", line 259, in load_module
  File "/tmp/tmpcw3afq6v/pip.zip/pip/_internal/locations/__init__.py", line 14, in <module>
  File "<frozen zipimport>", line 259, in load_module
  File "/tmp/tmpcw3afq6v/pip.zip/pip/_internal/locations/_distutils.py", line 9, in <module>
ModuleNotFoundError: No module named 'distutils.cmd'

阿里云服务器 ECS 开放端口

开放端口设置

配置路径

配置规则

授权策略 优先级 协议类型 端口范围 授权对象 描述
允许 1 自定义 TCP 目的:5000/5000 源:0.0.0.0/0 Flask
允许 1 自定义 TCP 目的:8000/8000 源:0.0.0.0/0 FastAPI

问题

今天通过上面的配置后,发现不能访问,上网搜索了半天,看到有说需要配置 iptables ,于是开始了一顿搜索和学习(Linux上iptables基础应用),进行了如下配置,发现还是访问不了。

iptables -A INPUT -p tcp --dport 5000 -j ACCEPT
iptables -A INPUT -p tcp --dport 8000 -j ACCEPT

解决

突然想到了 Web 应用服务器的配置 --host,我这里用的是 uvicorn,默认使用的 127.0.0.1,这样只能接收本机的访问,需要接收其它主机的访问就需要配置为 0.0.0.0。

Web 应用服务器的配置

  • uvicorn --host 0.0.0.0
  • gunicorn --bind 0.0.0.0

最后测试了一下,发现根本不需要使用 iptables 配置。

参考资料

命令 nc

捕获 HTTP 请求的内容

  1. 监听端口,用于捕获数据。
nc -l port 
  1. 发送 HTTP 请求。
curl http://ip:port/

GET 请求

curl http://127.0.0.1:8000/
GET /?name=wjj HTTP/1.1
Host: 127.0.0.1:8000
User-Agent: curl/7.61.1
Accept: */*

POST JSON 请求

curl --location --request POST 'http://127.0.0.1:8000/users_by_json' \
--header 'Content-Type: application/json' \
--data-raw '{
    "name": "wjj",
    "age": 40
}'
POST /users_by_json HTTP/1.1
Host: 127.0.0.1:8000
User-Agent: curl/7.61.1
Accept: */*
Content-Type: application/json
Content-Length: 36

{
    "name": "wjj",
    "age": 40
}

基于健康码识别的 FastAPI 同步和异步函数的基准测试

健康码识别服务使用了 FastAPI 进行开发的,本周主要工作是为了对健康码识别的服务进行性能调优。接口函数使用了 async 关键字,但是内部的实现并没有使用 await。由于改写成异步代码需要时间,这里并没有改写代码,只是删除了 async 关键字。部署服务使用了 uvicorn 和 gunicorn+uvicorn 两种方法。

基准测试工具使用的是 ab

测试流程

生成测试数据

准备测试图片 health.jpg

echo -n '{"base64": "' > health.json
base64 -w0 health.jpg >> health.json
echo -n '"}' >> health.json

部署服务

uvicorn

docker run --runtime=nvidia --rm -it -e NVIDIA_VISIBLE_DEVICES=2 -p 20001:8000 \
    -v $(pwd):/health_code_service --name=health-uvicorn  health-code-service \
    uvicorn controller:app --host 0.0.0.0 --workers 1
  • workers 并发进程数

HTTP 基准测试工具

wrk

wrk 使用的是 HTTP/1.1

安装

需要从 GitHub 上克隆代码自己编译,编译前需要安装 git, gcc。

git clone https://github.com/wg/wrk.git
cd wrk
#使用多线程(机器的处理器核数)加速编译,
make -j $(nproc)
cp wrk /usr/local/bin/

测试

10 个线程,保持打开 100 个并发连接,持续 10 秒。

wrk -t10 -c100 -d10 http://www.baidu.com/
Running 10s test @ http://www.baidu.com/
  10 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   138.46ms  219.05ms   1.89s    92.11%
    Req/Sec   128.07     79.83   700.00     94.40%
  12776 requests in 10.02s, 128.22MB read
  Socket errors: connect 0, read 57, write 0, timeout 3
Requests/sec:   1275.30
Transfer/sec:     12.80MB

打印详细的延时分布信息 wrk -c10 -t4 --latenc

阿里云 yum 安装应用报 404 错误

今天登录阿里云安装应用出现 404

问题

yum install install httpd-tools -y
CentOS-8 - AppStream                                                                                                                                                                      9.6 kB/s | 2.3 kB     00:00    
Errors during downloading metadata for repository 'AppStream':
  - Status code: 404 for http://mirrors.cloud.aliyuncs.com/centos/8/AppStream/x86_64/os/repodata/repomd.xml (IP: 100.100.2.148)
错误:为 repo 'AppStream' 下载元数据失败 : Cannot download repomd.xml: Cannot download repodata/repomd.xml: All mirrors were tried

解决方案 cd /etc/yum.repos.d/ find . -name '.repo' -exec sed -i 's/mirrors.cloud.aliyuncs.com/mirrors.aliyun.com/g' {} + find . -name '.

Python 自动生成周报

安装依赖库

pip install typer python-docx

编写生成个人周报的应用 制作个人周报模版 个人周报-{}-{}.xlsx 编写应用 weekly.py import shutil import openpyxl import typer from datetime import datetime, timedelta def get_weekly_info(): now = datetime.now() # 工作表的标题,格式: yymmdd(周一)-yymmdd(周五) monday = now-timedelta(now.weekday()) friday = monday+timedelta(4) sheet_title = '{}-{}'.format(monday.strftime('%y%m%d'), friday.strftime('%y%m%d')) # 报告日期,格式: yyyy/mm/dd(周四) report_date = now.strftime("%Y/%m/%d") # 计划的开始时间与结束时间 base_date = datetime(1899, 12, 30, 0, 0) work_tasks_begin_time = (monday-base_date).

Python办公自动化套件

操作 Word 文档

安装依赖库 python-docx

pip install python-docx

示例 from docx import Document from docx.shared import Inches document = Document() document.add_heading('Document Title', 0) p = document.add_paragraph('A plain paragraph having some ') p.add_run('bold').bold = True p.add_run(' and some ') p.add_run('italic.').italic = True document.add_heading('Heading, level 1', level=1) document.add_paragraph('Intense quote', style='Intense Quote') document.

Dockerfile 实践

系统

指定本地时区

FROM ubuntu:20.04
LABEL maintainer="wang-junjian@qq.com"

ARG TIME_ZONE=Asia/Shanghai
RUN DEBIAN_FRONTEND=noninteractive apt-get install tzdata -y && \
    ln -fs /usr/share/zoneinfo/$TIME_ZONE /etc/localtime && \
    echo $TIME_ZONE > /etc/timezone

Python 开发环境 构建 Python, OpenCV 开发环境的镜像 FROM ubuntu:20.04 LABEL maintainer="wang-junjian@qq.com" # 设置 apt 源(阿里云),设置完必须 update。 RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.

构建基于PaddlePaddle开发服务镜像

构建镜像

FROM paddlepaddle/paddle:2.2.2-gpu-cuda10.2-cudnn7
LABEL maintainer="wang-junjian@qq.com"

RUN apt-get update && apt-get install libjpeg-dev zlib1g-dev -y

RUN pip install -i https://mirrors.aliyun.com/pypi/simple/ \
    numpy fastapi paddleocr opencv-python

EXPOSE 20000

WORKDIR /inference-serving
ADD . ./

CMD ["python", "app.py"]

官方推荐:非安培架构的GPU,推荐使用CUDA10.2,性能更优。

自己构建 paddlepaddle 镜像

通过官方的 Docker Hub 没有找到 runtime 版本,想着节省几个G的空间,于是考虑自己来构建。

我删库了, rm -rf *

今天,我“删库”了......

/data$ ll logs/
rm -rf *

我在根目录查看子目录的信息,确认是想删除的数据,然后顺手执行了 rm -rf * ,杯具产生了......

拼命补救,没成功......

查看目录或文件的 inode id

$ ls -id /
2 /

$ ls -id /usr/
28966913 /usr/

$ ls -id /usr/bin/bash
28967390 /usr/bin/bash

参考资料

MinIO Quickstart

使用容器的方式部署 MinIO

Standalone

docker run --rm \
  -p 9000:9000 \
  -p 9001:9001 \
  --name minio \
  -v /data/minio/data:/data \
  -e "MINIO_ROOT_USER=admin" \
  -e "MINIO_ROOT_PASSWORD=12345678" \
  minio/minio server /data --console-address ":9001"
API: http://172.17.0.2:9000  http://127.0.0.1:9000 

Console: http://172.17.0.2:9001 http://127.0.0.1:9001 

Documentation: https://docs.min.io

单机分布式 # 创建4个目录 mkdir -p /data/minio/erasure-code/data{1..