分类 工业物联网 下的文章

目录:

一、微服务架构演进过程

二、微服务架构的好处

三、微服务应用4个设计原则

四、微服务架构带来的问题

五、微服务平台的19个落地实践

六、总结展望

一、微服务架构演进过程
2effedef6a25ff9a029a829e23725201.jpg
近年来我们大家都体会到了互联网、移动互联带来的好处,作为IT从业者,在生活中时刻感受互联网好处的同时,在工作中可能感受的却是来自自互联网的一些压力,那就是我们传统企业的IT建设也是迫切需要转型,需要面向外部客户,我们也需要应对外部环境的快速变化、需要快速创新,那么我们的IT架构也需要向互联网企业学习作出相应的改进,来支撑企业的数字化转型。

我们再看一下应用架构的演进过程,回忆一下微服务架构是如何一步一步进化产生的,最早是应用是单块架构,后来为了具备一定的扩展和可靠性,就有了垂直架构,也就是加了个负载均衡,接下来是前几年比较火的SOA,主要讲了应用系统之间如何集成和互通,而到现在的微服务架构则是进一步在探讨一个应用系统该如何设计才能够更好的开发、管理更加灵活高效。

微服务架构的基本思想就是“围绕业务领域组件来创建应用,让应用可以独立的开发、管理和加速”。

二、微服务架构的好处
acf5f894ee9345409bb2be41976bc1bd.jpg
我们总结了四个方面的优点,分别如下:

是每个微服务组件都是简单灵活的,能够独立部署。不再像以前一样,应用需要一个庞大的应用服务器来支撑。

可以由一个小团队负责更专注专业,相应的也就更高效可靠。

微服务之间是松耦合的,微服务内部是高内聚的,每个微服务很容易按需扩展。

微服务架构与语言工具无关,自由选择合适的语言和工具,高效的完成业务目标即可。

看到这里,大家会觉得微服务架构挺不错,然而还会有一些疑问,什么样的应用算是一个微服务架构的应用?该怎样设计一个微服务架构的应用?那我们来一起看看我们推荐的微服务应用的设计原则。

三、微服务应用4个设计原则
3fca8e2009ab2745f53c082c1752f0e6.jpg

我们总结了四个原则推荐给大家:

AKF拆分原则

前后端分离

无状态服务

Restful通信风格

1.AKF拆分原则
338d631f424e18d3a331311693804843.jpg
AKF扩展立方体(参考《The Art of Scalability》),是一个叫AKF的公司的技术专家抽象总结的应用扩展的三个维度。理论上按照这三个扩展模式,可以将一个单体系统,进行无限扩展。

X 轴 :指的是水平复制,很好理解,就是讲单体系统多运行几个实例,做个集群加负载均衡的模式。

Z 轴 :是基于类似的数据分区,比如一个互联网打车应用突然或了,用户量激增,集群模式撑不住了,那就按照用户请求的地区进行数据分区,北京、上海、四川等多建几个集群。

Y 轴 :就是我们所说的微服务的拆分模式,就是基于不同的业务拆分。

场景说明:比如打车应用,一个集群撑不住时,分了多个集群,后来用户激增还是不够用,经过分析发现是乘客和车主访问量很大,就将打车应用拆成了三个乘客服务、车主服务、支付服务。三个服务的业务特点各不相同,独立维护,各自都可以再次按需扩展。

2.前后端分离
16d8fcc185c70b24033bcb36c99942df.jpg
前后端分离原则,简单来讲就是前端和后端的代码分离也就是技术上做分离,我们推荐的模式是最好直接采用物理分离的方式部署,进一步促使进行更彻底的分离。不要继续以前的服务端模板技术,比如JSP ,把Java JS HTML CSS 都堆到一个页面里,稍复杂的页面就无法维护。这种分离模式的方式有几个好处:

前后端技术分离,可以由各自的专家来对各自的领域进行优化,这样前端的用户体验优化效果会更好。

分离模式下,前后端交互界面更加清晰,就剩下了接口和模型,后端的接口简洁明了,更容易维护。

前端多渠道集成场景更容易实现,后端服务无需变更,采用统一的数据和模型,可以支撑前端的web UI 移动App等访问。

3.无状态服务
11299392d486ea5b840c25a82668d9fb.jpg
对于无状态服务,首先说一下什么是状态:如果一个数据需要被多个服务共享,才能完成一笔交易,那么这个数据被称为状态。进而依赖这个“状态”数据的服务被称为有状态服务,反之称为无状态服务。

