1. 程式人生 > >如何在Python中使用ZeroMQ和Docker構建微服務架構

如何在Python中使用ZeroMQ和Docker構建微服務架構

ati 包含 file 更多 定價 lean https 目前 端口

@Container容器技術大會將於6月4日在上海光大會展中心國際大酒店舉辦,來自攜程、PPTV、螞蟻金服、京東、浙江移動、海爾電器、唯品會、eBay、道富銀行、麻袋理財等公司的技術負責人將帶來實踐經驗分享,3月21日之前購票只需238元,歡迎感興趣的同學搶購。

微服務是什麽?

微服務是一種架構風格,它包括多個彼此間進行通信的獨立進程。在設計上,這些進程具有高度的可擴展性、相互解耦而且一次只完成一個較小的任務。這些服務都擁有自己的資源以及通過網絡實現彼此間通信的進程。

相比於靠後端的單體結構來封裝所有服務器邏輯的傳統客戶端-服務器架構(C/S架構)而言,微服務架構的差異性體現在關註點分離(Separation of concern)。這種設計模式更易於維護,使得靈活性、可擴展性及容錯能力更強。但是這種分布式架構所的不足之處體現在如果設計不合理就會使得排錯及維護變得復雜。

一個簡單微服務的例子

讓我們來分析這樣的一個場景:你正在使用微服務模式構建一個電子商務網店。

對於一個電商網店上的常見商品,好比說iPhone,其詳情頁會顯示:

  • 產品的及基本信息
  • 你的購買歷史
  • 哪些人買了iPhone也買了手機套
  • 與蘋果手機相關的優惠和折扣
  • 店家的數據
  • 送貨方式
  • 推薦商品等等


此外,這個簡單的產品詳情頁的接口將有多個版本的來匹配Web、移動端以及用於第三方應用程序的REST API。

在微服務模式中數據分布在多個服務之間。在這個例子中,服務包括:

  • 產品詳情服務
  • 商家服務
  • 支付服務
  • 優惠及折扣服務
  • 庫存服務
  • 定價服務
  • 回顧服務
  • 推薦服務


這些獨立的服務是如何被訪問的呢?

解決辦法是使用一個API網管,它作為所有客戶端的單一入口並且根據需求調用分布在整個基礎架構中的特定微服務。以上模式的行業應用案例是NetFlix API網關,它具有支持不同設備的多個API客戶端。你可以點擊此處了解更多。

構建一個簡單的微服務

目前有很多方法可以用於構建你的微服務。

在本文中我們將使用ZeroMQ來創建兩個進程之間的通信。ZeroMQ提供了用於在套接字之上開發可擴展、分布式systed的構建塊。它使用橢圓曲線密碼體制(第四版)來實現安全性,並提供了即刻開啟的通訊模式。

關於ZMQ,還有很多優點。MQ即是針對異步工作而設計的線程化消息隊列。談論太多zeroMQ的內容已經超出了本文的範疇,你可以閱讀使用zeromq以及zeromq用於分布式系統。


我們要使用的另一個工具是Docker。本文假設讀者對Docker已經有了基礎的了解。

ZeroMQ有很多種通訊模式,為了開始我們的工作,讓我們用ZeroMQ和Flask來配置一個簡單的PUB-SUB。下圖展示了組件之間的關系和數據流。

技術分享圖片

  • 1&3 - 一個flask服務器運行在5000端口上而且其URL是/downcase/。該URL用來接受(GET)請求,而所有格式為的請求將收到回應:答謝字符將會轉換為小寫字符並返回。
  • 2 - 回應的消息也被發送給同一個容器中的ZMQ發布者(Publisher)
  • 4,5 - ZMQ訂閱者(subscriber)持續監聽並將來自ZMQ服務器的消息保存到名為subscriber.log的文件中

創建服務器

首先看一下我們的Dockerfile

FROM ubuntu:14.04 
RUN apt-get update 
RUN apt-get install -y --force-yes python python-dev python-setuptools software-properties-common gcc python-pip 
RUN apt-get clean all

RUN pip install pyzmq 

RUN pip install Flask 

