基于Predix云远程控制边缘节点的实践

2023-10-12 22:20

本文主要是介绍基于Predix云远程控制边缘节点的实践,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

基于Predix云远程控制边缘节点的实践

在工业互联网的核心场景中,除了使机器拥有感知,不断上传自身的运行数据外,通过云端远程控制边缘节点则是另一个非常重要的场景。因为,只有实现了从云端到设备端反向通信和控制,才能将云端经由大数据运算、优化过的推荐策略反馈到边缘设备端,从而达到优化运营管理、提高设备使用率、降低设备的非计划性停机时间等用户期待的结果。

Predix EdgeManager - 云端远程控制边缘节点的解决方案

Predix EdgeManager是Predix平台中云端远程控制边缘节点的全生命周期解决方案,它可以和Predix Machine完美集成,完成如下功能,

  • 用户权限管理
  • 提供设备注册与分组管理
  • 设备配置、算法的下发
  • 设备状态监控,报警
  • 设备端命令执行
  • 设备端软件依赖管理
  • 设备端软件版本管理

Predix EdgeManager能提供全生命周期的解决方案,但是,目前只针对Predix北美用户开放,中国Predix试用计划的用户还没法申请、试用Predix EdgeManager的服务。

如果只需要从云端远程控制边缘节点的功能,我们完全可以自己实现一个WebSocket服务器推送到Predix平台,从云端下发指令给设备端执行。本文就详细介绍一下,如何基于Predix云通过WebSocket协议远程控制边缘节点的实践

WebSocker服务器软件架构

实现一个WebSocket服务器一点都不困难,因为各种高级语言都有相应的开发框架,我们可以在几分钟内就能完成。真正需要注意的是,当WebSocket服务器已经连接了多个客户端的场景下,如何传递命令到相应的WebSocket客户端,而不是广播给所有的客户端。下图就是我们的一个示例,用Go语言实现的WebSocket服务器。

WebSocket服务器架构如下图所示,


我们可以看到,

  1. WebSocket服务器运行在Predix云平台上。
  2. 客户端通过WebSocket协议与Predix云平台上的WebSocket服务器通信。
  3. 服务器端实现了agentbrokerREST Interface几个核心组件。
  4. 服务器为每个WebSocket连接创建一个agent实例。agent实例一方面负责同WebSocket客户端进行双向通信,另一方面,agent还接收broker下发的命令并转发到客户端。
  5. 服务器创建一个broker实例。该broker实例负责注册每个agent实例,并在接收到具体的命令后,转发给相应的agent实例。也就是说,我们通过broker实例实现了传递命令到相应的WebSocket客户端,而不是广播给所有客户端的功能。
  6. REST Interface实现了/agentsGET方法。因此,用户可以通过浏览器发送相应的请求给broker实例,而broker实例则会转发命令给相应的agent实例。
  7. 同时,REST Interface会为每个请求创建一个callback管道,agent实例将客户端执行命令的结果通过该callback管道返回给REST Interface。因此,用户在浏览器中就可以看到边缘节点执行命令的结果。

Go语言代码实例

介绍完架构设计,让我们看看代码实现。

下载代码示例

git clone https://github.com/pxie/go.in.practices.git
cd go.in.practices/websocket/

实现WebSocket服务器

首先,我们需要实现一个运行在Predix平台的WebSocket服务器,而且实现两个URL的处理函数,

  1. 处理WebSocket客户端通过wss://<主机名>/register注册到服务器的请求
  2. 处理用户通过浏览器访问https://<主机名>/agents获取客户端系统信息的请求

注:严格意义上说,我们实现的服务器同时提供WebSocket接口和RESTful接口,不只是WebSocket服务器。