那么这个无状态服务原则并不是说在微服务架构里就不允许存在状态,表达的真实意思是要把有状态的业务服务改变为无状态的计算类服务,那么状态数据也就相应的迁移到对应的“有状态数据服务”中。

场景说明:例如我们以前在本地内存中建立的数据缓存、Session缓存,到现在的微服务架构中就应该把这些数据迁移到分布式缓存中存储,让业务服务变成一个无状态的计算节点。迁移后,就可以做到按需动态伸缩,微服务应用在运行时动态增删节点,就不再需要考虑缓存数据如何同步的问题。

4.Restful通信风格
2f54a950b11dbf3333c7d2eb56272d20.jpg
作为一个原则来讲本来应该是个“无状态通信原则”,在这里我们直接推荐一个实践优选的Restful 通信风格 ,因为他有很多好处:

无状态协议HTTP,具备先天优势,扩展能力很强。例如需要安全加密是,有现成的成熟方案HTTPS可用。

JSON 报文序列化,轻量简单,人与机器均可读,学习成本低,搜索引擎友好。

语言无关,各大热门语言都提供成熟的Restful API框架,相对其他的一些RPC框架生态更完善。

当然在有些特殊业务场景下,也需要采用其他的RPC框架,如thrift、avro-rpc、grpc。但绝大多数情况下Restful就足够用了。

四、微服务架构带来的问题

做到了前面讲的四个原则,那么就可以说是构建了一个微服务应用,感觉上也不复杂。但实际上微服务也不是个万金油,也是有利有弊的,接下来我们来看看引入微服务架构后带来的问题有哪些。
ae037625815c7bf1a77b99f7a161d578.jpg
依赖服务变更很难跟踪,其他团队的服务接口文档过期怎么办?依赖的服务没有准备好,如何验证我开发的功能。

部分模块重复构建,跨团队、跨系统、跨语言会有很多的重复建设。

微服务放大了分布式架构的系列问题,如分布式事务怎么处理?依赖服务不稳定怎么办?

运维复杂度陡增,如:部署物数量多、监控进程多导致整体运维复杂度提升。

上面这些问题我们应该都遇到过,并且也会有一些解决方案,比如提供文档管理、服务治理、服务模拟的工具和框架; 实现统一认证、统一配置、统一日志框架、分布式汇总分析; 采用全局事务方案、采用异步模拟同步;搭建持续集成平台、统一监控平台等等。

这些解决方案折腾到最后终于搞明白了,原来我们是需要一个微服务应用平台才能整体性的解决这些问题。

五、微服务平台的19个落地实践

1.企业IT建设的三大基础环境

我们先来宏观的看一下,一个企业的IT建设非常重要的三大基础环境:团队协作环境、个人基础环境、IT基础设施。
b92e6d900473315141a009eebaab4ef8.jpg
团队协作环境:主要是DevOps领域的范畴,负责从需求到计划任务,团队协作,再到质量管理、持续集成和发布。

个人基础环境:就是本文介绍的微服务应用平台,他的目标主要就是要支撑微服务应用的设计开发测试,运行期的业务数据处理和应用的管理监控。

IT基础设施:就是我们通常说的各种运行环境支撑如IaaS (VM虚拟化)和CaaS (容器虚拟化)等实现方式。
2.微服务应用平台总体架构
8f24e3c9eb25ebeb98138d20c862f3f0.jpg
微服务应用平台的总体架构,主要是从开发集成、微服务运行容器与平台、运行时监控治理和外部渠道接入等维度来划分的。

开发集成:主要是搭建一个微服务平台需要具备的一些工具和仓库

运行时:要有微服务平台来提供一些基础能力和分布式的支撑能力,我们的微服务运行容器则会运行在这个平台之上。

监控治理:则是致力于在运行时能够对受管的微服务进行统一的监控、配置等能力。

