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

相关文章

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

day-51 合并零之间的节点

思路 直接遍历链表即可,遇到val=0跳过,val非零则加在一起,最后返回即可 解题过程 返回链表可以有头结点,方便插入,返回head.next Code /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}*

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟)

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟) 题目描述 给定一个链表,链表中的每个节点代表一个整数。链表中的整数由 0 分隔开,表示不同的区间。链表的开始和结束节点的值都为 0。任务是将每两个相邻的 0 之间的所有节点合并成一个节点,新节点的值为原区间内所有节点值的和。合并后,需要移除所有的 0,并返回修改后的链表头节点。 思路分析 初始化:创建一个虚拟头节点

Prometheus与Grafana在DevOps中的应用与最佳实践

Prometheus 与 Grafana 在 DevOps 中的应用与最佳实践 随着 DevOps 文化和实践的普及,监控和可视化工具已成为 DevOps 工具链中不可或缺的部分。Prometheus 和 Grafana 是其中最受欢迎的开源监控解决方案之一,它们的结合能够为系统和应用程序提供全面的监控、告警和可视化展示。本篇文章将详细探讨 Prometheus 和 Grafana 在 DevO

springboot整合swagger2之最佳实践

来源:https://blog.lqdev.cn/2018/07/21/springboot/chapter-ten/ Swagger是一款RESTful接口的文档在线自动生成、功能测试功能框架。 一个规范和完整的框架,用于生成、描述、调用和可视化RESTful风格的Web服务,加上swagger-ui,可以有很好的呈现。 SpringBoot集成 pom <!--swagge

控制反转 的种类

之前对控制反转的定义和解释都不是很清晰。最近翻书发现在《Pro Spring 5》(免费电子版在文章最后)有一段非常不错的解释。记录一下,有道翻译贴出来方便查看。如有请直接跳过中文,看后面的原文。 控制反转的类型 控制反转的类型您可能想知道为什么有两种类型的IoC,以及为什么这些类型被进一步划分为不同的实现。这个问题似乎没有明确的答案;当然,不同的类型提供了一定程度的灵活性,但

深入解析秒杀业务中的核心问题 —— 从并发控制到事务管理

深入解析秒杀业务中的核心问题 —— 从并发控制到事务管理 秒杀系统是应对高并发、高压力下的典型业务场景,涉及到并发控制、库存管理、事务管理等多个关键技术点。本文将深入剖析秒杀商品业务中常见的几个核心问题,包括 AOP 事务管理、同步锁机制、乐观锁、CAS 操作,以及用户限购策略。通过这些技术的结合,确保秒杀系统在高并发场景下的稳定性和一致性。 1. AOP 代理对象与事务管理 在秒杀商品