// server.go
func main() {...http.HandleFunc("/", home)http.HandleFunc("/agents", func(w http.ResponseWriter, r *http.Request) {agentsHandler(broker, w, r)})// create agent, and register it to brokerhttp.HandleFunc("/register", func(w http.ResponseWriter, r *http.Request) {serveWs(broker, w, r)})

实现broker,并初始化一个实例

其次,我们需要实现brokerbroker实例通过register管道接收新创建的agent实例,接着存储到conns键值对中完成agent注册功能。在WebSocket服务器的初始化过程中,通过goroutine来运行一个broker的实例。在本例中,我们使用Go语言的内部类型map存储所有的键值对。如果要实现分布式无状态的横向扩展,我们可以非常方便的将agent实例的信息存储到外部存储服务中,例如Predix云平台的Redis服务。

// broker.go
type broker struct {// register channel to add new websocket connect to brokerregister chan map[string]*agent// channel to get message from http server to brokerhttpCh chan *message// record all websocket connsconns map[string]*agent
}// server.go
func main() {broker := newBroker()go broker.start()

实现agent

再次,我们需要实现agent。每当有新的WebSocket客户端注册到服务器端,就会创建一个agent实例。接着,agent实例会通过register管道把自己注册到broker中。最后,agent会启动一个goroutine接收broker下发的命令,并完成与WebSocket客户端的交互。

// agent.go
type agent struct {// broker to know every agentb *broker// connect to remote client via websocketconn *websocket.Conn// channel get message from brokeragentCh chan *message
}func serveWs(b *broker, w http.ResponseWriter, r *http.Request) {conn, err := upgrader.Upgrade(w, r, nil)ag := &agent{b: b, conn: conn, agentCh: make(chan *message, 256)}agentID := uuid.NewV4().String()// build map to register agentreg := make(map[string]*agent)reg[agentID] = agb.register <- reg// one goroutine to handle communication between agent to remote client, and brokergo ag.start()
}

实现WebSocket客户端

最后,我们需要实现WebSocket客户端,它首先完成向WebSocket服务器的注册,然后就不断监听WebSocket服务器下发的消息,并根据消息的内容,执行相应的处理函数,最终将处理结果通过WebSocket连接返回给WebSocket服务器。

// client/client.go
func main() {addr := "websocket-server.run.aws-jp01-pr.ice.predix.io"u := url.URL{Scheme: "wss", Host: addr, Path: "/register"}log.Printf("connect to %s", u.String())conn, _, err := websocket.DefaultDialer.Dial(u.String(), nil)if err != nil {log.Fatal("connect to websocker server error.", err)}defer conn.Close()ticker := time.NewTicker(10 * time.Second)defer ticker.Stop()for {select {case <-ticker.C:_, msg, err := conn.ReadMessage()if err != nil {log.Fatalln("read message from websocket error.", err)}exec(string(msg), conn)}}
}

推送到Predix云平台

和推送其他应用一样,我们用cf push就可以完成WebSocket服务器的推送。

推送完成的结果如下所示,

requested state: started
instances: 1/1
usage: 170M x 1 instances
urls: websocket-server.run.aws-jp01-pr.ice.predix.io   <-- 推送app后获得的URL
last uploaded: Tue Sep 26 04:20:50 UTC 2017
stack: cflinuxfs2
buildpack: https://github.com/cloudfoundry/go-buildpack.gitstate     since                    cpu    memory         disk           details
#0   running   2017-09-26 12:21:52 PM   0.0%   5.5M of 170M   7.7M of 350M

获取当前所有已注册的agent信息

我们可以通过浏览器访问https://websocket-server.run.aws-jp01-pr.ice.predix.io/agents来获取当前已注册的agent信息。和预期的一样,因为没有任何WebSocket客户端连接到服务器端,所以返回的结果是没有agent已经注册。

注册WebSocket客户端

因为,每个人推送到Predix云平台上WebSocket服务器的URL都是不一样的。因此,我们需要修改客户端的代码,指向正确的地址并重新编译。

// client/client.go
func main() {// 修改为正确的地址addr := "websocket-server.run.aws-jp01-pr.ice.predix.io"}// 保存client.go文件
// 运行go build命令完成编译

当编译完成后,我们就可以运行client/路径下的./client可执行文件,将agent注册到broker

这时,我们再次访问/agents页面就会得到agent相关的信息。

[{"AgentID":"298ee2a5-d43b-426c-b42c-04c14a6aae41","RemoteAddr":"10.120.3.10:8446"}]

查询WebSocket客户端的系统信息

最后,我们可以通过浏览器访问/agents?id=<AgentID>来查询WebSocket客户端的系统信息,包括执行WebSocket客户端的操作系统,CPU信息和主机信息。通过这个请求,我们从浏览器发送命令到指定的agent实例,然后agent将命令转发给WebSocket客户端,客户端执行相应的命令,并把命令执行的结果返回给浏览器展示。

> GET /agents?id=bc93384d-e46b-4508-ab7e-18ec55d9652d HTTP/1.1
> Host: websocket-server.run.aws-jp01-pr.ice.predix.io
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Length: 1073
< Content-Type: text/plain; charset=utf-8
< Date: Tue, 26 Sep 2017 04:57:14 GMT
< X-Vcap-Request-Id: 9cba4b18-e4ba-42fb-5cea-afca45385fd0
<
OS: darwin
CPU: [{"cpu":0,"vendorId":"GenuineIntel","family":"6","model":"70","stepping":1,"physicalId":"","coreId":"","cores":4,"modelName":"Intel(R) Core(TM) i7-4870HQ CPU @ 2.50GHz","mhz":2500,"cacheSize":256,"flags":["fpu","vme","de","pse","tsc","msr","pae","mce","cx8","apic","sep","mtrr","pge","mca","cmov","pat","pse36","clfsh","ds","acpi","mmx","fxsr","sse","sse2","ss","htt","tm","pbe","sse3","pclmulqdq","dtes64","mon","dscpl","vmx","smx","est","tm2","ssse3","fma","cx16","tpr","pdcm","sse4.1","sse4.2","x2apic","movbe","popcnt","aes","pcid","xsave","osxsave","seglim64","tsctmr","avx1.0","rdrand","f16c","smep","erms","rdwrfsgs","tsc_thread_offset","bmi1","avx2","bmi2","invpcid","fpu_csds","syscall","xd","1gbpage","em64t","lahf","lzcnt","rdtscp","tsci"],"microcode":""}]
host: {"hostname":"C02S8EWGG8WP","uptime":14451,"bootTime":1506387382,"procs":308,"os":"darwin","platform":"darwin","platformFamily":"","platformVersion":"10.11.6","kernelVersion":"15.6.0","virtualizationSystem":"","virtualizationRole":"","hostid":"b370db23-7244-3441-b95d-384442442565"}

注:/agents?id=<AgentID>获取的是WebSocket客户端的系统信息,而不是Predix云平台上agent实例的系统信息。

通过这个示例,我们完整演示了如何从云端传递命令到相应的WebSocket客户端,并将执行的结果反馈回云端的全过程。

小结

通过本文我们了解到,

  1. Predix EdgeManager提供了云端远程控制边缘节点的全生命周期解决方案,目前只对北美用户开放。
  2. 基于Predix云,通过WebSocket协议实现远程控制边缘节点是非常简单的。
  3. 在用Go语言实现的版本中,我们大量的使用了Go语言内置的管道和goroutine,做到通过消息通信来共享内存,而不是通过共享内存来完成消息通信。
  4. 本示例只完成了agent注册和云端命令下发到客户端的功能,并没有实现WebSocket持久连接和agent注销功能,大家可以自行完成。

作者:谢品,上海创新坊首席架构师,GE数字集团

专注于工业互联网,云计算,大数据,高性能分布式存储领域,对Cloud Foundry和传统应用向云端,特别是向Predix迁移有丰富的经验,曾供职于VMware,EMC,Autodesk等知名软件公司云计算部门。

这篇关于基于Predix云远程控制边缘节点的实践的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/198835

相关文章

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

golang内存对齐的项目实践

《golang内存对齐的项目实践》本文主要介绍了golang内存对齐的项目实践,内存对齐不仅有助于提高内存访问效率,还确保了与硬件接口的兼容性,是Go语言编程中不可忽视的重要优化手段,下面就来介绍一下... 目录一、结构体中的字段顺序与内存对齐二、内存对齐的原理与规则三、调整结构体字段顺序优化内存对齐四、内

浅析如何使用Swagger生成带权限控制的API文档

《浅析如何使用Swagger生成带权限控制的API文档》当涉及到权限控制时,如何生成既安全又详细的API文档就成了一个关键问题,所以这篇文章小编就来和大家好好聊聊如何用Swagger来生成带有... 目录准备工作配置 Swagger权限控制给 API 加上权限注解查看文档注意事项在咱们的开发工作里,API

C++实现封装的顺序表的操作与实践

《C++实现封装的顺序表的操作与实践》在程序设计中,顺序表是一种常见的线性数据结构,通常用于存储具有固定顺序的元素,与链表不同,顺序表中的元素是连续存储的,因此访问速度较快,但插入和删除操作的效率可能... 目录一、顺序表的基本概念二、顺序表类的设计1. 顺序表类的成员变量2. 构造函数和析构函数三、顺序表

python实现简易SSL的项目实践

《python实现简易SSL的项目实践》本文主要介绍了python实现简易SSL的项目实践,包括CA.py、server.py和client.py三个模块,文中通过示例代码介绍的非常详细,对大家的学习... 目录运行环境运行前准备程序实现与流程说明运行截图代码CA.pyclient.pyserver.py参

使用C++实现单链表的操作与实践

《使用C++实现单链表的操作与实践》在程序设计中,链表是一种常见的数据结构,特别是在动态数据管理、频繁插入和删除元素的场景中,链表相比于数组,具有更高的灵活性和高效性,尤其是在需要频繁修改数据结构的应... 目录一、单链表的基本概念二、单链表类的设计1. 节点的定义2. 链表的类定义三、单链表的操作实现四、

Spring IOC控制反转的实现解析

《SpringIOC控制反转的实现解析》:本文主要介绍SpringIOC控制反转的实现,IOC是Spring的核心思想之一,它通过将对象的创建、依赖注入和生命周期管理交给容器来实现解耦,使开发者... 目录1. IOC的基本概念1.1 什么是IOC1.2 IOC与DI的关系2. IOC的设计目标3. IOC

Spring Boot统一异常拦截实践指南(最新推荐)

《SpringBoot统一异常拦截实践指南(最新推荐)》本文介绍了SpringBoot中统一异常处理的重要性及实现方案,包括使用`@ControllerAdvice`和`@ExceptionHand... 目录Spring Boot统一异常拦截实践指南一、为什么需要统一异常处理二、核心实现方案1. 基础组件

VScode连接远程Linux服务器环境配置图文教程

《VScode连接远程Linux服务器环境配置图文教程》:本文主要介绍如何安装和配置VSCode,包括安装步骤、环境配置(如汉化包、远程SSH连接)、语言包安装(如C/C++插件)等,文中给出了详... 目录一、安装vscode二、环境配置1.中文汉化包2.安装remote-ssh,用于远程连接2.1安装2

SpringBoot项目中Maven剔除无用Jar引用的最佳实践

《SpringBoot项目中Maven剔除无用Jar引用的最佳实践》在SpringBoot项目开发中,Maven是最常用的构建工具之一,通过Maven,我们可以轻松地管理项目所需的依赖,而,... 目录1、引言2、Maven 依赖管理的基础概念2.1 什么是 Maven 依赖2.2 Maven 的依赖传递机