服务网关: 则是负责与前端的WEB应用 移动APP 等渠道集成,对前端请求进行认真鉴权,然后路由转发。
3.微服务应用平台的运行视图
5ac037cabc09cba45997a7b068955f2c.jpg
参考上图,在运行期,作为一个微服务架构的平台与业务系统,除了业务应用本身外,还需要有接入服务、统一门户、基础服务等平台级服务来保障业务系统的可靠运行。图中的公共服务就是业务处理过程中需要用到的一些可选服务。
4.微服务平台的设计目标
26b62e01bc1cfc2b3344f755ab43fc01.jpg
微服务平台的主要目标主要就是要支撑微服务应用的全生命周期管理,从需求到设计开发测试,运行期的业务数据处理和应用的管理监控等,后续将从应用生命周期的几个重要阶段切入,结合前面提到的设计原则和问题,介绍平台提供的能力支撑情况。
5.微服务开发:前端、后端、混合
9455328c6a2214c193d64f05f07d33ad.jpg
我们一起看一下我们正在开发中的微服务应用平台EOS8.0的一些开发工具截图,了解一下开发期提供了哪些关键的能力支撑。

前面的设计原则中提到了一个前后端分离的原则,那么我们的开发环境中,目前支持创建前端项目、后端项目和混合项目。其中前端项目、后端项目就对应前后端分离的原则,利用平台中集成的开发工具和框架可以做到前后端开发分离,利用持续集成工具可以方便的将前端、后端项目编译打包成可独立运行的程序。混合项目则是为了兼容传统模式而保留的,为企业应用向微服务架构演进提供过渡方案。

6.服务契约与API管理
对于前面提到的微服务带来的依赖管理问题,我们可以通过平台提供的API管理能力来解决。说到API管理,那首先就用提到服务契约。平台开发工具中提供了方便的服务发布能力,能够快速的将业务功能对外发布,生成服务的规格契约,当然也可以先设计服务契约,在根据契约来生成服务的默认实现代码。

这里强调一下,我们提到的服务契约是一个很重要的东西,他有点类似web service的wsdl描述,主要描述服务接口的输入输出规格标准和其他一些服务调用集成相关的规格内容。
eb5261fb9828a52e6e5fe1a507d3eb26.jpg
7.服务契约与服务模拟
有了服务契约,我们就可以根据契约自动生成服务的文档和服务模拟测试环境,这样,开发者就可以方便的获取到依赖服务变更的情况,能够及时的根据依赖服务的变化调整自己的程序,并且能够方便的进行模拟测试验证。
1b88da68c1e07aa268eb3deeb5e58345.jpg
根据契约生成模拟服务也就是我们常说的服务挡板,这样即使依赖的其他服务还无法提供功能,我们也可以通过挡板来进行联调测试。

8.服务契约与服务编排
f70d729d6a60a05e28278451e092ae2b.jpg
有了服务契约,那就有了服务接口的输入输出规格,那么restful的服务编排也就变得可行。在我们设计的契约标准中,还定义了调用集成相关的内容,比如服务支持的事务模式等等。通过这些约定,我们就可以采用简单图形化的方式来对业务服务流程进行编排。编排能够很大程度上简化分布式服务调用的复杂度,如同步、异步、异步模拟同步、超时重试、事务补偿等,均有服务编排引擎完成,不再完全依赖老师傅的编码能力。

服务编排的作用和意义很大,可以快速的将已经提供的微服务能力进行组合发布,非常适合业务的快速创新。

但是大家要注意,逻辑流编排的是业务流程,尽量能够简单明了,一眼看上去就明白业务含义。而业务规则推荐采用服务内部进行编码实现。千万不要将我们的 “逻辑流” 图形化服务编排完全取代程序编码,这样就会可能会走入另外一个极端,比如设计出像蜘蛛网一样的逻辑流图,简直就是灾难。
9.微服务容器
3ff83ecd25032a344f577e9de0385676.jpg
我们再来看一下微服务运行容器的一个逻辑图,大家可以看到,我们要做微服务架构的应用,可靠高效的微服务应用,实际上我们需要做的事情还是非常多的。如果没有一个统一的微服务容器,这些能力在每个微服务组件中都需要建设一遍,而且会五花八门,也很难集成到一起。有了统一的微服务运行容器和一些公共的基础服务,前面所提到的微服务架构下部分组件重复建设的问题也迎刃而解。
10.三方能力集成说明
我们的API管理契约文档API模拟我们是集成了Swagger的工具链。微服务应用平台的基础就是SpringCloud,从容器框架到注册发现再到安全认证这些基础方案均采用了他的能力来支撑。下面简单看下我们集成的一些开源框架和工具。
8d6bcae6b9544aa807efe3522b5c2ec0.jpg
SpringCloud在微服务平台中的定位是基础框架,本文重点是要介绍一个企业级的微服务平台在落地过程中的一些设计原则和解决方案。具体Spring Cloud 相关的技术就不在文中多做介绍了,大家可以在我们的公众号里面查看相关文章。

