伺服器 Galore:使用 Python 的 CherryPy 在精益環境中實現快速可擴展原型
TL;DR
成為一名年長的工程師的結果之一是,我只想完成專案。 花時間流覽一個不工作、執行不當或記錄不佳的圖書館,使得編碼成為一件苦差事,而不是一種樂趣。 這就是為什麼我一直很高興與 櫻桃皮 最近:
- Docker 檔案並不複雜
- 靜態內容可快速送達
- Python 文稿是一流公民
- 測試簡單明瞭
- 延伸我的應用程式是一個襯墊
什麼是櫻桃?
CherryPy 是一個極簡的 Python Web 框架。 它永遠不會取代一個更大的更完整的框架的企業軟體,但的東西啟動和運行是夢幻般的。 傳統上,我會使用 簡單HTHVer 原型設計,但它是功能光 - 要求我更新,只要我做任何事情,真正推動伺服器。 CherryPy 允許我的應用程式在切換到更大的框架(如果有的話)之前進行足夠大的擴展以非常有用。 作為參考,數位海洋做了一個很好的 比較 Python WSGI 伺服器。
碼頭和櫻桃Py
我們使用 Docker 的一切 ShareThis ,因此讓我們先完成,以便我們有一個完整的開發環境進行測試。 只需克隆我們的存儲庫,即可啟動此操作。 在開始設置這個需要額外的10分鐘,但將在編碼的最初幾天內多次還清。 這可以說是我們在 Docker 中用 Docker 換來簡單 HttpServer 的唯一成本。
Dockerfile
FROM python
RUN pip install cherrypy coverage # cherrypy server + python 3 test coverage
ADD *.py /
ADD *.sh /
CMD python run.py
testing.sh
#!/bin/bash
coverage run -a --omit=test.py /test.py
coverage report -m
run.sh
#!/bin/bash
# docker kill and rm prevent funny errors
docker kill cherrypy > /dev/null 2>&1
docker rm cherrypy > /dev/null 2>&1
# build, test, and run the image
docker build -t cherrypy .
docker run cherrypy /testing.sh
docker run -ti --name cherrypy -p 80:80 cherrypy $@
test.py
import unittest
class TestMethods(unittest.TestCase):
def test_simple(self):
self.assertTrue(True)
if __name__ == '__main__':
unittest.main()
第一次傳遞:腳稿化的內容
讓我們假設你想開始一個精益實驗,看看是否有人會降落在一個頁面上。 最快的操作是提供靜態頁面和日誌訪問。 讓我們添加缺少的run.py腳本:
run.py (V1)
import cherrypy
class Landing(object):
@cherrypy.expose
def index(self):
return scripted landing
if __name__ == "__main__":
cherrypy.quickstart(Landing(), '/')
此時,您擁有可擴展的 Web 伺服器,可以執行任何操作。 我用於儀錶板、監視和大量內部工具。
此時,您需要開始使用配置。 例如,您希望 Web 伺服器在 0.0.0.0 上聲明,而不是 127.0.0.1 在公共路由上聲明。 您希望在埠 80 上提供即時流量服務。 對於多個即時連接,您需要 10 多個線程(下面將介紹更多線程)。 儘管尾隨斜杠,但您希望路由流量。 您要一個 其他事物的主機 發生。
讓我們通過向 cherrypy.config.update
. 此外,讓我們透過更改靜態內容和設定檔來載入靜態內容和設定檔 cherrypy.quickstart(Landing(), '/')
自 cherrypy.quickstart(Landing(), '/', "prod.conf")
. 別忘了把 prod.conf 添加到您的 Dockerfile!!
run.py (V2)
import cherrypy
class Landing(object):
@cherrypy.expose
def index(self):
return scripted landing
# The config.update is optional, but this will prevent scaling issues in a moment
cherrypy.config.update({
'server.socket_host': '0.0.0.0', # 127.0.0.1 is default
'server.socket_port': 80, # 8080 is default
'server.thread_pool': 100, # 10 is default
'tools.trailing_slash.on': False # True is default
})
if __name__ == "__main__":
cherrypy.quickstart(Landing(), '/', "prod.conf")
在這一點上,你很可能也需要靜態資產。 讓我們添加帶有靜態圖像引用的設定檔! 您可以添加任意數量的靜態資產。 我更喜歡聲明性的方法,但你可以 服務目錄 太。
prod.conf
[/logo.png]
tools.staticfile.on = True
tools.staticfile.filename = "/logo.png"
快速延伸
擴展原型意味著快速擺脫阻滯器。 讓我們討論一些影響 CherryPy 的更常見問題,以及如何儘快解決這些問題。
執行狀況檢查及附加處理程式
在 ShareThis ,我們在庫伯內特內部運行應用程式 在 AWS 上。 我們需要監視 Docker 容器的狀態,以便系統知道容器是否處於活動狀態以及負載均衡器是否正常。 在需要其他處理程序的情況下,可以廣泛歸檔。 下面是編寫一個簡單的 HealthCheck 終結點並將處理程式添加到我們的 Landing 物件的簡單示例。 現在,我們可以指出 http://localhost/healthcheck 以查看伺服器是否處於活動狀態。
...
class HealthCheck(object):
def index(self):
return "Yay
\n"
index.exposed = True
class Landing(object):
healthcheck = HealthCheck()
...
監視對 Kubernetes 的一個副作用是網路隱藏了一些複雜性。 Kubernetes 群集中的每個節點都有一個代理,該代理將數據隨機排列到 Docker 容器此時運行的位置。 來自亞馬遜的彈性負載均衡器 (ELB) 將嘗試保持與每個節點的連接處於活動狀態,以便對群集執行運行狀況檢查。 這意味著,對於群集中的每個節點,您必須在伺服器可用的線程數中考慮這一點。 在我們的 20 個節點群集中,我們的測試應用程式將不起作用,因為 ELB 一次訪問 20 個線程。 CherryPy 預設為 10 個線程,因此代理將不斷被踢出旋轉狀態。 因此,我們增加到上述 100 個線程將允許其擴展,而不會出現操作問題。
新增測試
當您不確定在進行更改時會發生什麼時,複雜性會妨礙工作效率。 測試套件添加簡單協定,告訴未來的開發人員(包括您自己)程式碼打算做什麼,可以保持代碼縮放,而無需大量開銷。
我們包括腳本和覆蓋工具的方式,您應該能夠為任何 python 文本添加導入語句,並且覆蓋範圍將處理其餘內容。 您可能需要新增 mock
包到您的 pip install
語句以方便測試。
總結
CherryPy 有據可查,擴展得相當好。 通常,在縮放的環境中啟動和運行應用是您所需要的一切。 以從樣本開始,您可以立即擁有本機運行 python 代碼的 Web 伺服器。 對我們來說,在 ShareThis ,我們已將其用於後端數據處理,通過休息介面,監視 S3 和 BQ 上的源,並快速啟動需要連接到 API 的數據儀錶板。 通過使用 Docker,在生產環境中部署和維護應用程式變得微不足道。