ADD zmqserver.py /tmp/zmqserver.py 


# # Flask Port

EXPOSE 5000 


# #  Zmq Sub Server

EXPOSE 4444 

CMD ["python","/tmp/zmqserver.py"]


我們選擇Ubuntu 14.04作為容器操作系統。我們安裝了基本的軟件包。通過pip,我們安裝pyzmq(zeromq的Python綁定)同時也安裝了Flask。接著我們導出端口5000(flask服務器)和4444(發布者運行的端口)。此外,我們復制了包含所有flask及zeromq pythond代碼的腳本文件zmqserver.py並運行它。

現在我們來看一下zmqserver.py的內容:

# server.py 
import time 
import zmq 

HOST = ‘127.0.0.1‘ 
PORT = ‘4444‘ 

_context = zmq.Context() 
_publisher = _context.socket(zmq.PUB) 
url = ‘tcp://{}:{}‘.format(HOST, PORT) 

def publish_message(message):
try: 
_publisher.bind(url) 
time.sleep(1) 
_publisher.send(message) 

except Exception as e: 
print "error {}".format(e) 
finally: _publisher.unbind(url) 

from flask import Flask 
from flask import request 
app = Flask(__name__) 

@app.route("/downcase/", methods=[‘GET‘]) 
def lowerString(): 

_strn = request.args.get(‘param‘) 
response = ‘lower case of {} is {}‘.format(_strn, _strn.lower()) publish_message(response) 
return response

if __name__ == ‘__main__‘: 
app.run(host=‘0.0.0.0‘, debug=False)


ZMQ發布者運行在4444端口上。我們創建了一個context並且聲明了URL。我們運行了flask app,它通過URL /downcase/把GET獲得的參數Param轉換成小寫字符,這就是服務的應答。應答的字符串是published,它作為一個消息把相同的字符串返回給瀏覽器。

為了構建以上的Docker映像(image),我們執行以下的命令:
sudo docker build -t docker-zmq-pub
並且在該映像之上執行:
docker run --name docker-pub-server -p 5000:5000 -p 4444:4444 -t docker-zmq-pub

我們把容器中的端口5000和4444映射到這臺主機上,於是無論客戶端在哪裏,它們都可以訂閱這個發布者。

訂閱者客戶端

# client.py
import zmq
import sys
import time
import logging
import os

HOST = ‘127.0.0.1‘
PORT = ‘4444‘

logging.basicConfig(filename=‘subscriber.log‘, level=logging.INFO)


class ZClient(object):

def __init__(self, host=HOST, port=PORT):
    """Initialize Worker"""
    self.host = host
    self.port = port
    self._context = zmq.Context()
    self._subscriber = self._context.socket(zmq.SUB)
    print "Client Initiated"

def receive_message(self):
    """Start receiving messages"""
    self._subscriber.connect(‘tcp://{}:{}‘.format(self.host, self.port))
    self._subscriber.setsockopt(zmq.SUBSCRIBE, b"")

    while True:
        print ‘listening on tcp://{}:{}‘.format(self.host, self.port)
        message = self._subscriber.recv()
        print message
        logging.info(
            ‘{}   - {}‘.format(message, time.strftime("%Y-%m-%d %H:%M")))

if __name__ == ‘__main__‘:
zs = ZClient()
zs.receive_message() 


我們聲明了發布者的IP地址及端口,當前它運行在同一個的主機上因此地址是127開頭。我們在URL tcp://IP:PORT上進行監聽。一旦我們收到一個消息,就將其附上時間戳後記錄到名為subscriber.log的文件中。運行客戶端要做的所有工作就是執行 python <name_of_client_file>.py。如果你在以上的架構上進行構建,它可以很好地充當近實時的日誌聚合引擎。

我在Unbuntu主機上對以上的代碼進行了測試。這裏所用的代碼保管在GitHub上。這是一個如何配置ZMQ、Docker和Python服務器的基礎講解,在我的下一片文章中我們會使用我們已經學習的東西構建簡單的微服務。

希望這篇文章對你有所幫助。

如何在Python中使用ZeroMQ和Docker構建微服務架構