自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

如何快速創(chuàng)建一個(gè)擁有異步任務(wù)隊(duì)列集群的 Rest Api

開發(fā) 前端
本文分享如何使用 docker-compose、FastAPI、rq 來(lái)快速創(chuàng)建一個(gè)包含異步任務(wù)隊(duì)列集群的 REST API,后端執(zhí)行任務(wù)的節(jié)點(diǎn)可以隨意擴(kuò)展。

異步任務(wù)是 Web 后端開發(fā)中最常見的需求,非常適合多任務(wù)、高并發(fā)的場(chǎng)景。本文分享如何使用 docker-compose、FastAPI、rq 來(lái)快速創(chuàng)建一個(gè)包含異步任務(wù)隊(duì)列集群的 REST API,后端執(zhí)行任務(wù)的節(jié)點(diǎn)可以隨意擴(kuò)展。

系統(tǒng)的架構(gòu)圖:

上圖中的每一個(gè)方框都可以理解為一個(gè)服務(wù)器。

用戶請(qǐng)求 api, api 將任務(wù)放入 redis 隊(duì)列,worker 自動(dòng)去 redis 隊(duì)列取出任務(wù)并執(zhí)行,worker 節(jié)點(diǎn)可以任意水平擴(kuò)展。

接下來(lái),我們來(lái)實(shí)現(xiàn)這一架構(gòu)的 demo,你可以看到 docker 的強(qiáng)大和方便之處。

1、先創(chuàng)建一個(gè)虛擬環(huán)境,安裝依賴

依賴 fastapi,redis,rq 庫(kù),安裝后生成一個(gè) requirements.txt 文件

  1. mkdir myproject 
  2. python3 -m venv env 
  3. source env/bin/activate 
  4. pip install rq 
  5. pip install fastapi 
  6. pip install redis 
  7. pip freeze > requirements.txt 

2、編碼實(shí)現(xiàn) REST API、Worker