11.服务注册发现路由
da0f74773e77c1013e4a5adbdeb96a52.jpg
接下来我们聊一下注册发现,以前的单块应用之间互相调用时配置个IP就行了,但在微服务架构下,服务提供者会有很多,手工配置IP地址又变成了一个不可行的事情。那么服务自动注册发现的方案就解决了这个问题。

我们的服务注册发现能力是依赖SpringCloud Eureka组件实现的。服务在启动的时候,会将自己要发布的服务注册到服务注册中心,运行时,如果需要调用其他微服务的接口,那么就要先到注册中心获取服务提供者的地址,拿到地址后,通过微服务容器内部的简单负载均衡期进行路由用。

一般情况,系统内微服务的调用都通过这种客户端负载的模式进行,否则就需要有很多的负载均衡进程。跨业务系统的服务调用,也可以采用这种去中心化的路由方式。当然采用SOA的模式,由中心化的服务网管来管理系统间的调用也是另一种选择,要结合企业的IT现状和需求来决定。
12.统一认证鉴权
750eaae688f5b27a584e5db8e910ebc1.jpg
安全认证方面,我们基于Spring Security结合Auth2再加上JWT(Json web token)做安全令牌,实现统一的安全认证与鉴权,使得微服务之间能够按需隔离和安全互通。后续在统一认证和权限方面我们产品会陆续推出较完善并且扩展性良好的微服务组件,可以作为微服务平台的公共的认证和鉴权服务。再啰嗦一句,认证鉴权一定是个公共的服务,而不是多个系统各自建设。

13.日志与流水设计
a2b42e355834fec265c33bdb033b48a2.jpg
作为一个微服务应用平台除了提供支撑开发和运行的技术组件和框架之外,我们还提供一些运维友好的经验总结,我们一起来看一下我们推荐的日志与流水实现,先来看日志,平台默认回会提供的日志主要有三种,系统日志,引擎日志还有跟踪日志。有了这些日志,在出问题的时候能够帮助我们获取一些关键信息进行问题定位。

要想做到出了问题能够追根溯源,那么右边的这些流水号的设计也是非常重要的,日志与各种流水号配合,能够让我们快速定位问题发生的具体时间地点以及相关信息,能够快速还原业务交易全链路。对这些日志与流水的细节处理,对于系统运维问题定位有非常大的帮助,没有这些有用的日志内容,ELK日志收集套件搭建的再漂亮,收一对垃圾日志也是没用的。通常开源框架只是提供个框架有开发人员自由发挥,而设计一个平台则一定要考虑直接提供统一规范的基础能力。
14.集中配置管理
759185261b83941a40f221dd2fa339fd.jpg
微服务分布式环境下,一个系统拆分为很多个微服务,一定要告别投产或运维手工修改配置配置的方式。需要采用集中配置管理的方式来提升运维的效率。

配置文件主要有运行前的静态配置和运行期的动态配置两种。静态配置通常是在编译部署包之前设置好。动态配置则是系统运行过程中需要调整的系统变量或者业务参数。要想做到集中的配置管理,那么需要注意以下几点。

是配置与介质分离,这个就需要通过制定规范的方式来控制。千万别把配置放在Jar包里。

是配置的方式要统一,格式、读写方式、变更热更新的模式尽量统一,要采用统一的配置框架

就是需要运行时需要有个配置中心来统一管理业务系统中的配置信息,这个就需要平台来提供配置中心服务和配置管理门户。
15.统一管理门户
4b9aa2a8ff9b0fe24d33ff5f09bcd397.jpg
微服务架构下,一个大的EAR、WAR应用被拆为了多个小的可独立运行的微服务程序,通常这些微服务程序都不再依赖应用服务器,不依赖传统应用服务器的话,应用服务器提供管理控制台也就没得用了,所以微服务的运行时管理需要有统一的管理门户来支撑。我们规划了的统一集中的微服务门户,可以支撑 应用开发、业务处理、应用管理、系统监控等。上图是应用管理页面,就是对我们传统意义上的业务系统进行管理,点击一个业务系统,我们就能够看到系统下有哪些微服务,每个微服务有几个节点实例再运行,可以监控微服务的子节点状态,对微服务进行配置管理和监控。

