基于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

相关文章

用js控制视频播放进度基本示例代码

《用js控制视频播放进度基本示例代码》写前端的时候,很多的时候是需要支持要网页视频播放的功能,下面这篇文章主要给大家介绍了关于用js控制视频播放进度的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言html部分:JavaScript部分:注意:总结前言在javascript中控制视频播放

Spring Boot 配置文件之类型、加载顺序与最佳实践记录

《SpringBoot配置文件之类型、加载顺序与最佳实践记录》SpringBoot的配置文件是灵活且强大的工具,通过合理的配置管理,可以让应用开发和部署更加高效,无论是简单的属性配置,还是复杂... 目录Spring Boot 配置文件详解一、Spring Boot 配置文件类型1.1 applicatio

tomcat多实例部署的项目实践

《tomcat多实例部署的项目实践》Tomcat多实例是指在一台设备上运行多个Tomcat服务,这些Tomcat相互独立,本文主要介绍了tomcat多实例部署的项目实践,具有一定的参考价值,感兴趣的可... 目录1.创建项目目录,测试文China编程件2js.创建实例的安装目录3.准备实例的配置文件4.编辑实例的

Python 中的异步与同步深度解析(实践记录)

《Python中的异步与同步深度解析(实践记录)》在Python编程世界里,异步和同步的概念是理解程序执行流程和性能优化的关键,这篇文章将带你深入了解它们的差异,以及阻塞和非阻塞的特性,同时通过实际... 目录python中的异步与同步:深度解析与实践异步与同步的定义异步同步阻塞与非阻塞的概念阻塞非阻塞同步

Python Dash框架在数据可视化仪表板中的应用与实践记录

《PythonDash框架在数据可视化仪表板中的应用与实践记录》Python的PlotlyDash库提供了一种简便且强大的方式来构建和展示互动式数据仪表板,本篇文章将深入探讨如何使用Dash设计一... 目录python Dash框架在数据可视化仪表板中的应用与实践1. 什么是Plotly Dash?1.1

springboot集成Deepseek4j的项目实践

《springboot集成Deepseek4j的项目实践》本文主要介绍了springboot集成Deepseek4j的项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录Deepseek4j快速开始Maven 依js赖基础配置基础使用示例1. 流式返回示例2. 进阶

Python异步编程中asyncio.gather的并发控制详解

《Python异步编程中asyncio.gather的并发控制详解》在Python异步编程生态中,asyncio.gather是并发任务调度的核心工具,本文将通过实际场景和代码示例,展示如何结合信号量... 目录一、asyncio.gather的原始行为解析二、信号量控制法:给并发装上"节流阀"三、进阶控制

使用DrissionPage控制360浏览器的完美解决方案

《使用DrissionPage控制360浏览器的完美解决方案》在网页自动化领域,经常遇到需要保持登录状态、保留Cookie等场景,今天要分享的方案可以完美解决这个问题:使用DrissionPage直接... 目录完整代码引言为什么要使用已有用户数据?核心代码实现1. 导入必要模块2. 关键配置(重点!)3.

Android App安装列表获取方法(实践方案)

《AndroidApp安装列表获取方法(实践方案)》文章介绍了Android11及以上版本获取应用列表的方案调整,包括权限配置、白名单配置和action配置三种方式,并提供了相应的Java和Kotl... 目录前言实现方案         方案概述一、 androidManifest 三种配置方式

Spring Boot中定时任务Cron表达式的终极指南最佳实践记录

《SpringBoot中定时任务Cron表达式的终极指南最佳实践记录》本文详细介绍了SpringBoot中定时任务的实现方法,特别是Cron表达式的使用技巧和高级用法,从基础语法到复杂场景,从快速启... 目录一、Cron表达式基础1.1 Cron表达式结构1.2 核心语法规则二、Spring Boot中定