基于DC/OS打造高可扩展性的IoT物联网平台

基于DC/OS打造高可扩展性的IoT物联网平台

在本篇文章中,我们将分享如何在DC/OS上使用

Percona-Server-MongoDB服务构建IoT架构

在为Mesosphere DC/OS平台集成Percona-Server-MongoDB服务时,笔者决定尝试以此服务作为持久化存储后端来构建一套IoT架构。

许多IoT架构都采用MongoDB作为持久化存储方案,MongoDB之所以那么流行有如下几点原因:

高可扩展性

支持复杂查询

不强制schema约束(即使某个字段包含不同类型的值,也可以按原生JSON格式直接导入MongoDB)

* 注:本篇文章的所有代码都可以在 https://github.com/dcos/demos 里找到。

首先,我们来看一下平台的整体架构:

上图顶端显示的是一组使用MQTT协议的设备,采集并生成数据。MQTT协议基于发布/订阅模式,是专为传感器设计的一种标准化协议。该协议是笔者在IBM时期一个英国同事Andy Stanford-Clark设计的,使用在处理能力很弱的低功耗设备上。由于我们的演示环境中并没有真实设备,笔者使用了Eclipse开源的Python库Paho (https://www.eclipse.org/paho/clients/python/docs/ )模拟了一个输出随机值的、采样率可配的单传感器设备。本例中假设它是一个工业用传感器,输出的值是温度。

使用MQTT协议的采集设备(生产者)需要连接到一个broker,来发布它们的数据。本次分享中,我们采用EclipseMosquitto( https://mosquitto.org/ )作为broker方案。

我们需要通过某种形式的网关,将感知层brokers提供的数据拉取到MongoDB的聚合层。通过向broker订阅相关主题(topic),持续获取消息报文,转换格式后写入后端MongoDB数据集。

我们利用paho-mqtt和the pymongo (https://api.mongodb.com/python/current/ )两个库,给出了Python版本的参考实现。

让我们从模拟设备开始,了解一下该方案的实施细节。代码非常简单:

#!/usr/bin/env python

"""

MQTT generator

"""

import random

import time

import uuid

import json

from argparse import ArgumentParser

import paho.mqtt.client as mqtt

parser = ArgumentParser()

parser.add_argument("-b", "--broker", dest="broker_address",

required=True, help="MQTT broker address")

parser.add_argument("-p", "--port", dest="broker_port", default=1883, help="MQTT broker port")

parser.add_argument("-r", "--rate", dest="sample_rate", default=5, help="Sample rate")

parser.add_argument("-q", "--qos", dest="qos", default=0, help="MQTT QOS")

args = parser.parse_args()

uuid = str(uuid.uuid4())

topic = "device/%s" % uuid

mqttc = mqtt.Client(uuid, False)

mqttc.connect(args.broker_address, args.broker_port)

while True:

rand = random.randint(20,30)

msg = {

'uuid': uuid,

'value': rand

}

mqttc.publish(topic, payload=json.dumps(msg), qos=args.qos)

time.sleep(float(args.sample_rate))

mqttc.loop_forever()

可以看到,我们在设备上需要配置几个参数。首先,是要连接的MQTT broker的地址和端口号;其次,希望模拟数据以什么频率生成(采样率);此外,还有个QoS设定,暂时没有用到。QoS (Quality of Service 服务质量)也是MQTT标准的一部分,可以参阅the Mosquitto的文档( https://mosquitto.org/man/mqtt-7.html )了解更多细节。

启动阶段,(IoT采集)设备会生成一个唯一的UUID编号,以device/$uuid格式的主题名连接到MQTT broker,接下来每个采样周期,设备发送一个很小的JSON载荷到broker,其中封装了UUID和模拟传感器生成的随机值。

为了在DC/OS上跑起服务,一种方案是使用pyinstaller打包所有依赖,可以参考笔者先前写的关于Python微服务的博客文章(https://mesosphere.com/blog/native-python-microservices-mesos/ )。这次我们可以试试用Docker,构建镜像发布到镜像仓库,最后部署到平台。在此不详述如何安装Docker环境,网上的参考有很多。我们假设您已经在本地建好了一个可运行的Docker环境。

首先要生成一个文本文件,描述我们的应用包含的所有需求。由于我在虚拟环境中(https://virtualenv.pypa.io/en/stable/ )已经通过pip安装了所有依赖,所以文本生成只需要一行命令:

$ pip freeze > requirements.txt

$ cat requirements.txt

paho-mqtt==1.3.1

接着,创建一个的Dockerfile用于构建镜像,这非常简单:

$ cat Dockerfile

FROM python:2

WORKDIR /usr/src/app

COPY requirements.txt ./

RUN pip install --no-cache-dir -r requirements.txt

COPY device.py .

CMD [ "/bin/bash" ]

以Python2作为Docker基础镜像,将requirements.txt拷贝到工作目录下,使用pip按装依赖包,再加上运行设备使用的Python代码。由于我们最终将采用通用容器运行时(Universal Container Runtime)跑服务,其实并不需要定义CMD,不过为了测试,我们暂且把CMD设成shell。

有了Dockerfile,可以编译一个自定义镜像:

$ docker build -t device .

Sending build context to Docker daemon 12.78MB

Step 1/6 : FROM python:2

2: Pulling from library/python

0bd44ff9c2cf: Pull complete

047670ddbd2a: Pull complete

ea7d5dc89438: Pull complete

ae7ad5906a75: Pull complete

0f2ddfdfc7d1: Pull complete

85124268af27: Pull complete

1be236abd831: Pull complete

fe14cb9cb76d: Pull complete

cb05686b397d: Pull complete

Digest: sha256:c45600ff303d92e999ec8bd036678676e32232054bc930398da092f876c5e356

Status: Downloaded newer image for python:2

---> 0fcc7acd124b

Step 2/6 : WORKDIR /usr/src/app

Removing intermediate container ea5359354513

---> a382209b69ea

Step 3/6 : COPY requirements.txt ./

---> b994369a0a58

Step 4/6 : RUN pip install --no-cache-dir -r requirements.txt

---> Running in 1e60a96f7e7a

Collecting paho-mqtt==1.3.1 (from -r requirements.txt (line 1))

Downloading https://files.pythonhosted.org/packages/2a/5f/cf14b8f9f8ed1891cda893a2a7d1d6fa23de2a9fb4832f05cef02b79d01f/paho-mqtt-1.3.1.tar.gz (80kB)

Installing collected packages: paho-mqtt

Running setup.py install for paho-mqtt: started

Running setup.py install for paho-mqtt: finished with status 'done'

Successfully installed paho-mqtt-1.3.1

Removing intermediate container 1e60a96f7e7a

---> 3340f783442b

Step 5/6 : COPY device.py .

---> 72a88b68e43c

Step 6/6 : CMD [ "/bin/bash" ]

---> Running in a128ffb330fc

Removing intermediate container a128ffb330fc

---> dad1849c3966

Successfully built dad1849c3966

Successfully tagged device:latest

$ docker images

REPOSITORY TAG IMAGE ID CREATED SIZE

device latest dad1849c3966 About an hour ago 903MB

python 2 0fcc7acd124b 9 days ago 902MB

我们在本地得到了新的Docker镜像,需要发布到DockerHub上,方便随后使用DC/OS上的Marathon来部署该镜像。

先确认一下是否已经登陆到DockerHub:

$ docker login --username=mattjarvis

Password:

Login Succeeded

确认登陆成功,给本地镜像打个标签(tag)推送到镜像库:

$ docker tag dad1849c3966 mattjarvis/device:latest

$ docker push mattjarvis/device

The push refers to repository [docker.io/mattjarvis/device]

d52256b6a396: Pushed

6b19db956ca6: Pushed

cd0c68b16296: Pushed

812812e9c2f5: Pushed

05331f1f8e6f: Layer already exists

d8077e47eb94: Layer already exists

5c0800b60a4e: Layer already exists

ebc569cb707f: Layer already exists

9df2ff4714f2: Layer already exists

c30dae2762bd: Layer already exists

43701cc70351: Layer already exists

e14378b596fb: Layer already exists

a2e66f6c6f5f: Layer already exists

latest: digest: sha256:8a1407f64dd0eff63484f8560b605021fa952af00552fec6c8efb913d5bba076 size: 3053

在着手实施真正的部署之前,来看另一段Python代码mongogw.py,用于建立MQTT broker和MongoDB集群连接:

#!/usr/bin/env python

"""

MQTT to MongoDB Gateway

"""

import json

from argparse import ArgumentParser

import pymongo

import datetime

import os

parser = ArgumentParser()

parser.add_argument("-b", "--broker", dest="broker_address",

required=True, help="MQTT broker address")

parser.add_argument("-p", "--port", dest="broker_port", default=1883, help="MQTT broker port")

parser.add_argument("-m", "--mongouri", dest="mongo_uri", required=True, help="MongoDB URI")

parser.add_argument("-u", "--mongouser", dest="mongo_user", required=True, help="MongoDB user")

parser.add_argument("-w", "--mongopwd", dest="mongo_password", required=True, help="MongoDB password")

args = parser.parse_args()

def on_message(client, userdata, message):

json_data = json.loads(message.payload)

post_data = {

'deviceUID': json_data['uuid'],

'value': json_data['value'],

'gatewayID': os.environ['MESOS_TASK_ID']

}

result = devices.insert_one(post_data)

# MongoDB connection

mongo_client = pymongo.MongoClient(args.mongo_uri,

username=args.mongo_user,

password=args.mongo_password,

authSource='mongogw',

authMechanism='SCRAM-SHA-1')

db = mongo_client.mongogw

devices = db.devices

# MQTT connection

mqttc = mqtt.Client("mongogw", False)

mqttc.on_message=on_message

mqttc.connect(args.broker_address, args.broker_port)

mqttc.subscribe("device/#", qos=0)

mqttc.loop_forever()

从上述代码中,网关同时连接了MQTT采集设备的broker和MongoDB,然后订阅所有以device/前缀的主题,使用回调函数读取消息报文,转换格式并附加自定义metadata后,写入MongoDB。这个步骤中,我们给写入后台的记录另加一个时间戳,这也是为了模拟真实环境中很可能存在的情况:传感器设备很可能没有足够的处理能力来实现时钟功能。同时,我们也添加了Mesos任务ID,以便在感知层(传感器阵列)扩充的时候,我们可以跟踪究竟是哪个网关实例处理了报文消息。

这一部分和在采集设备上的操作一样,定义Dockerfile构造镜像然后推送到镜像仓库。

连同Dockerfile定义也和应用到采集设备上的那套非常接近:

$ cat Dockerfile

FROM python:2

WORKDIR /usr/src/app

COPY requirements.txt ./

RUN pip install –no-cache-dir -r requirements.txt

COPY mongogw.py .

CMD [ “/bin/bash” ]

我们现在已经定制好了实现代码,可以开始着手部署了。首先部署MongoDB replica集。我写了很长一篇关于Percona-Server-MongoDB服务的博文(发布后会附上链接),里面详述了如何利用该服务的很多高级特性。但是我们现在谈到的demo里,全部采用缺省设置就可以了,我们能轻松建起一个3副本的数据集。可以参考下述JSON配置默认用户名、密码、密钥:

$ cat demo.json

{

"mongodb-credentials": {

"backupUser": "backup",

"backupPassword": "backupuserpassword",

"userAdminUser": "useradmin",

"userAdminPassword": "useradminpassword",

"clusterAdminUser": "clusteradmin",

"clusterAdminPassword": "clusteradminpassword",

"clusterMonitorUser": "clustermonitor",

"clusterMonitorPassword": "monitoruserpassword",

"key": "8cNNTVP6GqEOKzhUVDVryxIt04K6kDbXygamH4upPGAO59gzXVQAgX9NwxwqDvpt 094zMkkRWDLzuCgbg3Aj8EFVEM0/W1Nz+XUSTHEn4HiNzCVG4TTHFP6P1PEPswG6 tQMP6bnRXL7uGWmdGhbAxOV/+p6AfNs67MTvfCeH0EaPCgPPXhJft9D0nZ0SPOm9 VvfxG3djnHClIlclkchoIwc1Kw21loyXwuOjX4RkywVDdmFXjKC+l9yxfyt/9Gyh YE0OlS7ozWLiH8zy0MyzBdK+rc0fsxb2/Kb/8/2diC3O3gdVxjneQxaf66+FHVNW mV9/IHDptBHosdWkv0GboW8ZnTXnk0lyY0Jw85JFuTeFBzqPlB37jR0NU/HFm5QT Ld62woaGIWCTuXGb81QHaglPZUBIhEq/b3tahJBmLc+LKd0FUShoupTtPc2FjxbH xD8dZ+L9Uv7NPtSe+o3sTD60Pnsw1wbOrNDrrC+wpwoMy2GbQjXk/d+SRK/CXfuk Z676GKQDivpinhdF58l4OEi+WEN633yuNtNAQDgz+aOVZKN4oLoyR22B1nrea1qW wzZjRw7kpVxcQKiyn+gDmAZZPbctiVqTNHPE5n9LrOcctuLZKpoQk97lvZTSCKfy d32mfx9szZZ/QCfF9Dt7+G5nJUAULigKnQYRi/i86ZTPHSzfun+ZIzYLCzJuZfyS 7E8DMsmv9wCPrPAF/8cOFMWW0o0Na7GZKCJ8U+AMm92R725h4g5ao6+kQPG7vOkY LR8MJzDOqcmAC0M9AwE5UXQl56V6qBNyREx/WGGYS1B5DOfZvVTJNDkoHVIL1upZ geSlACiXQ+M0Rkgo0h8BJUhGY9LTuc6S8qiMBEnhBClg4kA/u4FJ06nlmF3ZpIXT KsVSr9ee3mu0vSr6P52slvAAX+RL3y+JgSlz2kC8oVgCZZdKn7yq9e6yB3zHNMjX 8VIi/UgFmfqCiaAlUT0pt2ZzGuw1L9QUOuNAZfufSkK1ED4V"

}

}

用户定义的密码不能短于10个字符,生成的key不能少于1024个字符。在MacOS系统中可由下述命令生成key:

$ openssl rand -base64 756

我们用这个options.json配置来安装percona-server-mongod服务包:

$ dcos package install percona-server-mongodb --options=demo.json

By Deploying, you agree to the Terms and Conditions https://mesosphere.com/catalog-terms-conditions/#community-services

Default configuration requires 3 agent nodes each with: 1.0 CPU | 1024 MB MEM | 1 1000 MB Disk

Continue installing? [yes/no] yes

Installing Marathon app for package [percona-server-mongodb] version [0.4.0-3.6.6]

Installing CLI subcommand for package [percona-server-mongodb] version [0.4.0-3.6.6]

New command available: dcos percona-server-mongodb

The DC/OS Percona Server for MongoDB service is being installed.

Documentation: https://docs.mesosphere.com/service-docs/percona-server-mongodb/

Issues: https://jira.percona.com/secure/CreateIssue!default.jspa?pid=12402.

如果安装了Percona-Server-MongoDB CLI扩展,我们还可以直接通过DC/OS的CLI直接给MongoDB数据库配一个用户。当然,这步操作需要事先在JSON文件里定义要创建的用户:

$ cat mongouser.json

{

"user": "mongogw",

"pwd": "123456",

"roles": [

{ "db": "mongogw", "role": "readWrite" }

]

}

JSON配置中需要附上具有管理员权限的登陆凭证,使用CLI指定要配置的数据库名称,操作如下:

$ dcos percona-server-mongodb user add mongogw mongouser.json

{

"message": "Received cmd: start update-user with parameters: "

}

下一步我们来部署MQTT层。理论上传感器设备可能多达成千上万,所以感知层必须做到可扩展。鉴于此,我们在DC/OS通过创建一个带别名的虚拟IP地址(VIP),实现多个Mosquitto端点的负载均衡接入。当然在真实的互联网环境下,我们通常采用集群外部暴露Marathon-LB实例的方式来实现。

上述方案做到了和设备的对接。然而,使用了网关层提供的虚拟IP地址接入,如果同时要求网关层支持可伸缩,会带来新的问题。

做采集的MQTT层并不是作为一个集群而是单独接入的,不方便统计管理发布数据实际的消费情况;同时接入后端MongoDB的网关可以从任意一个Mosquitto实例读取数据,

并不会感知到消息生产侧的情况,在网关层伸缩的时候很可能会丢失MQTT层生产的数据。

为解决上述问题,我们设计在POD里部署运行Mosquitto实例的同时,附带一个专属的网关微服务( https://docs.mesosphere.com/1.11/deploying-services/pods/ ),网关通过本地连接(localhost)访问Mosquitto,确保每个网关只从一个Mosquitto实例获取数据。

由此,确保通过负载均衡器IP接入的设备,确定能够访问到部署的某个Mosquitto实例,最终存储层都能获得传感器数据。

下面给出我们部署运行POD的JSON范例:

{

"id": "/mqtt",

"containers": [

{

"name": "mosquitto",

"resources": {

"cpus": 0.1,

"mem": 64

},

"image": {

"id": "eclipse-mosquitto",

"kind": "DOCKER"

},

"endpoints": [

{

"name": "mqtt",

"containerPort": 1883,

"hostPort": 1883,

"protocol": [

"tcp"

],

"labels": {

"VIP_0": "/mqtt:1883"

"name": "mongogw",

"resources": {

"cpus": 0.1,

"mem": 64

},

"image": {

"id": "mattjarvis/mongogw",

"kind": "DOCKER"

},

"exec": {

"command": {

}

}

}

],

"scaling": {

"instances": 1,

"kind": "fixed"

},

"networks": [

{

"name": "dcos",

"mode": "container"

}

],

"volumes": [],

"fetch": [],

"scheduling": {

"placement": {

"constraints": []

}

}

}

我们使用Mosquitto提供的预编译镜像建立我们的第一个容器,为MQTT连接开放1883端口。我们需要给它分配一个负载均衡器的虚拟IP地址,同时在宿主机上映射一个端口号。

第二个容器运行的是我们的mongogw网关Python微服务。mongogw进程启动后,通过本地连接(localhost)访问Mosquitto,通过DC/OS分配的DNS访问MongoDB实例。

把如下JSON通过DC/OS CLI传给Marathon,即可完成上述操作:

$ dcos marathon pod add mqttpod.json

Created deployment 19887892-f3e9-44b4-9dd3-22a5790196f3

我们的感知层已经启动了,可以打开采集设备了。我们还需要补充几个Marathon配置,JSON格式如下:

{

"id": "device",

"instances": 1,

"cpus": 0.1,

"mem": 16,

"container": {

"type": "MESOS",

"docker": {

"image": "mattjarvis/device",

"forcePullImage": true,

"privileged": false

}

},

"requirePorts": false

}

我们已经安装通用的容器运行时环境,下拉相关的Docker镜像。接下来需要配合参数运行Python脚本,配置设备间隔两秒连接一次分配了负载均衡VIP的Mosquitto POD发布数据。可以看到整个流程对CPU和内存的需求相当小,我们应该可以扩展出很多很多的实例。

开始部署我们的第一个(虚拟)采集设备:

$ dcos marathon app add device.json

Created deployment 231be2c7-47c6-4f28-a7e0-40f4aae2f743

一旦我们的设备启动运行了,可以通过检查MongoDB记录的方式,确认流程中每一层部署都正常运作。首先通过DC/OS命令行取得某个MongoDB副本的任务ID。有了任务ID,就能通过DC/OS命令行开个shell直接访问那个容器:

$ dcos task

NAME HOST USER STATE ID MESOS ID REGION ZONE

admin-0-watchdog 10.0.2.229 root R admin-0-watchdog__a3ff9cc4-daeb-4f76-b730-aea8e2667417 3ba115f5-b4fe-43e9-a05a-0d9b0240fb51-S4 --- ---

device 10.0.3.192 root S device.769ef300-b75d-11e8-9d5d-fe0bc23c90b8 3ba115f5-b4fe-43e9-a05a-0d9b0240fb51-S3 --- ---

mongo-rs-0-mongod 10.0.0.44 root R mongo-rs-0-mongod__f0a27fca-138a-4f39-a0b2-4a1a0960c079 3ba115f5-b4fe-43e9-a05a-0d9b0240fb51-S6 --- ---

mongo-rs-1-mongod 10.0.3.152 root R mongo-rs-1-mongod__a039fb0f-6ca7-4706-974a-855542fa5e36 3ba115f5-b4fe-43e9-a05a-0d9b0240fb51-S2 --- ---

mongo-rs-2-mongod 10.0.0.26 root R mongo-rs-2-mongod__5c68c451-c11d-49bd-bf49-e99b8bcceb5c 3ba115f5-b4fe-43e9-a05a-0d9b0240fb51-S1 --- ---

mongogw 10.0.0.44 root R mqtt.instance-565e6b1f-b75d-11e8-9d5d-fe0bc23c90b8.mongogw 3ba115f5-b4fe-43e9-a05a-0d9b0240fb51-S6 --- ---

mosquitto 10.0.0.44 root R mqtt.instance-565e6b1f-b75d-11e8-9d5d-fe0bc23c90b8.mosquitto 3ba115f5-b4fe-43e9-a05a-0d9b0240fb51-S6 --- ---

percona-server-mongodb 10.0.0.26 root R percona-server-mongodb.cfbfcaae-b75b-11e8-9d5d-fe0bc23c90b8 3ba115f5-b4fe-43e9-a05a-0d9b0240fb51-

$ dcos task exec --tty --interactive mongo-rs-0-mongod__f0a27fca-138a-4f39-a0b2-4a1a0960c079 /bin/bash

root@ip-10-0-0-44:/mnt/mesos/sandbox#

用mongo shell客户端访问MongoDB,使用先前创立的用户名,以及DC/OS自动分配给MongoDB的DNS地址别名:

root@ip-10-0-0-44:/mnt/mesos/sandbox# mongo mongodb://mongogw:123456@mongo-rs-0-mongod.percona-server-mongodb.autoip.dcos.thisdcos.directory,mongo-rs-1-mongod.percona-server-mongodb.autoip.dcos.thisdcos.directory,mongo-rs-2-mongod.percona-server-mongodb.autoip.dcos.thisdcos.directory:27017/mongogw?replicaSet=rs

现在我们应该能够看到MongoDB shell提示符了,随后切换到我们的数据库:

rs:PRIMARY> use mongogw;

switched to db mongogw

看看我们的设备集写入了几条记录:

117

当然也可以检视记录详情:

{

"_id" : ObjectId("5b9a6db71284f4000452fd31"),

"date" : ISODate("2018-09-13T14:01:27.529Z"),

"deviceUID" : "f5265ed9-a162-4c72-926d-f537b0ef356c",

"value" : 22,

"gatewayID" : "mqtt.instance-565e6b1f-b75d-11e8-9d5d-fe0bc23c90b8.mongogw"

}

以上输出中我们可以看到,网关对报文进行了处理:

- 转换数据格式

- 添加了时间戳

- 标记了DC/OS网关任务ID(标记是哪个网关实例处理了报文)

我们确认了数据可以从单一设备上采集到,我们修改devce.json,把设备数量扩充到3,更新一下应用:

$ cat device.json

{

"id": "device",

"instances": 3,

"cpus": 0.1,

"mem": 16,

"container": {

"type": "MESOS",

"docker": {

"image": "mattjarvis/device",

"forcePullImage": true,

"privileged": false

}

},

"requirePorts": false

}

$ dcos marathon app update device

我们可以从DC/OS UI里看到设备实例变成了3个,同时在MongoDB层也能看到出现了3个不同的设备UUID值:

{ "_id" : ObjectId("5b9a6ef01284f4000452fdef"), "date" : ISODate("2018-09-13T14:06:40.698Z"), "deviceUID" : "919473a4-b332-4929-9b5e-c0a80f498222", "value" : 24, "gatewayID" : "mqtt.instance-565e6b1f-b75d-11e8-9d5d-fe0bc23c90b8.mongogw" }

{ "_id" : ObjectId("5b9a6ef01284f4000452fdee"), "date" : ISODate("2018-09-13T14:06:40.165Z"), "deviceUID" : "9474a1ee-c1c7-4f1d-a012-c6e4c883c7d3", "value" : 27, "gatewayID" : "mqtt.instance-565e6b1f-b75d-11e8-9d5d-fe0bc23c90b8.mongogw" }

{ "_id" : ObjectId("5b9a6eef1284f4000452fded"), "date" : ISODate("2018-09-13T14:06:39.882Z"), "deviceUID" : "f5265ed9-a162-4c72-926d-f537b0ef356c", "value" : 29, "gatewayID" : "mqtt.instance-565e6b1f-b75d-11e8-9d5d-fe0bc23c90b8.mongogw" }

{ "_id" : ObjectId("5b9a6eee1284f4000452fdec"), "date" : ISODate("2018-09-13T14:06:38.696Z"), "deviceUID" : "919473a4-b332-4929-9b5e-c0a80f498222", "value" : 25, "gatewayID" : "mqtt.instance-565e6b1f-b75d-11e8-9d5d-fe0bc23c90b8.mongogw" }

{ "_id" : ObjectId("5b9a6eee1284f4000452fdeb"), "date" : ISODate("2018-09-13T14:06:38.163Z"), "deviceUID" : "9474a1ee-c1c7-4f1d-a012-c6e4c883c7d3", "value" : 25, "gatewayID" : "mqtt.instance-565e6b1f-b75d-11e8-9d5d-fe0bc23c90b8.mongogw" }

显然,由于我们只部署了一个网关,所有设备都是通过同一个网关接入的。我们试试能不能在网关层扩充一个POD。我们先修改定义采集设备数量的JSON,然后更新POD的设置:

$ dcos marathon pod update mqtt

Created deployment 1fdc863b-9815-417e-87ac-858b56f8630f

当前所有设备都是通过负载均衡虚拟IP接入的,绑定到了第一个网关。如果把设备数量加到5,由于配置了负载均衡,启动运行新设备后,应该能观察到通过新网关接入的流量。可以通过查询MongoDB来验证,应该能够看到接收数据里出现了不止一个网关ID:

{ "_id" : ObjectId("5b9a6f981284f4000452fef9"), "date" : ISODate("2018-09-13T14:09:28.076Z"), "deviceUID" : "f5265ed9-a162-4c72-926d-f537b0ef356c", "value" : 26, "gatewayID" : "mqtt.instance-565e6b1f-b75d-11e8-9d5d- fe0bc23c90b8.mongogw" }

{ "_id" : ObjectId("5b9a6f971284f4000452fef8"), "date" : ISODate("2018-09-13T14:09:27.158Z"), "deviceUID" : "43e2785e-90b2-4cac-9e68-c3b72984f83c", "value": 27, "gatewayID" : "mqtt.instance-565e6b1f-b75d-11e8-9d5d-fe0bc23c90b8.mongogw" }

{ "_id" : ObjectId("5b9a6f964931e30004900d25"), "date" : ISODate("2018-09-13T14:09:26.942Z"), "deviceUID" : "6b9d763b-699e-47eb-8541-704931dbb6e9", "value" : 26, "gatewayID" : "mqtt.instance-6f0de323-b75e-11e8-9d5d-fe0bc23c90b8.mongogw" }

{ "_id" : ObjectId("5b9a6f961284f4000452fef7"), "date" : ISODate("2018-09-13T14:09:26.882Z"), "deviceUID" : "919473a4-b332-4929-9b5e-c0a80f498222", "value" : 30, "gatewayID" : "mqtt.instance-565e6b1f-b75d-11e8-9d5d-fe0bc23c90b8.mongogw" }

{ "_id" : ObjectId("5b9a6f961284f4000452fef6"), "date" : ISODate("2018-09-13T14:09:26.363Z"), "deviceUID" : "9474a1ee-c1c7-4f1d-a012-c6e4c883c7d3", "value" : 26, "gatewayID" : "mqtt.instance-565e6b1f-b75d-11e8-9d5d-fe0bc23c90b8.mongogw" }

我们最终目标是MongoDB层也可以任意扩展:通过往replica集里添加更多实例水平扩展;通过改变实例的规模实现垂直扩展。扩展通过DC/OS UI可以轻松实现。点选Percona-Server-MongoDB服务的”Edit“选项,切换到”MongoDB“选单,将计数由3改至5。修改完配置,点击“Review and Run”,Percona-Server-MongoDB服务会往副本集里另增两个实例。

(新增)部署完成后,我们还会在“服务”选项卡里看到另外两个mongod守候进程实例,修改MongoDB配置不会干扰到Percona-Server-MongoDB服务本身的运行。

综上所述,以上这个IoT应用的演示中,每一层都实现了高可扩展性,DC/OS极大地简化了部署和管理工作。随着传感器设备数量的增长,我们只需在负载均衡背后拉起更多的Mosquitto/网关POD实例即可。同时,借助Percona-Server-MongoDB服务,可以非常容易地实现MongoDB层的水平及垂直扩展。

上述例子中的所有代码、Dockerfile文件,以及Marathon配置,都可以在ttps://github.com/dcos/demos上找到。

原作者:Matt Jarvis,Mesosphere

译者:Isaac Lu, Mesosphere

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181012G1RNP200?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券