您好,登錄后才能下訂單哦!
這期內容當中小編將會給大家帶來有關基于 Serverless 的舞萌音游查分器是怎樣的,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
一、什么是 Serverless Framework
Serverless Framework
是業界非常受歡迎的無服務器應用框架,開發者無需關心底層資源即可部署完整可用的Serverless
應用架構。Serverless Framework
具有資源編排、自動伸縮、事件驅動等能力,覆蓋編碼、調試、測試、部署等全生命周期,幫助開發者通過聯動云資源,迅速構建Serverless
應用
沒錯,就像幾天前看到的《Serverless 之歌》里面所說 I'm gonna reduce your ops
,它能大幅度減輕運維壓力,那就開始動手吧!注意開發環境需 Node.js 10.0+
,一鍵全局安裝:npm install -g serverless
二、騰訊云 Flask Serverless Component 簡介
騰訊云
Flask Serverless Component
,支持Restful API
服務的部署
按照慣例首先來部署 demo
吧
本地 PyCharm
創建一個新的 Flask
項目
手動創建內容為 Flask
的 requirements.txt
按照配置文檔創建 serverless.yml
,例如本項目實際使用的完整內容,初次使用可自行酌情簡化
將密匙寫入 .env
(當然,部署的時候也可以選擇微信掃碼授權)
TENCENT_SECRET_ID=<rm> TENCENT_SECRET_KEY=<rm>
這樣基于 Serverless
的 Flask Demo
就部署完成了,接下來繼續按照自己的方式寫剩下的代碼。
三、maimai_DX
maimai 是一款街機音游。
在這里放一張動圖自行體會一下,原始素材來自「外錄 maimai」QZKago Requiem Re:MASTER ALLPERFECT Player: Ruri*R
日本官網
海外官網
在國內,只能從微信公眾號中查看成績,而且每次進頁面都需要微信的授權登錄,并且里面存儲的記錄有條數限制,相冊
只存最新 10 條,游戲記錄
只存最新 50 條(就是一個隊列,先進先出的那種)。這就是本項目的初衷,自己打出來的每一次成績都應該保存好。
成果展示了,前端 Fomantic-UI
,后端 Flask
+MySQL
。gh
開源地址:https://github.com/yuangezhizao/maimai_DX_CN_probe,歡迎 watch
、star
、fork
& pr
!
目前實裝了如下功能:
wechat_archive中包含 主頁
,游戲數據
,相冊
和 游戲記錄
:對原始網頁進行了修改,并且添加了 Highcharts
庫可視化曲線顯示變化
record包含 記錄(分頁)
和 差異(分頁)
:即自寫的快速預覽頁面,是查看歷史記錄和成績變化的非常實用的功能
info包含 鋪面列表
:即全部鋪面基礎信息,輸出到一個頁面中,方便頁面內搜索
接下來將按照時間的順序,描述一下開發過程中遇到的問題以及如何解決
Serverless Framework Component
配置文件Serverless Framework
現在是 V2
版本,也就是說不能沿襲之前版本的 serverless.yml
配置文件,需要重新對照文檔修改。
a. 之前版本會根據 requirements.txt
自動下載第三方庫到項目目錄下的 .serverless
文件夾下的 requirements
文件夾以參加最終的依賴打包,壓縮成 zip
文件再最終上傳至云函數運行環境
b. 最新版本不再自動下載,需要自行處理。官方示例的參考用法:hook
src: # TODO: 安裝python項目依賴到項目當前目錄 hook: 'pip3 install -r requirements.txt -t ./requirements' dist: ./ include: - source: ./requirements prefix: ../ # prefix, can make ./requirements files/dir to ./ exclude: - .env - 'requirements/**'
注釋寫的很清楚,使用 hook
去根據 requirements.txt
下載第三方庫到項目目錄下的 requirements
文件夾,避免第三方庫導致本地文件夾管理混亂。然后 include
中指定了項目目錄下的 requirements
文件夾在云端的 prefix
,即對于云端的云函數運行環境,requirements
文件夾中的第三方庫和項目目錄是同級的,可以正常導入使用。當然了,本地運行使用的是全局的第三方庫,并未用到項目目錄下的 requirements
文件夾。
前者(指 b)是一個很合理的設計,不過在實際環境中卻發現了新的問題。完全一致的配置文件
src: hook: 'pip3 install -r ./src/requirements.txt -t ./src/requirements' dist: ./src include: - source: ./requirements prefix: ../ exclude: - .env
在 macOS 下成功部署之后,云端的云函數編輯器中看到 requirements
文件夾不存在,第三方庫和項目目錄是同級的,的確沒問題。
不過在 Windows 下成功部署之后,云端的云函數編輯器中看到了 requirements
文件夾?也就是說第三方庫和項目目錄非同級,于是訪問就會出現 no module found
的導入報錯了……
反復嘗試修改 prefix
等配置項到最后也沒有調試成功,因此在這里提出兩種解決方法:
a. 修改配置文件如下,讓本地的第三方庫和項目目錄同級存在
src: hook: 'pip3 install -r ./src/requirements.txt -t ./src' dist: ./src exclude: - .env
不過隨著項目和第三方庫的擴大文件夾會越來越多,非常不便于管理
b. 使用云函數提供的 層
雖然 sls deploy
部署的速度很快,但是如果可以在部署時只上傳項目代碼而不去處理依賴不就更好了嘛,這樣跨終協作端開發只需要關心項目代碼就 ok
了,再也不需要管理依賴!
并且還有一點,想在 SCF
控制臺中在線編輯函數代碼需要將部署程序包保持在 10MB
以下,不要以為十兆很大,很快就用光也是可能的
具體如何操作呢?那就是要將第三方庫文件夾直接打包并創建為層,則在函數代碼中可直接通過 import
引用,畢竟有些特殊庫比如 Brotli
,Windows 下沒有 vc++
的話就只能去https://lfd.uci.edu/~gohlke/pythonlibs下載 wheel
安裝。
macOS 下正常安裝之后會得到 _brotli.cpython-39-darwin.so
,brotli.py
中再以 import _brotli
的形式導入,不過又出新問題了,云端會導入報錯ModuleNotFoundError: No module named '_brotli'"
當前
SCF
的執行環境建立在以下基礎上:標準CentOS 7.2
為了解決問題嘗試在 linux 環境下打包,拿起手頭的 CentOS 8.2
云主機開始操作
pip3 install -r requirements.txt -t ./layer --upgrade zip -r layer.zip ./layer
然后就可以把打包的 layer.zip
下載到本地再傳上去了,暫時可以一勞永逸了。
對了,配置文件可以移除 hook
并添加 layers
了
src: src: ./src exclude: - .env - '__pycache__/**' layers: - name: maimai_DX_CN_probe version: 3
已綁定層的函數被觸發運行,啟動并發實例時,將會解壓加載函數的運行代碼至
/var/user/
目錄下,同時會將層內容解壓加載至/opt
目錄下。若需使用或訪問的文件file
,放置在創建層時壓縮文件的根目錄下。則在解壓加載后,可直接通過目錄/opt/file
訪問到該文件。若在創建層時,通過文件夾進行壓縮dir/file
,則在函數運行時需通過/opt/dir/file
訪問具體文件
體驗更快的部署速度吧!因為第三方庫已經打包在“層”中了
但是奇怪的是,在云端導入任意第三方庫均會報錯,于是調試著查看 path
for path in sys.path: print(path) /var/runtime/python3 /var/user /opt /var/lang/python3/lib/python36.zip /var/lang/python3/lib/python3.6 /var/lang/python3/lib/python3.6/lib-dynload /var/lang/python3/lib/python3.6/site-packages /var/lang/python3/lib/python3.6/site-packages/pip-18.0-py3.6.egg
再查看 opt
import os dirs = os.listdir('/opt') for file in dirs: print(file) layer
這才恍然大悟,打包時需要在當前路徑直接打包。上傳之后“層”更新為版本 2
,但是 ModuleNotFoundError: No module named '_brotli'
報錯依舊,并且確認 _brotli.cpython-38-x86_64-linux-gnu.so
文件實際存在。
而在 CentOS
和 macOS
上本地導入均沒有問題,這可就犯難了,又想到很有可能是 python
版本的問題,于是去尋找現成 3.6
的環境,比如這里:
再再次上傳之后“層”更新為版本 3
,訪問成功!課題終于解決,原來是需要相同版本的 Python 3.6
運行環境
components源碼tencent-flask/src/_shims/中的文件每次都會被原封不動地重新打包上傳到云端云函數中,目前有兩個文件
a. severless_wsgi.py
,作用是 converts an AWS API Gateway proxied request to a WSGI request.
WSGI
的全稱是Python Web Server Gateway Interface
即Web 服務器網關接口
,它是為Python
語言定義的Web
服務器和Web
應用程序或框架之間的一種簡單而通用的接口
b. sl_handler.py
,就是默認的入口文件
import app # Replace with your actual application import severless_wsgi # If you need to send additional content types as text, add then directly # to the whitelist: # # serverless_wsgi.TEXT_MIME_TYPES.append("application/custom+json") def handler(event, context): return severless_wsgi.handle_request(app.app, event, context)
針對于自己的項目,使用了 Flask
的 工廠函數
,為了避免每次都要在云端云函數編輯器中重新修改,最好的方法是自定義入口文件:
import severless_wsgi from maimai_DX_CN_probe import create_app # Replace with your actual application # If you need to send additional content types as text, add then directly # to the whitelist: # # serverless_wsgi.TEXT_MIME_TYPES.append("application/custom+json") def handler(event, context): return severless_wsgi.handle_request(create_app(), event, context)
再指定 執行方法
為 serverless_handler.handler
,就 ok 了
url_for
輸出 http
而非 https
的 URL
在視圖函數中重定向到 url_for
所生成的鏈接都是 http
,而不是 https
……其實這個問題 Flask
的文檔 Standalone WSGI Containers有描述到
說到底這并不是 Flask
的問題,而是 WSGI
環境所導致的問題,推薦的方法是使用中間件,官方也給出了 ProxyFix
from werkzeug.middleware.proxy_fix import ProxyFix app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_host=1)
但是是從X-Forwarded-Proto
中取的值,apigw
中其為http
,因此并不能直接使用這個ProxyFix
因為Flask
的社區還算完善,參考資料很多前人都鋪好了路,所以直接去Stack Overflow
搜解決方法,Flask url_for generating http URL instead of https 問題出現的原因如圖:Browser ----- HTTPS ----> Reverse proxy(apigw) ----- HTTP ----> Flask
因為自己在apigw
設置了前端類型
僅https
,也就是說Browser
端是不可能使用http
訪問到的,通過打印environ
可知
{ "CONTENT_LENGTH": "0", "CONTENT_TYPE": "", "PATH_INFO": "/", "QUERY_STRING": "", "REMOTE_ADDR": "", "REMOTE_USER": "", "REQUEST_METHOD": "GET", "SCRIPT_NAME": "", "SERVER_NAME": "maimai.yuangezhizao.cn", "SERVER_PORT": "80", "SERVER_PROTOCOL": "HTTP/1.1", "wsgi.errors": <__main__.CustomIO object at 0x7feda2224630>, "wsgi.input": <_io.BytesIO object at 0x7fed97093410>, "wsgi.multiprocess": False, "wsgi.multithread": False, "wsgi.run_once": False, "wsgi.url_scheme": "http", "wsgi.version": (1, 0), "serverless.authorizer": None, "serverless.event": "<rm>", "serverless.context": "<rm>", "API_GATEWAY_AUTHORIZER": None, "event": "<rm>", "context": "<rm>", "HTTP_ACCEPT": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "HTTP_ACCEPT_ENCODING": "gzip, deflate, br", "HTTP_ACCEPT_LANGUAGE": "zh-CN,zh;q=0.9,en;q=0.8", "HTTP_CONNECTION": "keep-alive", "HTTP_COOKIE": "<rm>", "HTTP_ENDPOINT_TIMEOUT": "15", "HTTP_HOST": "maimai.yuangezhizao.cn", "HTTP_SEC_FETCH_DEST": "document", "HTTP_SEC_FETCH_MODE": "navigate", "HTTP_SEC_FETCH_SITE": "none", "HTTP_SEC_FETCH_USER": "?1", "HTTP_UPGRADE_INSECURE_REQUESTS": "1", "HTTP_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36", "HTTP_X_ANONYMOUS_CONSUMER": "true", "HTTP_X_API_REQUESTID": "5bcb29af2ca18c1e6d7b1ec5ff7b5427", "HTTP_X_API_SCHEME": "https", "HTTP_X_B3_TRACEID": "5bcb29af2ca18c1e6d7b1ec5ff7b5427", "HTTP_X_QUALIFIER": "$LATEST" }
HTTP_X_FORWARDED_PROTO
對應apigw
里的變量是HTTP_X_API_SCHEME
,故解決方法如下:app.wsgi_app = ReverseProxied(app.wsgi_app)
class ReverseProxied(object): def __init__(self, app): self.app = app def __call__(self, environ, start_response): scheme = environ.get('HTTP_X_FORWARDED_PROTO') if scheme: environ['wsgi.url_scheme'] = scheme return self.app(environ, start_response) app = Flask(__name__) app.wsgi_app = ReverseProxied(app.wsgi_app)
不論是IIS
、Apache
還是Nginx
,都提供有壓縮功能。畢竟自己在用的云主機外網上行只有1M
帶寬,壓縮后對于縮短首屏時間的效果提升極為顯著。對于Serverless
,響應數據是通過API Gateway
傳輸到客戶端,那么壓縮也應該是它所具備的能力(雖然外網速度大幅度提高,但是該壓縮還是得壓縮),然而并沒有找到……看到某些js
框架原生有提供壓縮功能,于是打算添加Flask
自行壓縮的功能。簡單來講,通過訂閱@app.after_request
信號并調用第三方庫brotli
的compress
方法即可( 在寫之前去gh
上看看有沒有現成的輪子拓展,果然有……剛開始用的是Flask-Zipper
,后來換成Flask-Compress
解決了問題 實測3.1 MB
的數據采用brotli
壓縮算法減至76.1 kB
apigw
三種環境不同路徑所產生的影響默認的映射如下:
ID | 環境名 | 訪問路徑 |
---|---|---|
1 | 發布 | release |
2 | 預發布 | prepub |
3 | 測試 | test |
因為配置的static_url_path
為""
,即static
文件夾是映射到/
路徑下的,所以再加上release
、prepub
和test
訪問就自然404
了 因此綁定了自定義域名
,使用自定義路徑映射
,并將發布
環境的訪問路徑設置成/
,這樣再訪問發布
環境就沒有問題了
ID | 環境名 | 訪問路徑 |
---|---|---|
1 | 發布 | / |
2 | 預發布 | prepub |
3 | 測試 | test |
私有網絡
和外網
云函數
中可以利用到的云端數據庫有如下幾種
云數據庫CDB
,需要私有網絡
訪問,雖然可以通過外網訪問但是能走內網就不走外網
PostgreSQL for Serverless(ServerlessDB)
,這個是官方給Serverless
配的pg
數據庫
云開發TCB
中的MongoDB
,沒記錯的話需要開通內測權限訪問
因為自己是從舊網站遷移過來的,數據暫時還沒有遷移,因此直接訪問原始云數據庫CDB
,在云函數
配置所屬網絡
和所屬子網
即可。但是此時會無法訪問外網,一種解決方法是開啟公網訪問
和公網固定IP
,就可以同時訪問內網和外網資源了。關于配置文件,本項目是單實例應用
也就是說項目中只引入一個組件,部署時只生成一個組件實例
。但是如果想引入數據庫的話,就得新增組件了,目前在Flask Components
中并沒有提供數據庫相關的配置項,因此需要項目中引入多個組件,部署時生成多個組件實例
。也很簡單,創建一個含有serverless.yml
的新文件夾,用來配置postgresql
component: postgresql # (必填) 組件名稱,此處為 postgresql name: maimai_DX_CN_probe # (必選) 組件實例名稱. org: yuangezhizao # (可選) 用于記錄組織信息,默認值為您的騰訊云賬戶 appid,必須為字符串 app: yuangezhizao # (可選) 用于記錄組織信息. 默認與name相同,必須為字符串 stage: dev # (可選) 用于區分環境信息,默認值是 dev inputs: region: ap-beijing # 可選 ap-guangzhou, ap-shanghai, ap-beijing zone: ap-beijing-3 # 可選 ap-guangzhou-2, ap-shanghai-2, ap-beijing-3 dBInstanceName: maimai_DX_CN_probe # projectId: 0 dBVersion: 10.4 dBCharset: UTF8 vpcConfig: vpcId: vpc-mrg5ak88 subnetId: subnet-hqwa51dh extranetAccess: false
然后在終端cd
到這個目錄再執行sls deploy
即可成功部署postgresql
yum install python3-devel postgresql-devel pip install psycopg2
結果
import psycopg2 File "/opt/psycopg2/__init__.py", line 51, in <module> from psycopg2._psycopg import ( # noqa ImportError: libpython3.6m.so.1.0: cannot open shared object file: No such file or directory
下列問題處于解決之中:
http
強制跳轉 https
測試環境推送至生產環境
上述就是小編為大家分享的基于 Serverless 的舞萌音游查分器是怎樣的了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。