Fastapi is a modern Python web framework for writting web apis. it's fast and featured.
see more detail about fastapi.
this Boilerplate is based on Fastapi framework with some common module for fast python restapi development.
- fully async support: function, database, background task
- celery distribute task support
- distribute request id support
- feature log support
- in-memory zmq support for multi-process task
- async postgresql support
- support sql template programing
- docker support
- api doc
- api test
Fastapi provide a way to give background task, but is not really cover all ways when we develop other web application, the one buildin fastapi is good at io-bound task but not cpu bound task. when we define many io-bound task inside web application, we will make the api server slower. we need some way to make web server and tasks isolation.
even you use UUID4
as request id, it's not suitable for high cocurrent api server. you will get same request id for a batch of requests, it's bad for log analyse and debug.
zmq
gains high performance and is very simple. use zmq to communicate with multiprocess task is a good way.
we usally use zmq queue do tasks:
- send multi-process log to single file
- send multi-process redis writting data using single redis client
docker is a good way to distribute application on different os environment, it makes our final web application deployment easy.
we choose wrk
as a load test tool. it very simple and fast. see more detail inside benchmark.sh
.
aliyun ECS 16C 32G 2.4G with 8 process.
run test 4 threads 300 concurrency with postgres read:
./wrk -t 4 -c 300 -d10s http://127.0.0.1:8000/api/v1/user/list
Running 10s test @ http://127.0.0.1:8000/api/v1/user/list
4 threads and 300 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 66.94ms 49.40ms 604.50ms 73.71%
Req/Sec 1.22k 252.57 1.87k 64.75%
48659 requests in 10.10s, 11.09MB read
Requests/sec: 4819.52
Transfer/sec: 1.10MB
run test 4 threads 300 concurrency with redis write:
./wrk -t 4 -c 400 -d10s http://127.0.0.1:8000/api/v1/user/counter
Running 10s test @ http://127.0.0.1:8000/api/v1/user/counter
4 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 58.08ms 140.53ms 1.05s 94.98%
Req/Sec 4.04k 1.95k 8.53k 66.00%
160779 requests in 10.04s, 31.89MB read
Socket errors: connect 0, read 1820, write 0, timeout 0
Requests/sec: 16012.11
Transfer/sec: 3.18MB
run test 4 threads 300 concurrency with echo server:
./wrk -t 4 -c 400 -d10s http://127.0.0.1:8000/api/v1/user/greeting
Running 10s test @ http://127.0.0.1:8000/api/v1/user/greeting
4 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 33.45ms 77.33ms 1.01s 96.80%
Req/Sec 5.35k 2.66k 12.48k 66.75%
212805 requests in 10.05s, 43.43MB read
Socket errors: connect 0, read 2078, write 0, timeout 0
Requests/sec: 21179.64
Transfer/sec: 4.32MB
we use make tool to manage other web server.
# build the docker container
make build
# test web application
make test
# run docker container
make run
# stop docker container
make stop
you can write you business config inside config.py
file, other environments config use by components you can write it into .envs.production directory, please look at the two sample config file:
- sample.fastapi
- sameple.postgres
config and rename it without sample(.fastapi .postgres) and move it into .envs/.production directory.
if you need to write your own sql function, you need to read the doc first, anosql query options.
- Execute SQL script statements with #
- Insert/Update/Delete Many with *!
- Insert Returning with <!
- Insert/Update/Delete with !
- Flat return single row data with ?
for example:
-- name: publish_blog<!
insert into blogs(userid, title, content) values (:userid, :title, :content);
-- name: insert_many*!
insert into blogs(userid, title, content, published) values (?, ?, ?, ?);