16.分布式事务问题
9541fd49d753a293e7d2797d1c6c11b8.jpg
微服务架构的系统下,进程成倍增多,那么也分布式事务一致性的问题也就更加明显。我们这里说的事务一致性,不是传统说的基于数据库实现的技术事务。微服务之间是独立的、调用协议也是无状态的,因此数据库事务方案在一开始就已经不再我们考虑的范围内。我们要解决的是一定时间后的数据达到最终一致状态,准确的说就是采用传统的业务补偿与冲正方式。

推荐的事务一致性方案有三种:

可靠事件模式:即事件的发送和接收保障高可靠性,来实现事务的一致性。

补偿模式:Confirm Cancel ,如果确认失败,则全部逆序取消。

TCC模式:Try Confirm Cancel ,补偿模式的一种特殊实现 通常转账类交易会采用这种模式。

17.分布式同步调用问题
a20c2fd6500880bc1ce6b64b823b1609.jpg
微服务架构下,相对于传统部署方式,存在更多的分布式调用,那么“如何在不确定的环境中交付确定的服务”,这句话可以简单理解为,我所依赖的服务的可靠性是无法保证的情况下,我如何保证自己能够正常的提供服务,不被我依赖的其他服务拖垮?

我们推荐SEDA架构来解决这个问题。
f2f59ea4fece156ab9929a73fb74e3d6.jpg
SEDA : staged event-driven architecture本质上就是采用分布式事件驱动的模式,用异步模拟来同步,无阻塞等待,再加上资源分配隔离结起来的一个解决方案。

18.持续集成与持续交付设计
6503f3c9cea84de1efabbdee40297d65.jpg
在运维方面,首先我们要解决的就是持续集成和持续交付,而微服务应用平台的职责范围目前规划是只做持续集成,能够方便的用持续集成环境把程序编译成介质包和部署包。(目前规划持续部署由DevOps平台提供相应能力,微服务平台可与DevOps平台集成)

这里要厘清一个概念:介质,是源码编译后的产物,与环境无关,多环境下应该是可以共用的,如:jar、dockerfile;配置:则是环境相关的信息。配置+介质=部署包。

获取到部署包之后,微服务应用平台的职责就完成了,接下来就是运维人员各显神通来进行上线部署操作。
19.微服务平台与容器云、DevOps的关系
27cbe603a63ec9d939d3ea0a0dce7443.jpg
就微服务应用平台本身来说,并不依赖DevOps和容器云,开发好的部署包可以运行在物理机、虚拟机或者是容器中。

然而当微服务应用平台结合了DevOps和容器云之后,我们就会发现,持续集成和交付变成了一个非常简单便捷并且又可靠的过程。

简单几步操作,整套开发、测试、预发或者生产环境就能够搭建完成。整个过程的复杂度都由平台给屏蔽掉了,通过三大基础环境的整合,我们能够使分散的微服务组件更简单方便的进行统一管理和运维交付。

六、总结展望

我们再来回顾一下,三大基础环境的关系。微服务应用平台负责应用开发、运行以及管理;DevOps负责项目管理、计划管理、CI、CD和团队沟通协作等;容器云平台则负责基础设置管理,屏蔽环境的复杂度。

这三大基础环境的建设情况,直接反应出了企业IT能力水平。这三大基础环境是技术人员和企业都希望拥有的,是企业赢得竞争、驱动业务创新的基础,是企业加速数字化转型的必由之路。

什么是Modbus

Modbus和OPC UA、mqtt本质一样,都是为了实现多个设备相互通信的应用层协议。Modbus于1979年产生于Modicon公司(现被Schneider公司收购),一经面世因其简单开放的通信方式逐渐成为工业系统中流行的标准。Modbus的国际组织主要有Modbus-IDA,负责推广Modbus标准以及对Modbus产品进行认证。Modbus官网见 www.modbus.org,网站主要包括协议文档,Modbus产品和厂商等内容。

之前的物联网IoT协议之OPC UA快速入门教程中提到OPC UA是工业领域常用的协议,其实在工业领域中Modbus比OPC/OPC UA更常见,市面上很多数据采集设备(如温湿度采集)都使用Modbus协议;OPC UA大量的专有名词(如节点、服务、引用等)总能把初学者弄得云里雾里,而Modbus比OPC UA简单太多了,简单之处体现包括:

Modbus最开始使用RS232,RS485等串行链路作为底层通信方式,串行总线的接口芯片成本低,而且布线也简单方便;
Modbus是简单的应用层协议,其信息格式简单易懂,下文会详细讲述协议内容;
Modbus相关的资料文档有很多。

