软件工程应用与实践——微服务治理

Posted 叶卡捷琳堡

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了软件工程应用与实践——微服务治理相关的知识,希望对你有一定的参考价值。

2021SC@SDUSC

一、概述

在老年健康管理系统的后端代码中,使用了当前火热的微服务技术。微服务架构改变了传统单体架构的模式,使不同功能,不同模块之间的代码更加解耦合。微服务将服务进行原子化拆分,不同为服务之间独立打包,部署和升级,运维成本也大大降低。在本次项目中,微服务之间的通信使用使用了Http请求(Restful方式),使不同微服务之间能互相传递信息。当系统中一个服务需要调用另一个服务提供的接口时,可以向另一个服务发送Http请求,获取另一个服务提供的服务。

经过小组讨论,决定由我负责微服务部分代码的阅读和理解,本篇博客主要围绕老年健康管理系统后端微服务环境的整体架构,注册中心,配置中心和服务间通信等进行代码分析。

二、核心代码

在本项目后台的微服务构建中,有几个比较重要的基础部分。第一个部分是微服务搭建的部分,第二部分是每个服务的注册和服务间通信,第三个部分是微服务之间互相通信的负载均衡问题。接下来我将从这三个方面介绍本项目的内容。

2.1 微服务搭建

在老年健康管理系统中,后端使用目前行业中通用的Spring Cloud框架完成微服务的治理任务。处理使用Spring Cloud框架以外,还是用了Spring Cloud Alibaba的Nacos组件作为注册和配置中心

由于后端使用了Spring Cloud作为微服务治理的框架,因此本项目的pom.xml的形式与一般单体应用的pom.xml略有区别

在父项目中继承了Spring Boot项目

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.5.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

使用dependencyManagement标签维护父项目的总依赖

这部分依赖是用于整个父项目,父项目中的具体子项目(所有微服务),都会继承该父项目的全部依赖。这样的方便之处在于,微服务不需要再关注具体的版本号,只需要引入微服务对应的父项目的依赖即可(类似上面父项目引入Spring Boot依赖那样)

<dependencyManagement>
    <dependencies>
        <!--引入springcloud依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>$spring.cloud-version</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!--引入lombok依赖-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>$lombok-version</version>
            <optional>true</optional>
        </dependency>
        <!--热部署依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <version>$devTool-version</version>
            <optional>true</optional>
        </dependency>
        <!--引入junit依赖-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

版本号的维护

随着服务的不断增加,需要的依赖也越来越多,本项目中利用properties标签对版本号进行公共维护,便于修改,在这里可以看到,Spring Cloud的版本是Hoxton.SR8,早期Spring Cloud的版本号是以伦敦地铁站的站名命名的。

<properties>
    <spring.cloud-version>Hoxton.SR8</spring.cloud-version>
    <lombok-version>1.18.20</lombok-version>
    <devTool-version>2.5.3</devTool-version>
</properties>

2.2 注册和配置中心

2.2.1 服务注册中心

在微服务系统中,由于微服务众多,且不同微服务往往以集群形式部署,因此需要一个统一注册管理中心用于管理所有的微服务,查看微服务的健康状况,等等。在本项目中,使用Spring Cloud Alibaba的Nacos作为服务注册中心。

为了使用Nacos组件,本项目在pom.xml中引入了Nacos依赖

首先在父项目中引入Spring Cloud Alibaba

<dependencyManagement>
    <dependencies>
        <!--springcloudalibaba-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>$spring.cloud.alibaba.version</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

对应的版本号为

<properties>
    <spring.cloud.alibaba.version>2.2.1.RELEASE</spring.cloud.alibaba.version>
</properties>

接着在子项目中引入nacos依赖

注意,子项目中的依赖并没有版本号,只有groupId和artifactId,这是因为在父项目中已经指定了相应依赖的版本,因此子项目中不需要重复指定。

<dependencies>
    <!--引入Nacos依赖-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <!--引入nacos config client依赖-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>
</dependencies>

主程序

通过阅读源码可知,注册到nacos注册中心的客户端类的启动类就是一个简单的Spring Boot启动类,与其他的项目类似

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class UserApplication

    public static void main(String[] args) 
        SpringApplication.run(NacosClientApplication.class, args);
    

