现在,我们需要模拟传感器,生成数据,并发布到 RabbitMQ。

建立传感器项目

在 GOPATH src 下建立文件夹 sensors,使用 go mod init 初始化,并创建 main.go。

同时别忘了安装 amqp 的包:go get -u github.com/streadway/amqp

我们要生成一些模拟数据,生成数据有一定的范围(位于一个最大值和最小值之间),如下图:

因此,我们需要这样几个配置参数:

  1. 传感器的名称

  2. 传感器数据的更新频率

  3. 模拟生成数据的最大值

  4. 模拟生成数据的最小值

  5. 与前一次生成数据的差值的最大值(变化幅度的最大值)

设置命令行参数并读取

在这个项目里,我们需要通过命令行参数来传递配置,并在 Go 程序里面进行解析和读取。我们可以使用 os.Args 来搞这些命令行参数,但是更好的办法是使用 flag 这个包(其内部实现使用的也是 os.Args)。

我们先看代码:

  1. 第 5-9 行,我们声明了 5 个命令行参数。都是使用 flag 包下相应的函数实现的。

    1. 这几个命令行参数分别表示传感器名称、模拟数据的更新频率、模拟数据的最大值、最小值以及变化幅度的最大值。

    2. 这些命令行参数的类型分别是 string,uint,float64,float64,float64。

    3. 这些函数的参数都类似:

      1. 第一个参数是命令行参数的名称

      2. 第二个参数是命令行参数的默认值

      3. 第三个参数是参数的描述/帮助

  2. 在 main 函数里,我们调用     flat.Parse() 函数,就可以将命令行的参数值解析到 5-9 行声明变量里面。

我们测试一下,命令行输入 go run . --help,其结果如下:

生成模拟数据

要生成模拟传感器的数据,需要使用到 math/rand 和 time 这两个包。

先看代码:

  1. 第 17 行,我们需要一个 *rand.Rand 类型来生成随机数,它又需要一个源,这里使用 time.Now().UnixNano() 生成源,这样做的好处是因为这个时间纳秒数永远不会重复。

  2. 第 19 行,声明 value,它表示传感器的数值,在这先生成一个初始值。

  3. 第 20 行,是额定值,在这里也就是最大值最小值的中间平均值。

  4. 第 25 行,把更新频率(每秒更新的次数)转化为了两次更新之间的时间间隔(毫秒),并解析成 time.Duration 这个类型。

  5. 第 26 行,time.Tick 函数会返回一个 time 的 Channel,该函数会按照提供的时间间隔不断触发,并向这个 Channel 发送当前时间。

  6. 第 28 行,使用 for range 来处理 signal 这个 Channel,每次 Channel 中有数据传递过来,我们就使用 calcValue 这个函数来生成新的模拟数据。

  7. 第 29 行,把生成的最新数据打印一下即可。

calcValue 函数

生成模拟数据的逻辑是如果数据偏离额定值,那么尽量让下次生成的值向额定值靠拢。

这部分可根据自己的特定需求来实现,不必和我的相同。

先看代码:

  1. 第 35 行,声明了 maxStep 和 minStep 两个变量,表示本次更新相比上次所能够发生的最大变化和最小变化幅度。

  2. 第 36 - 42     行,区分当前值大于额定值或小于额定值两种情况,按不同的逻辑得出 maxStep 和 minStep

  3. 第 44 行,使用 maxStep     和 minStep 以及随机数生成新的 value 数据。

运行 sensors 项目

使用 go run . 运行,命令行参数使用默认值即可:

一切正常的话,它就会每秒钟生成 5 次数据。

如何运行多个传感器

生产环境中,通常会接收来自多个传感器的数据。

这里,我们让每个传感器都设置自己的路由 Key,所以 RabbitMQ 将会为每个 Key 创建一个 Queue:

但是这也会引起问题,就是之前章节里面的那个协调程序如何发现这些传感器呢?

首先,我们可以让每个传感器使用路由 Key 向一个所有传感器和协调程序都知晓的路径中发送一个消息。但这只能解决问题的一半,另一半我们以后再说。

将传感器数据发布到 RabbitMQ

创建传感器的消息类型

这里会使用到 encoding/gob 包。