什么是总线/什么是Modbus总线

Modbus中的bus是总线的意思,那么什么是总线呢?总线是一种网络拓扑结构,网络拓扑结构有星型、环型、树型、总线型等多种,总线型拓扑结构是其中一种。无论哪种网络拓扑结构,最终都是为了实现多个设备相互通信。

两个设备相互通信,用一条线把两个设备连接起来即可。
modbus_ab.png
三个设备相互通信,两两相连需要3条线。
modbus_abc.png
四个设备相互通信,两两相连需要6条线。
modbus_abcd.png
很明显,随着设备个数的增加,两两相连需要的线按指数级增长,所以两两相连的方式肯定是不合适了,总线型拓扑结构通过引入总线来解决多个设备连线并通信的问题。
modbus_bus.png
多个设备复用同一条总线,减少了布线的复杂度;但是复用同一条总线时会遇到新的问题,当多个设备同时发送数据,数据会产生冲突。为了避免数据冲突,有多种解决办法,比如以太网使用的CSMA/CD(即载波侦听多路访问/冲突检测),CSMA协议要求设备在发送数据之前先监听总线/信道,如果总线空闲,设备就可以发送数据,如果总线忙,则设备不能发送数据;而Modbus采用了一种更简单的避免冲突的方式,即主从通信模式。

Modbus的主从通信模式

Modbus为了避免多个设备数据的冲突,使用了单主机/多从机的模式,即整个系统中只能有一个主机(Master)和多个从机(Slave).
modbus_ms.png
Modbus使用请求-应答的模式,且Modbus标准规定,Modbus请求只能由主机发起,主机发送请求数据给从机,从机只有在接收到主机的请求数据后,才能发送应答数据到总线上;整个过程中从机只能被动应答,不能主动发送数据到总线上。通过主从通信模式,Modbus避免了多个设备数据的冲突;
modbus_yd.png
为了避免数据冲突,不允许主机并行发送多个消息到总线上,主机发送请求数据后,必须等到从机应答数据或者超时后,才能发送下一个请求;主机发送信息给从机后,主机会启动一个等待超时计时器,如果主机没有收到从机的应答信息,只有在等待超时计时器超时后,才可以发送下一个请求信息。

每个从机都一个唯一的从机地址,主机发起请求时,请求数据中携带了目标从机地址;主机把请求数据发送到总线上,总线上所有从机都会收到该请求,从机会检查该请求中携带的从机地址是否是自己,如果是自己就回复应答数据,如果不是自己就忽略请求。

Modbus的业务模型

Modbus的业务模型也比较简单,源码先生把Modbus业务模型简称为“读写数据”模型,即通过“读”某个(内存)地址的数据,获取设备采集的数据(或者设备的状态);通过“写”某个(内存)地址的数据,实现对设备的控制(如配置设备的参数)。

Modbus标准中,把Modbus地址空间划分为4个区域。
modbus_addr_en.png
这4个区域,在很多文档中称为4种寄存器。
modbus_addr_zh.jpg
之所以叫寄存器,是沿用了历史叫法,Modbus最开始是用来操作PLC的寄存器,如今可以把寄存器泛化为内存,4种寄存器等效为4个内存分区即可。
至于寄存器的名称,如寄存器0的名称为线圈(coils)状态,也是采用了历史叫法(线圈是继电器上的线圈,继电器是电子开关,给线圈通电,继电器开,给线圈断电,继电器关,所以线圈只有开/关这两种状态),不明白什么是线圈的话,完全可以忽略线圈这个名字,只要记住寄存器0对应数据只有0/1这两种值即可,这也是上图中single bit的含义(正好对应了线圈开/关这两种状态,其实是通过线圈这个名称告诉使用者,这个寄存器分区的数据只有0/1),这意味着“读”寄存器0的任何地址的数据,读到的数据不是0就是1,读寄存器0的0x0000地址的数据,读到的是0(或者1),读取寄存器0的0x0001地址的数据,读到的也是0(或者1)。

请忽略寄存器的名称,4种寄存器本质都是“内存”,每中寄存器都包含了一段内存地址空间(每种寄存器的地址取值范围为0x0000-0xFFFF),用户需要做的就是“读写内存”。

4种寄存器按照功能的不同分类,比如寄存器0可读可写,而寄存器1只读;寄存器0的数据是single bit(不是0就是1),而寄存器3的数据是16-bit world(两个字节),这意味着读取寄存器3的0x0000地址的数据,读出的是2个字节的数据,读取寄存器3的0x0001地址的数据,读出的也是2个字节的数据。