REST 是一種風(fēng)格,這里不是重點(diǎn),我們使用 FastAPI 來(lái)快速創(chuàng)建一個(gè)接口,新建一個(gè) api.py 的文件,內(nèi)容如下:

  1. from fastapi import FastAPI 
  2. from redis import Redis 
  3. from rq import Queue 
  4. from worker import send_captcha 
  5. app = FastAPI() 
  6.  
  7. # 需要注意,這里的 host 是主機(jī)名,在 docker 中就是服務(wù)名,后面的 docker-compose.ymal 中的服務(wù)名稱也要是這個(gè) 
  8. redis_conn = Redis(host='myproj_redis', port=6379, db=0) 
  9.  
  10. # 定義一個(gè)隊(duì)列,名稱是 my_queue 
  11. q = Queue('my_queue'connection=redis_conn) 
  12.  
  13. @app.get('/hello'
  14. def hello(): 
  15.     """Test endpoint""" 
  16.     return {'hello''world'
  17.  
  18. # Rest API 示例 
  19. @app.post('/send_captcha/{phone_number}', status_code=201) 
  20. def addTask(phone_number: str): 
  21.     ""
  22.     Adds tasks to worker queue. 
  23.     Expects body as dictionary matching the Group class. 
  24.  
  25.     ""
  26.     job = q.enqueue(send_captcha, phone_number) 
  27.  
  28.     return {'job'"tasks add done."

這里的 send_captcha 函數(shù)就是一個(gè)異步任務(wù),從 worker.py 中導(dǎo)入,worker.py 的內(nèi)容如下:

  1. import time 
  2.  
  3. def send_captcha(phone_number): 
  4.     ""
  5.     模擬一個(gè)耗時(shí)的異步任務(wù) 
  6.     ""
  7.     print(f'{time.strftime("%T")} 準(zhǔn)備發(fā)送手機(jī)驗(yàn)證碼') # in place of actual logging 
  8.     print(f'{time.strftime("%T")} 生成隨機(jī)驗(yàn)證碼并存入 redis,設(shè)置 5 分鐘過(guò)期時(shí)間'
  9.     time.sleep(5) # simulate long running task 
  10.     print(f'{time.strftime("%T")} {phone_number}發(fā)送完成'
  11.     return { phone_number: 'task complete'

return { phone_number: 'task complete'}

3、構(gòu)建 Dokcer 鏡像

現(xiàn)在的目標(biāo)是實(shí)現(xiàn)一個(gè)擁有兩個(gè)執(zhí)行節(jié)點(diǎn)的集群。我們需要啟動(dòng) 4 個(gè)容器來(lái)完成一個(gè)集群部署:

  • 容器1:運(yùn)行 FastAPI app
  • 容器2:運(yùn)行 Redis 服務(wù)
  • 容器3:運(yùn)行 worker 1 服務(wù)
  • 容器4:運(yùn)行 worker 2 服務(wù)

其中容器 1、3、4 都是 Python 應(yīng)用,可以共用一個(gè) Python 鏡像。

為了方便調(diào)試,我們可以讓 1、3、4 容器共享我們的本地路徑,這樣改了代碼就不需要重新構(gòu)建鏡像,比較方便。

創(chuàng)建一個(gè)包含依賴的 Python 鏡像

現(xiàn)在我們來(lái)創(chuàng)建一個(gè)包含前文 requirements.txt 依賴的 Python 鏡像,編寫 Dockerfile,內(nèi)容如下:

  1. FROM python:3.8-alpine 
  2. RUN adduser -D myproj 
  3. WORKDIR /home/myproj 
  4. COPY requirements.txt requirements.txt 
  5. RUN pip install -r requirements.txt 
  6. RUN chown -R myproj:myproj ./ 
  7. USER myproj 
  8. CMD uvicorn api:app --host 0.0.0.0 --port 5057 

內(nèi)容說(shuō)明:

FROM python:3.8-alpine

指定使用 python:3.8-alpine,這個(gè)容器已經(jīng)預(yù)裝了 Python3.8,可以在命令行執(zhí)行 docker search python 看看有哪些 Python 鏡像。

RUN adduser -D myproj

添加一個(gè)用戶 myproj,這一步的主要目的是為了生成目錄 /home/myproj

WORKDIR /home/myproj

設(shè)置程序的執(zhí)行路徑為 /home/myproj

COPY requirements.txt requirements.txt

復(fù)制當(dāng)前路徑下的 requirements.txt 到容器的 /home/myproj,這里沒有復(fù)制 .py 文件是因?yàn)楹竺嫖覀儐?dòng)容器的時(shí)候會(huì)共享本地路徑,不需要再?gòu)?fù)制了,生產(chǎn)部署時(shí)最好復(fù)制到窗口內(nèi)部,這樣容器就不會(huì)依賴本機(jī)。

RUN pip install -r requirements.txt

在容器中安裝依賴

RUN chown -R myproj:myproj ./

將 /home/myproj 路徑下的文件的擁有者和所屬組改為 myproj,這一步為了使用 myproj 用戶來(lái)啟動(dòng) fastapi 服務(wù),生產(chǎn)環(huán)境通常用 root 用戶啟動(dòng),也就不需要這個(gè)指令了。

USER myproj

切換到 myproj 用戶

CMD uvicorn api:app --host 0.0.0.0 --port 5057

容器啟動(dòng)后執(zhí)行的命令,服務(wù)端口為 5057

更多的 Dockerfile 語(yǔ)法請(qǐng)參考官方文檔,這里僅是簡(jiǎn)要說(shuō)明。

現(xiàn)在 Dockerfile 所在的目錄執(zhí)行下面的命令構(gòu)建一個(gè)鏡像:

  1. docker build -t myproject:latest . 

創(chuàng)建完成后,可以使用 docker images 來(lái)查看:

  1. ❯ docker images | grep myproj 
  2. myproject               

4、啟動(dòng)集群

這里使用 Docker Compose 來(lái)啟動(dòng) 4 個(gè)容器,為什么用 Docker Compose 呢?因?yàn)榉奖悖绻挥玫脑?,需要手?dòng)一個(gè)容器一個(gè)容器啟動(dòng)。

Docker Compose 會(huì)讀取一個(gè) yaml 格式的配置文件,依據(jù)配置文件來(lái)啟動(dòng)容器,各容器共享同一網(wǎng)絡(luò)。還記得 api.py 中使用的 Redis 主機(jī)名嗎,這里就需要將 redis 服務(wù)名設(shè)置為那個(gè)主機(jī)名。