看代码:

  • 在 sensors 包中创建 model 包,并建立 models.go 文件。

  • 在 models.go 的第 12 行,建立 SensorMessage 作为传感器传递消息的类型,里面包含三个字段分别是传感器名称、数值和时间戳。

  • 很显然我们不能把 Go 的 struct 类型直接扔到 RabbitMQ 里面,但我们项目中的各种客户端只涉及到 Go 语言,所以在这里我使用 Go 语言的 gob 来对消息进行编码,这样会更高效一些。如果这个项目是跨语言的我可能会使用 JSON 或 Protocol Buffers。

  • 在 model 包的 init 函数里面,需要使用 gob 包的 Register 函数把将要编码的类型进行注册,这样依赖于这个包的其它 Go 程序就可以把     SensorMessage 这个类型的消息对象发送过去了

建立 Queue 相关的工具包

建立 tools 包,并建立 queuetools.go 文件,其内容如下:

代码内容与之前的项目类似,就不解释了。

发布传感器数据到 RabbitMQ

这里还会使用到 bytes 包。

回到 main.go,修改代码:

  1. 前面添加了获取 Channel 和 Queue 的代码。其中第 37 行比较重要,因为我们不能保证在程序运行时,使用 Queue 名称作为路由 Key 的 Queue 存在,而使用 GetQueue 函数,就可以保证这个 Queue 会被正确的设置,并准备好被我们使用了。

  2. 第 42 行,使用 bytes 包创建了一个 *bytes.Buffer,它用来来承载编码后的数据,这个 Buffer 可以重复利用,所以实在 for range 的外部声明的。

    1. 但是每次使用 Buffer 都需要进行重置,也就是第 53 行的作用,这样以前的数据就会被移除,Buffer 的指针会回到初始位置。

  3. 第 43 行,使用 gob 和 Buffer 来创建编码器 。

  4. 第 54 行,使用 编码器的 Encode 方法对消息进行编码。

  5. 第 56 行,创建要发送给 RabbitMQ 的消息(amqp.Publishing 类型),这里只需要填写 Body 字段即可,其它的字段根据自己的需求选填即可。

  6. 第 60 行,使用 Channel 来发布消息,这里使用的是默认的 Exchange,路由 key 就是 Queue 的名字,最后一个参数就是发布的消息。

运行程序

运行 sensors 包:

打开控制台:

可以看到发送频率确实是每秒 5 次。

打开 sensor Queue:

目前已经有 384 条消息了,都没有被发送。

随便点开一个消息查看其内容:

可以看到 Body 应该是 Base64 编码的。因为 gob 编码器使用的是二进制消息格式,尽可能的高效,所以在控制台里面它没有一个有意义的表述展示。

然后,先停止运行程序。

传感器上线时通知协调程序

最后我们就来处理上面那个问题:当传感器上线的时候,得让协调程序知道,并发送数据。

因为每个传感器都创建了一个自己的 Queue,所以在没有帮助的情况下,协调程序将无法有效知道这些传感器。

这个问题实际上具体需要做两件事,我们先来做第一件事:

多个传感器他们 Queue 的名称是不一样的,是动态的,所以我们需要一个大家都知道的 Queue,它用来将每个新创建的传感器的 Queue 名称发送给协调程序。

首先,在 queuetools.go 里面添加这个 Queue 的名称,使用一个常量保存:

然后,在 main.go 里,使用这个名称创建一个 Queue,并将传感器的 Queue 的名称发布上去:

再次运行 sensor 包

打开控制台:

可以看到 SensorList Queue 出现了。

进入到 SensorList Queue,看它的 Message:

可以看到当前这一个传感器的名字 sensor 就在里面。

 
 