通过查阅资料,我了解到,Nacos可以认为是一个小的软件(该软件的作用是用于服务注册),默认占用服务器的8848端口,使用Nacos的好处在于,不需要再在微服务中单独定义一个工程,这个工程仅用于充当服务注册中心(类似Eruka)。使用Spring Boot集成Nacos后,仅需要引入依赖,并在bootstrap.properties中配置Nacos的基本信息,即可在启动时自动注册到Nacos。

配置信息如下

spring.cloud.nacos.config.server-addr=localhost:8848

Nacos服务注册中心默认以集群的方式启动。

2.2.2 配置中心

在微服务的治理过程中,由于每个微服务都有自己的配置文件,而微服务通常以集群的方式部署,如果所有的配置文件都放在本地,那么修改起来将会非常麻烦,需要对微服务集群中的每一个节点都进行修改,这显然是不合理的。因此在阅读源码的过程中,我发现该系统将所有的配置文件,都放到nacos的配置中心中,将配置中心放到一个集中的云配置中心中,便于更改。此外,nacos在管理配置文件的过程中,还会对配置文件进行版本控制。

bootstrap.properties配置

在使用统一注册中心后,本项目将原本的application.properties变为bootstrap.properties,这样才能拉取到远端的具体配置。

#nacos配置中心ip和端口
spring.cloud.nacos.config.server-addr=localhost:8848
#组名
spring.cloud.nacos.config.group-name=NURSE_GROUP
#配置文件名
spring.cloud.nacos.config.name=nurse-prod
#配置文件后缀
spring.cloud.nacos.config.file-extension=properties

尽管使用了统一的配置中心,但在本地的bootstrap.properties依然要书写少量的配置信息,这部分配置信息的主要作用是告诉该服务配置文件具体的位置。

2.3 服务间通信

在老年健康管理系统中,不同微服务之间的通信有多种方式。本篇博客不对MQ(异步消息队列)通信方式做过多介绍,仅对普通的Http通信进行介绍。(后续会对MQ消息通信部分得源码进行阅读并介绍)

使用RestTemplate进行通信

在本项目中,有少部分代码使用RestTemplate进行通信,RestTemplate是一个类,可以发送Http请求,另外,在使用RestTemplate的同时,还是用了Ribbon组件使服务间的通信负载均衡。在阅读源码的过程中,我发现他对RestTemplate进行了封装配置,已保证负载均衡的效果。

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class BeansConfig

    @Bean
    //使用@LoadBalanced注解,让对象具有ribbon负载均衡特性
    @LoadBalanced
    public RestTemplate restTemplate()
        return new RestTemplate();
    

通过阅读源码可知,本项目使用自动注入的方式注入前面配置好的RestTemplate对象

@Autowired
private RestTemplate restTemplate;

使用OpenFeign进行服务间通信

在本项目中,处理上面的通信方式以外,还使用了Spring Cloud的Open Feign组件进行不同服务间的通信,使用Open Feign进行通信比前面的RestTemplate通信的优点在于,不会将路径写死,且在使用OpenFeign进行通信的过程中会自动实现请求的负载均衡,不需要再使用@loadBalance注解。

通过阅读源码可知,在使用Open Feign时,首先引入了OpenFeign的相关依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

这里以一个简单的例子展示项目中OpenFeign配置类的具体配置

import org.springframework.cloud.openfeign.FeignClient;

//调用用户服务的接口
//value=""服务名称
@FeignClient("user")
public interface UserClient

    @GetMapping("user")
    //注意这里的@RequestParam("key")一定要加
    String getCurrentUser(@RequestParam("name") String name,@RequestParam("age") Integer age);

在对应的controller类中,自动注入该接口对象,而后调用对应的方法,即可直接发送请求

@Autowired
private UserClient userClient;

三、总结

在本篇博客中,我主要对项目中微服务治理的部分源代码进行了解读,通过对这部分源代码的解读,我对微服务之间的关系理解得更深刻了。此外,由于本项目在微服务治理的源代码内容较多,一篇博客难以分析完,在后面的博客中我也会对这一部分源码进行更进一步地分析。

最后感谢老师和小组成员对我提供的帮助,这让我更好地在阅读源码的过程中学习到更多地知识了。

以上是关于软件工程应用与实践——微服务治理的主要内容,如果未能解决你的问题,请参考以下文章

华为高级技术专家多年经验分享微服务治理体系架构及实践文档

软件工程应用与实践(10)——网关,服务熔断

软件工程应用与实践(10)——网关,服务熔断

转转服务治理实践

Mendix结合腾讯TSF实现微服务治理

Istio技术与实践05:如何用istio实现流量管理