編寫一個(gè) docker-compose.yml 內(nèi)容如下:

  1. version: '3' 
  2.  
  3. services: 
  4.   myproj_redis: 
  5.     image: redis:4.0-alpine 
  6.     ports: 
  7.       - "6379:6379" 
  8.     volumes: 
  9.       - ./redis:/data 
  10.  
  11.   myproj_api: 
  12.     image: myproject:latest 
  13.     command: uvicorn api:app --host 0.0.0.0 --port 5057 
  14.     ports: 
  15.       - "5057:5057" 
  16.     volumes: 
  17.       - ./:/home/myproj 
  18.  
  19.   myproj_worker1: 
  20.     image: myproject:latest 
  21.     command: rq worker --url redis://myproj_redis:6379 my_queue 
  22.     volumes: 
  23.       - ./:/home/myproj 
  24.  
  25.   myproj_worker2: 
  26.     image: myproject:latest 
  27.     command: rq worker --url redis://myproj_redis:6379 my_queue 
  28.     volumes: 
  29.       - ./:/home/myproj 

第一個(gè)容器是 myproj_redis,運(yùn)行著 redis 服務(wù), redis 的數(shù)據(jù)通過(guò) volumes 方式保存在本地,因此需要在本地創(chuàng)建一個(gè) redis 目錄,來(lái)映射容器內(nèi)部的 /data 目錄。

第二個(gè)容器就是 fastapi 服務(wù),端口 5057,使用本地路徑映射為 /home/myproj

第三個(gè)容器和第四個(gè)容器是 worker 節(jié)點(diǎn),雖然也映射了本地路徑,但它僅使用 worker.py 文件。當(dāng)任務(wù)太多時(shí),worker 節(jié)點(diǎn)可以擴(kuò)展,解決負(fù)載壓力,

最終的目錄是這樣:

執(zhí)行 docker compose 命令啟動(dòng) 4 個(gè)容器:

  1. docker compose -f docker-compose.yml up 

可以看到 4 個(gè)服務(wù)均啟動(dòng)并正常打印了日志輸出。

4、測(cè)試

現(xiàn)在來(lái)測(cè)試一下,左邊的窗口,我使用 Python 快速發(fā)送了 3 個(gè) post 請(qǐng)求:

  1. import subprocess 
  2. for i in range(3): 
  3.     subprocess.run("curl -v -X POST 'http://localhost:5057/send_captcha/18012345678'",shell = True

從右邊窗口的日志輸出可以看出 worker1 和 worker2 都執(zhí)行了任務(wù),其中 worker1 執(zhí)行了 2 個(gè),worker2 執(zhí)行了 1 個(gè)。

查看完整代碼請(qǐng)點(diǎn)擊「閱讀原文」

最后的話

本文分享了如何使用 Dockerfile 構(gòu)建一個(gè)鏡像,使用 Docker Compose 管理一個(gè)容器集群,以此為基礎(chǔ)實(shí)現(xiàn)了一個(gè)具有異步任務(wù)隊(duì)列集群的 REST API,拋磚引玉,關(guān)于 Dockerfile、docker-compose 的詳細(xì)用法,還請(qǐng)參考 Docker 官方文檔

 

責(zé)任編輯:武曉燕 來(lái)源: Python七號(hào)
相關(guān)推薦

2023-08-01 07:25:38

Expresso框架API

2021-08-10 07:27:42

Elasticsear集群開源

2023-11-19 20:16:43

RESTAPIPOST

2023-04-10 14:20:47

ChatGPTRESTAPI

2020-10-28 17:15:45

Redis前端數(shù)據(jù)庫(kù)

2020-09-29 07:24:14

Python字典數(shù)據(jù)

2010-03-08 16:36:53

攻略備案域名注冊(cè)淘寶網(wǎng)

2024-05-23 11:26:02

2013-07-01 11:01:22

API設(shè)計(jì)API

2023-05-11 12:40:00

Spring控制器HTTP

2024-01-02 13:58:04

GoREST API語(yǔ)言

2020-08-25 07:48:17

Kubernetes集群系統(tǒng)

2023-08-14 09:00:00

APIgRPCREST

2024-10-14 08:46:50

Controller開發(fā)代碼

2020-09-22 07:50:23

API接口業(yè)務(wù)

2023-03-01 09:39:40

調(diào)度系統(tǒng)

2018-06-19 16:04:27

Dubbo應(yīng)用Java

2013-05-02 10:40:24

xcode

2019-11-11 10:45:44

LinuxWindows 10Debian 10

2022-06-21 09:27:01

PythonFlaskREST API
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)