RabbitMQ 入门 (Go) - 3. 模拟传感器,生成数据并发布的更多相关文章

  1. RabbitMQ 入门 (Go) - 4. 使用 Fanout Exchange 做服务发现(上)

    到目前为止,我们项目的结果大致如下: 传感器生成的模拟数据(包含传感器名称.数据.时间戳)是通过传感器在运行时动态创建的 Queue 来发送的.这些 Queue 很难直接被发现. 为了解决这个问题,我 ...

  2. RabbitMQ 入门 (Go) - 6. 数据持久化(上)

    从本节开始,我介绍一下如何将相关数据持久化到数据库,也就是上图中蓝色的部分. 目前的问题 我先运行 6 个传感器和2 个协调器,这里我使用了批处理文件: 运行后,看一下 RabbitMQ 的管理控制台 ...

  3. RabbitMQ 入门 (Go) - 7. 数据持久化(下)【完】

    数据库 我使用的是 PostgreSQL. 使用的驱动是 github.com/lib/pq 这个网址 https://pkg.go.dev/github.com/lib/pq 是官方文档. 创建数据 ...

  4. 【详细】【转】C#中理解委托和事件 事件的本质其实就是委托 RabbitMQ英汉互翼(一),RabbitMQ, RabbitMQ教程, RabbitMQ入门

    [详细][转]C#中理解委托和事件   文章是很基础,但很实用,看了这篇文章,让我一下回到了2016年刚刚学委托的时候,故转之! 1.委托 委托类似于C++中的函数指针(一个指向内存位置的指针).委托 ...

  5. [转]RabbitMQ入门教程(概念,应用场景,安装,使用)

    原文地址:https://www.jianshu.com/p/dae5bbed39b1 RabbitMQ 简介 RabbitMQ是一个在AMQP(Advanced Message Queuing Pr ...

  6. .NET 环境中使用RabbitMQ RabbitMQ与Redis队列对比 RabbitMQ入门与使用篇

    .NET 环境中使用RabbitMQ   在企业应用系统领域,会面对不同系统之间的通信.集成与整合,尤其当面临异构系统时,这种分布式的调用与通信变得越发重要.其次,系统中一般会有很多对实时性要求不高的 ...

  7. RabbitMQ入门教程(十六):RabbitMQ与Spring集成

    原文:RabbitMQ入门教程(十六):RabbitMQ与Spring集成 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https: ...

  8. RabbitMQ 入门 (Go) - 5. 使用 Fanout Exchange 做服务发现(下)

    到目前为止,我一直专注于如何让消息进出消息代理,也就是RabbitMQ. 实际上,我们可以继续使用 RabbitMQ 和它的 Exchanges 来连接这个应用程序的其他部分,但是我想探索一个稍微不同 ...

  9. RabbitMQ入门到进阶(Spring整合RabbitMQ&SpringBoot整合RabbitMQ)

    1.MQ简介 MQ 全称为 Message Queue,是在消息的传输过程中保存消息的容器.多用于分布式系统 之间进行通信. 2.为什么要用 MQ 1.流量消峰 没使用MQ 使用了MQ 2.应用解耦 ...

随机推荐

  1. GitHub & JavaScript & Trending

    GitHub & JavaScript & Trending Trending JavaScript repositories on GitHub this week https:// ...

  2. 系统错误,MSVCP100D.dll找不到或丢失!

    文章首发 | 公众号:lunvey 今日研究c++,找了一些示例程序,发现无法打开.弹出如下的报错提示: 作为新时代人类,遇见问题第一件事情就是问度娘.然而眼花缭乱的检索数据,大家众说纷纭,不知道如何 ...

  3. (1)MySQL进阶篇在linux环境下安装

    1.概述 对于mysql二进制安装,优点是可以安装到任何路径下,灵活性好,一台服务器可以安装多个mysql.缺点是已经编译过,性能不如源码编译得好,不能灵活定制编译参数.如果用户即不想安装最简单却不够 ...

  4. 关于Sidecar Pattern

    本文转载自关于Sidecar Pattern 导语 Sidecar 是一个很纠结的名字,我们在翻译技术雷达时采用了一个比较通俗的翻译,即边车,而这个词随着微服务的火热与 Service Mesh 的逐 ...

  5. SpringBoot注解集合

    使用注解的优势: 1.采用纯java代码,不在需要配置繁杂的xml文件 2.在配置中也可享受面向对象带来的好处 3.减少复杂配置文件的同时亦能享受到springIoC容器提供的功能 @SpringBo ...

  6. 更换 grub 主题

    默认的 grub 界面比较简陋 然后突然有想法了,想换个主题 具体操作 1.下载 grub 主题包 去这个地址下载主题(应该是这个地址): https://www.gnome-look.org/bro ...

  7. nacos服务注册之服务器端Distro

    一致性协议算法Distro阿里自己的创的算法吧,网上能找到的资料很少.Distro用于处理ephemeral类型数据 Distro协议算法看代码大体流程是: nacos启动首先从其他远程节点同步全部数 ...

  8. PHP Webshell List

    目录 基础类 编码替换 无关键字函数类型 躲避检测记录 MySQL写入一句话 基础类 很容易被扫描.检测出来 <?php @eval($_GET['phpcode']);?> <?p ...

  9. jquery动态赋值id与动态取id方法

    $("#" + packageNameId + "").text(packageName); $("#" + packageNumId + ...

  10. 剑指 Offer 53 - I. 在排序数组中查找数字 I + 二分法

    剑指 Offer 53 - I. 在排序数组中查找数字 I Offer_53_1 题目描述 方法一:使用HashMap package com.walegarrett.offer; /** * @Au ...