注意,4种寄存器分别是寄存器0、寄存器1、寄存器3、寄存器4,没有寄存器2,至于为什么没有寄存器2,估计也是历史原因造成的吧?!

Modbus报文格式/消息帧格式

Modbus有3种的报文:

Modbus ASCII:使用ASCII编码,底层使用RS458串行链路通信
Modbus RTU:使用原始二进制,底层使用RS458串行链路通信
Modbus TCP:使用原始二进制,底层使用TCP通信
这三种报文的报文主体(包括从机地址+功能码+数据域)都相同,三者没有本质区别。由于Modbus ASCII使用ASCII编码,相比Modbus RTU使用的原始二进制,前者占用空间更大,传输效率低,所以Modbus ASCII并不常用,这里主要介绍Modbus RTU和Modbus TCP。

  1. Modbus RTU
    Modbus RTU的报文格式如下图。

modbus_rtu.png
从机地址(Slave Address)
设备的从机地址用来标识设备的唯一性,用户可以自定义配置设备的从机地址,只要保证总线上每个设备的从机地址唯一,不冲突即可,从机地址范围:1-247,0为广播地址,248-255为预留地址。

功能码(Function Code)
功能码对应了设备提供的某个服务/功能,Modbus标准中把功能码分为3类:

公共功能码(Public Function Codes):Modbus标准定义好的,功能已经明确的功能码,此类功能码可以查询Modbus标准文档( http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf )
用户自定义功能码(User-Defined Function Codes):设备根据需求自定义的功能码,取值范围65-72和100-110;
保留功能码(Reserved Function Codes):目前没有使用,可忽略
虽然Modbus标准中定义了很多个公共功能码,但实际场景中,常用的只有读/写4种寄存器相关的功能码,读写又分为Single读写(一次只读写一个地址的数据)和Multiple读写(一次读写多个地址的数据):

0x01 Multiple Coils 批量读寄存器0
0x02 Multiple Discrete Inputs 批量读寄存器1
0x03 Multiple Holding Registers 批量读寄存器4
0x04 Multiple Input Registers 批量读寄存器3
0x05 Single Coil 写单个寄存器0
0x06 Single Holding Register 写单个寄存器4
0x07 Read Exception Status 读异常状态
0x0F Multiple Coils 批量写寄存器0
0x10 Multiple Holding Registers 批量写寄存器4
开发Modbus设备时,根据设备需求可自行选取对应的功能码:

当设备数据是开关量0/1,读设备数据的可选功能码有0x01和0x02;
当设备数据是开关量0/1,同时只允许读不允许写的话,读设备数据的功能码只能选择0x02,因为功能码0x01对应的寄存器0允许写;
当数据长度大于2字节长度时(比如4字节),可以选取批量读写的功能码(批量读功能码0x03和0x04,批量写功能码0x10),注意此时会遇到大端/小端的问题(另外,4个字节的数据对应是整型还是浮点数,这取决于应用程序如何解析4个字节的数据,和Modbus标准没有关)
当购买了Modbus设备时,一般需要从设备配套的说明文档中查询设备使用哪些功能码、以及读写数据的含义。

数据域(Data)
数据域用来存放真正要通信的数据,也就是常说的Payload。数据域以字节为单位,长度可变,数据域的格式也是可变的,具体格式由功能码决定,对于有些功能码,数据域可以为空,不同的功能码,数据域格式不同,可以通过Modbus标准文档的功能码查询具体的数据域格式,下图是功能码0x03对应的数据域格式。
modbus_payload.png
0x03是批量读,所以请求报文的数据域包括了要读取“寄存器”的起始数据地址、要读取的寄存器个数。

数据地址

Modbus业务模型为“读写数据”模型,而读写时必须要有数据地址,理论上每种寄存器的数据地址的取值范围都为0x0000-0xFFFF,注意不同种类的寄存器的数据地址是独立,寄存器可以有0x0000,寄存器2也可以有0x0000,数据地址虽然相同,但是读写数据不会相互影响。
实际情况中,由于历史原因,寄存器的数据地址有多种标法。
modbus_reg_addr.png
虽然标法各有异同,不过也比较好区别,记住如下特征即可:

地址范围(最大)都是0x0000-0xFFFF,但是分为16进制表示法或者10进制表示法
地址最前面,有的有寄存器序号的前缀,有的没有,见上图中红色框,寄存器序号对应4种寄存器
16进制表示法的地址从0开始,而十进制表示法的地址从1开始
CRC校验
对数据的正确性和完整性进行校验,计算方式是固定的,按固定的算法计算出CRC值即可。

  1. Modbus TCP

虽然RS485串行链路比以太网链路简单,但是鉴于以太网太流行了,Modbus引入TCP/IP的作为通信方式。Modbus是应用层协议,不管底层使用RS485链路还是TCP,应用层变化不大。
modbus_tcp.jpg
对比Modbus RTU报文,Modbus TCP报文有以下异同:

功能码和数据域和Modbus RTU相同
去掉了从机地址(即上图中的附加地址),因为TCP是面向连接的,TCP必须先根据IP地址建立一对一的连接,连接建立后,已经不在需要从机地址了;
去掉了差错校验,因为TCP是可靠传输,TCP传输层已经做过了数据校验了,Modbus应用层可以不再校验;
增加了事务处理标志,这个可以作为自增ID来标识不同的报文,由于Modbus标准中不允许多个消息并行发送,所以事务处理标志填为0也没问题;
增加了协议标识符,Modbus协议值固定为0x00;
增加了数据长度,即Modbus TCP报文的长度,因为TCP是流式数据,需要使用数据长度来识别两个报文的边界;
增加了单元标识符,这里可以填0或者填写从机地址(可用于网关转发请求给从机);
前面提到Modbus主从通信模式主要是为了避免多个设备的数据冲突,而TCP底层已经使用CSMA/CD解决了数据冲突问题,而且TCP是全双工通信(RS485链路是半双工),这意味着Modbus TCP的从机主动发送报文也不会产生冲突的,但是如果从机主动发送报文,就不符合Modbus标准了。TCP是面向连接的,基于Modbus TCP实现多主/多从的通信也是可行的,不会产生冲突,但是就不符合Modbus标准了。

TCP中有客户端(Client)和服务器(Server),对应到Modbus中,Modbus主机(Master)对应了TCP客户端(Client),Modbus从机(Slave)对应了TCP服务器(Server),使用Modbus TCP时,先使用标准的socket建立客户端到服务器的TCP连接,建立后发送Modbus TCP报文即可。

使用Modbus上云

由于Modbus主从通信模式,从机只能被动应答,不能主动上报数据,所以Modbus其实不太适合上云,但是现存大量Modbus设备,如果支持Modbus上云的话,可以快速把现有设备接入到云端,还是非常有必要的。
modbus_gateway.png
上图是Modbus标准文档中提供的Modbus通信框图,图中引入了网关的概念,要上云的话,需要使用到网关。网关需要带有Wifi/4G/网口,网关通过TCP/IP和云端通信,具体上云有以下两种方式。

方式一:云端作为Modbus主机
modbus_gateway1.png
云端软件平台作为Modbus主机,云端定时发送请求报文给网关,网关再把请求报文转发Modbus总线上,Modbus总线上的从机收到请求后,返回应答数据到Modbus总线,网关读取应答报文并转发给云端;
云端和网关之间使用Modbus TCP报文通信,网关和设备之间可以使用Modbus RTU,也可以使用Modbus TCP报文通信;
网关作为转发的角色,在云端和从机设备之间转发数据,网关同时也作为转换协议的角色,比如把Modbus TCP转换为Modbus RTU;
云端需要不停的发送请求报文,相当于不停的轮询,当从机设备数量比较多时,云端的轮询压力大,通信带宽要求也比较高。

方式二:网关作为Modbus主机
modbus_gateway2.png
网关作为Modbus主机,网关主动定时发送请求报文到Modbus总线上,然后接收从机的应答报文;网关接收到从机应答报文后,可以使用其他协议(比如mqtt)把应答信息转发给云端。
网关除了作为Modbus主机,还需要作为连接云端的客户端(比如Mqtt客户端)把轮询到的数据主动上报给云端;
需要把网关如何轮询从机的信息从云端配置给网关,配置稍微麻烦,但是轮询压力分散在网关上,比较符合边缘计算的思路。

Modbus优缺点

Modbus优点:协议简单,接口芯片成本低;

Modbus缺点:实时性差(从机不能主动上报数据,必须依赖主机轮询),总线利用率低,传输速率低,另外RS485抗干扰较弱,节点错误是会影响整个总线。如果Modbus不能满足自己的需求,可以使用CAN总线。