springcloud之项目实战服务治理

news2024/11/19 3:22:47

写在前面

在这篇文章 我们已经搭建完成了优惠券模块的单体版本,为了向微服务化迈出坚实的一步,这部分来看下服务治理的内容,并在我们的项目中引入服务治理,下面我们就开始吧!

源码 。

1:什么是,为什么需要服务治理?

假定现在有服务A和服务B,并且服务A和服务B都有3个节点,因此现在有一个3节点的服务A集群和一个3节点的服务B集群,通常的做法是在外层挂一层VIP,假定服务A要调用服务B,则过程如下图:

在这里插入图片描述

我们只需要将服务B的服务列表维护在VIP层就行了,但注意这个过程是手动的,因此这种方式就可能存在如下的问题:

1:需要手动维护服务器列表VIP pool中,如果是集群很大的话,这将会是一个很大的工作量
2:新的机器上线和下线,需要手动更新VIP pool,且在此期间不可用机器还能继续处理请求(时间比较长,从人工发现,到人工替换完成)

可以看到上述的问题的根源都是手动维护,如果我们能将手动维护改为自动维护,不管是集群中的新机器(服务注册),还是机器故障(服务剔除),都能够自动发现,这些工作在微服务环境下我们叫做服务治理。为了实现这些需求,我们需要引入一个新的三方组件(注册中心),由它来负责维护这些信息,服务的提供方从将自己的信息注册在这里(服务注册),服务的消费方从这里获取可用的服务列表(服务发现),可以参考下图:

然后注册中心通过心跳机制来检测服务提供方的存活情况(“服务探活”或“心跳检查”),发现服务不可用则可以执行服务剔除,然后将这个变化告知服务消费者,这样请求就不会访问到不可用服务了(以为服务探活是有时间间隔的,所以还是会有访问到不可用服务的情况,但是时间相比于手动方式会短很多),参考下图:
在这里插入图片描述

nacos就是一个具体的注册中心中间件,接下来一起看下。

2:nacos分析

2.1:领域模型

在这里插入图片描述

如上图所以就展示了领域模型中三个组成,服务,集群,实例,如下:

  • 服务
    在服务这个层级上我们可以配置元数据和服务保护阈值等信息。服务阈值是一个 0~1 之间的数字,当服务的健康实例数与总实例的比例小于这个阈值的时候,说明能提供服务的机器已经没多少了。这时候 Nacos 会开启服务保护模式,不再主动剔除服务实例,同时还会将不健康的实例也返回给消费者。尽管这样做可能造成请求失败,但间接保证了最低限度的服务可用性。
  • 集群
    一个服务由很多服务实例组成,在每个服务实例启动的时候,我们可以设置它所属的集群,在集群这个层级上,我们也可以配置元数据。除此之外,我们还可以为持久化节点设置健康检查模式。所谓持久化节点,是一种会保存到 Nacos 服务端的实例,即便该实例的客户端进程没有在运行,实例也不会被服务端删除,只不过 Nacos 会将这个持久化节点状态标记为不健康,Nacos 可以采用一种“主动探活”的方式来对持久化节点做健康检查。除了持久化节点以外,大部分服务节点在 Nacos 中以“临时节点”的方式存在,它是默认的服务注册方式,从名字中我们就可以看出,这种节点不会被持久化保存在 Nacos 服务器,临时节点通过主动发送 heartbeat 请求向服务器报送自己的状态。
  • 实例
    对应的就是我们的应用实例。即一个进程。在nacos的控制界面我们查看每个实例的IP,端口等信息,并且可以设置其上线,下线状态,权重等。

可以发现服务,集群,实例都是可以设置元数据的,这样我们就可以在不同的纬度来设置信息,client端根据这些元数据信息就可以执行不同的操作(通过IP,端口调用到服务,通过权重来动态设置负载均衡策略)

2.2:数据模型

数据模型分为三个层次,namespace,group,servieId/dataId,是包含的关系,可以参考下图:
在这里插入图片描述

namepsace:一般用来区分环境,如本地环境,测试环境,生产环境等,默认部署到叫public的公共命名空间中
group:namepspace下的概念,默认是default-group分组,不同分组的微服务是相互隔离的
serviceId/dataId:就是具体的微服务了,如订单服务,用户服务,支付服务等

更具体的可以参考下图:
在这里插入图片描述

可以有很多的namespace,每个namespace下有若干个group,每个group有若干个serviceId/dataId。通过三者的组合我们就能定位到一个具体的微服务了,比如production(namepsace)+mainGroup(group)+orderService(serivceId)就可以定位到生产环境下的main组下的订单微服务了。

2.3:架构

架构图如下:
在这里插入图片描述
各组件说明如下:

provider app:服务提供者
consumer app:服务消费者
openapi:nacos提供rest接口,用户增删改查服务信息
config service:提供配置中心的功能
naming service:提供注册中心的功能(本部分析的)
nacos core:提供nacos的核心功能,如启动模式,数据存储等
consistency protocol:处理naco集群模式下的数据一致性问题

关于openapi详细可以参考这里 。另外nacos-core提供的功能如下图:
在这里插入图片描述

3:nacos环境搭建

人的一生由很多部分组成,健康的身体,美满幸福的家庭,无话不谈的好友,花之不尽的财富(做梦),但,除了健康的身体是一串数字的1之外,其他的都是0,即有了最好,没有也无所谓。同理,一个系统架构也由很多分布构成,而这里的1是高可用性,要实现高可用性基本解决如下的两个问题就行了:

1:单点故障
    我们做系统架构时要假定,我们必须悲观的认为所有的服务都是会挂掉的,避免单点故障
2:故障恢复
    故障的机器在重启后,要能够恢复到故障前的状态

想要解决以上的这2个问题,就需要依赖于服务器集群了,而nacos也不例外,所以,我们这部分就一起来搭建一个nacos的集群环境,并应用在后续的优惠券功能微服务化的改造中。

  • 下载
    点鸡 。
  • 解压
    首先解压到一个目录,再重新复制一份,在一台机器起两个服务模拟集群,如下:
    在这里插入图片描述
  • 修改配置conf/application.properties
    主要修改端口号和MySQL地址,如下:
server.port=8858
spring.datasource.platform=mysql
db.url.0=jdbc:mysql://192.168.64.129:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=123456
  • 创建集群配置conf/cluster.conf
    没有就创建,如下:
192.168.10.62:8858
192.168.10.62:8868
  • 创建schema和db
create schema nacos;

conf/nacos-mysql.sql
  • 启动
    注意俩都启动。
JHP+Administrator@jhp MINGW64 /d/test/nacos-cluster/nacos-cluster-2/nacos/bin
$ ./startup.cmd
"nacos is starting with cluster"

         ,--.
       ,--.'|
   ,--,:  : |                                           Nacos 2.0.0
,`--.'`|  ' :                       ,---.               Running in cluster mode, All function modules
|   :  :  | |                      '   ,'\   .--.--.    Port: 8868
:   |   \ | :  ,--.--.     ,---.  /   /   | /  /    '   Pid: 18952
|   : '  '; | /       \   /     \.   ; ,. :|  :  /`./   Console: http://192.168.64.1:8868/nacos/index.html
'   ' ;.    ;.--.  .-. | /    / ''   | |: :|  :  ;_
|   | | \   | \__\/: . ..    ' / '   | .; : \  \    `.      https://nacos.io
'   : |  ; .' ," .--.; |'   ; :__|   :    |  `----.   \
|   | '`--'  /  /  ,.  |'   | '.'|\   \  /  /  /`--'  /
'   : |     ;  :   .'   \   :    : `----'  '--'.     /
;   |.'     |  ,     .-./\   \  /            `--'---'
'---'        `--`---'     `----'

2023-10-11 09:00:10,954 INFO The server IP list of Nacos is [192.168.10.62:8858, 192.168.10.62:8868]
...
2023-10-11 09:00:30,852 INFO Nacos started successfully in cluster mode. use external storage

出现Nacos started successfully in cluster mode. use external storage就是成功了。

  • 访问
    访问任意一个节点就行,账号nacos/nacos:
    在这里插入图片描述

在这里插入图片描述

4:服务注册到nacos

首先我们改造模板模块和计算模块,让其服务注册到nacos,首先需要在每个模块对应的impl实现子模块中引入nacos注册的依赖如下:

<!-- Nacos服务发现 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

之后需要引入nacos相关的配置项:

spring:
  application:
    ...
  cloud:
    nacos:
      discovery:
        # 可以配置多个,逗号分隔
        server-addr: 192.168.64.1:8858
        # 默认就是application name,一般不用配置
        service: coupon-calculation-serv
        # nacos客户端向服务端发送心跳的时间间隔,时间单位其实是ms
        heart-beat-interval: 5000
        # 服务端没有接受到客户端心跳请求就将其设为不健康的时间间隔,默认为15s
        # 注:推荐值该值为15s即可,如果有的业务线希望服务下线或者出故障时希望尽快被发现,可以适当减少该值
        heart-beat-timeout: 20000
        # [注意] 这个IP地址如果更换网络后变化,会导致服务调用失败,建议先不要设置
        # ip: 172.20.7.228
        # 元数据部分 - 可以自己随便定制
        metadata:
          mydata: abc
        # 客户端在启动时是否读取本地配置项(一个文件)来获取服务列表
        # 注:推荐该值为false,若改成true。则客户端会在本地的一个文件中保存服务信息,当下次宕机启动时,会优先读取本地的配置对外提供服务。
        naming-load-cache-at-start: false
        # 创建不同的集群
        cluster-name: Cluster-A
        # 命名空间ID,Nacos通过不同的命名空间来区分不同的环境,进行数据隔离,
        # 服务消费时只能消费到对应命名空间下的服务。
        # [注意]需要在nacos-server中创建好namespace,然后把id copy进来
        namespace: dev
        # [注意]两个服务如果存在上下游调用关系,必须配置相同的group才能发起访问
        group: myGroup
        # 向注册中心注册服务,默认为true
        # 如果只消费服务,不作为服务提供方,倒是可以设置成false,减少开销
        register-enabled: true
        # 类似长连接监听服务端信息变化的功能
        watch:
          enabled: true
        watch-delay: 30000

配置项含义如下:
在这里插入图片描述

在正式注册服务之前我们需要先在nacos添加这里的命名空间dev,如下:
在这里插入图片描述
配置完毕后,分别启动服务,就能完成在nacos注册中心的注册了,成功后在nacos控制台查看:
在这里插入图片描述

5:改造用户模块基于服务发现调用

接着我们改造用户模块基于服务发现调用,这里我们以requestCoupon接口,即发放优惠券为例来看下,首先我们将coupon-customer-impl中对于模板模块和计算模块的impl实现的依赖,而改为对公用的api的相关bean模块的依赖,如下:

<!--
    删除计算模块具体实现依赖
    <dependency>
        <groupId>${project.groupId}</groupId>
        <artifactId>coupon-calculation-impl</artifactId>
        <version>${project.version}</version>
    </dependency>
-->
<!-- 使用计算模块公用api -->
<dependency>
    <groupId>${project.groupId}</groupId>
    <artifactId>coupon-calculation-api</artifactId>
    <version>${project.version}</version>
</dependency>
<!--
    删除模板模块具体实现依赖
    <dependency>
        <groupId>${project.groupId}</groupId>
        <artifactId>coupon-template-impl</artifactId>
        <version>${project.version}</version>
    </dependency>
-->
<!-- 引入模板模块公用api -->
<dependency>
    <groupId>${project.groupId}</groupId>
    <artifactId>coupon-template-impl</artifactId>
    <version>${project.version}</version>
</dependency>

接着配置用来执行服务调用的WebClient,以Java config方式来配置,如下:

// Configuration注解用于定义配置类
// 类中定义的Bean方法会被AnnotationConfigApplicationContext和AnnotationConfigWebApplicationContext扫描并初始化
@org.springframework.context.annotation.Configuration
public class Configuration {

    @Bean
    @LoadBalanced
    public WebClient.Builder register() {
        return WebClient.builder();
    }

}

接着来改造领取优惠券的方法requestCoupon,如下:

@Slf4j
@Service
public class CouponCustomerServiceImpl implements CouponCustomerService {
    ...
    /**
      * 用户领取优惠券
      */
    @Override
    public Coupon requestCoupon(RequestCoupon request) {
        /*
        Mono<ResponseEntity<CouponTemplateInfo>> entityMono = client.get()
          .uri("http://coupon-template-serv/template/xxxx")
          .accept(MediaType.APPLICATION_JSON)
          .retrieve()
          .toEntity(CouponTemplateInfo.class);
          */
        CouponTemplateInfo templateInfo = webClientBuilder.build()
                // 声明了这是一个GET方法
                .get()
                .uri("http://coupon-template-serv/template/getTemplate?id=" + request.getCouponTemplateId())
                .header(TRAFFIC_VERSION, request.getTrafficVersion())
                .retrieve()
                .bodyToMono(CouponTemplateInfo.class)
                .block();

        // 模板不存在则报错
        if (templateInfo == null) {
            log.error("invalid template id={}", request.getCouponTemplateId());
            throw new IllegalArgumentException("Invalid template id");
        }

        // 模板不能过期
        long now = Calendar.getInstance().getTimeInMillis();
        Long expTime = templateInfo.getRule().getDeadline();
        if (expTime != null && now >= expTime || BooleanUtils.isFalse(templateInfo.getAvailable())) {
            log.error("template is not available id={}", request.getCouponTemplateId());
            throw new IllegalArgumentException("template is unavailable");
        }

        // 用户领券数量超过上限(通过优惠券对应的规则)
        Long count = couponDao.countByUserIdAndTemplateId(request.getUserId(), request.getCouponTemplateId());
        if (count >= templateInfo.getRule().getLimitation()) {
            log.error("exceeds maximum number");
            throw new IllegalArgumentException("exceeds maximum number");
        }

        Coupon coupon = Coupon.builder()
                .templateId(request.getCouponTemplateId())
                .userId(request.getUserId())
                .shopId(templateInfo.getShopId())
                .status(CouponStatus.AVAILABLE)
                .templateInfo(templateInfo)
                .build();
        couponDao.save(coupon);
        return coupon;
    }
    ...
}

接着启动服务,就可以来调用测试了:
json参数

{
    "userId": 1,
    "couponTemplateId": 2
}

在这里插入图片描述
在这里插入图片描述

写在后面

参考文章列表

Open API 指南 。

如何给集群设置VIP(虚拟IP) 。

k8s实现nacos动态伸缩1 。

k8s实现nacos动态伸缩2 。

springcloud和springboot版本对应关系 。

springcloud,springcloud-alibaba,springboot版本对应关系 。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1105816.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Java公益志愿捐赠管理系统设计与实现(源码+LW+调试+开题报告)

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…

卡尔曼滤波器融合六轴IMU数据

卡尔曼滤波 卡尔曼滤波是一种常用的状态估计方法&#xff0c;其基本原理是对系统状态进行最优估计。其主要思想是将系统的状态分为先验状态和后验状态&#xff0c;通过将先验状态和观测值进行加权平均&#xff0c;得到最优估计状态。 卡尔曼滤波增益的计算是使后验误差协方差…

程序员工作5年,还是个中级程序员,如何再快速晋升?

我曾经就是这个状态&#xff0c;5年工作经验就像是一年工作经验用了5年。职业生涯遇到了瓶颈&#xff0c;无法突破。分析原因有很多&#xff0c;一方面是基本功没练好&#xff0c;像操作系统底层、数据结构、算法、计算机网络这些计算机基础知识掌握的不扎实&#xff0c;不能灵…

vue项目的创建——总结版

目录 前提&#xff1a; 一、vue项目的创建 二、浏览项目页面 三、vue项目目录文件含义和作用 ​四、修改端口号 前提&#xff1a; 首先要有Node.js环境。 1.安装vue npm install vue 2.命令行工具&#xff08;CLI&#xff09;为单页面应用快速搭建繁杂的脚手架 npm in…

vulnhub之MATRIX-BREAKOUT 2 MORPHEUS

信息收集 输入命令&#xff1a;arp-scan 192.168.239.0/24&#xff0c;探测存活主机&#xff0c;发现192.168.239.185 对存活主机进行端口扫描&#xff0c;发现&#xff1a;22、80、81端口 浏览器访问http://192.168.239.185:81是一个登录界面 浏览器访问http://192.168.239.…

大模型携手AI原生应用融入产业场景

前言 10月17日&#xff0c;百度世界2023在北京首钢园召开。百度集团执行副总裁、百度智能云事业群总裁沈抖宣布&#xff0c;对“云智一体”的战略内涵全面升级&#xff0c;即云智一体&#xff0c;深入产业&#xff0c;生态繁荣&#xff0c;AI普惠。重磅发布“千帆AI原生应用开…

ASO优化之增加APP应用下载安装量的技巧1

想要增加APP应用的下载安装量&#xff0c;首先要在发布之前&#xff0c;分析我们的应用推广策略该如何运作并进行调整。提高知名度的基础是关键词&#xff0c;其次使用社交网络来推广我们的应用程序。 1、基础与规划。 在启动应用程序或者是实行ASO计划之前&#xff0c;需要了…

6-3 用链栈实现将非负的十进制数转换为指定的进制数【有题解视频,可本地编译器调试】 分数 15

int DecimalConvert(LinkStack s, int dec, int scale) {while (dec){if (LinkStackPush(s, dec % scale))dec dec / scale;elsereturn 0;}return 1; }

微信小程序获取手机号和openid

小程序通过wx.login组件会返回一个code&#xff0c;这个code用来获得用户的openid。 小程序写法为&#xff1a; wx.login({success (res) {if (res.code) {//发起网络请求wx.request({url: https://example.com/onLogin,// 后台给的请求地址data: {code: res.code}})} else {…

流程图如何制作?好用的11款流程图软件盘点!

流程图是一种强大的可视化工具&#xff0c;用于清晰地展示各种过程和步骤&#xff0c;应用非常广泛&#xff0c;在各个行业中随处可见&#xff0c;凡是涉及流程步骤的场景&#xff0c;都可以用到流程图&#xff0c;那么问题来了&#xff1a;流程图如何制作&#xff1f; 这篇文…

性能优化-卡顿优化-tarce抓取及分析

性能优化&#xff08;卡顿分析&#xff09; 文章目录 一、抓取trace的方法1.使用systrace抓取trace2.使用atrace抓取3.使用Perfetto抓取trace 二、trace文件的分析1.快捷操作1.1 导航操作1.2 快捷操作 2.chrome trace工具分析trace文件3.Prefetto分析trace文件 一、抓取trace的…

C++初阶-类和对象(上)

类和对象&#xff08;上&#xff09; 一、面向过程和面向对象初步认识二、类的引入三、类的定义四、类的访问限定符及封装访问限定符封装 五、类的作用域六、类的实例化七、类的对象大小的计算如何计算类对象的大小类对象的存储方式猜测 八、类成员函数的this指针this指针的引出…

精神科常用评估量表汇总,建议收藏!

根据精神科医生的量表使用情况&#xff0c;笔者整理了10个精神科常用量表&#xff0c;可在线评测直接出结果&#xff0c;可转发使用&#xff0c;可生成二维码使用&#xff0c;可创建项目进行数据管理&#xff0c;有需要的小伙伴赶紧收藏&#xff01; 抑郁自评量表 抑郁自评量表…

22.项目开发之量化交易抓取数据QuantTradeData(一)

项目创建及后端业务&#xff1a;定时更新“股票列表基础信息”数据 项目创建 该量化交易数据平台用于数据库的数据抓取、分析等操作。 和QuantTrade使用同一个数据库&#xff0c;无需重新创建 pom.xml <properties><java.version>1.8</java.version><pro…

GPU 驱动下载记录

1. 我的GPU 是这个&#xff1a;GeForce RTX 2060 下载链接是&#xff1a;Official Drivers | NVIDIA

人脸识别技术是什么?如何进行人脸识别数据标注?

人脸识别解锁、人脸识别防盗系统、人脸识别登陆账户&#xff0c;相比于传统的指纹识别或者是虹膜识别等生物识别技术&#xff0c;人脸识别的应用更加广泛和多样。人脸识别技术是什么&#xff1f;人脸识别和数据标注有什么关系&#xff1f;阅读本文你会了解&#xff1a; 人脸识…

异形led显示屏调试步骤

调试异形LED显示屏需要一定的专业知识和技能。以下是一般的异形LED显示屏调试步骤&#xff1a; 安装和连接&#xff1a; 安装LED模块和框架&#xff0c;确保它们正确固定和对齐。连接电源和信号线。确保电源供电正常&#xff0c;信号线连接正确。什么是LED显示模块&#xff1f;…

android源码查阅连接

原文链接如下&#xff1a; AOSPXRef 在此做个笔记

Paypal提现到万里汇再提现到支付宝的全过程

因为外汇管制的缘故&#xff0c;paypal的钱无法直接提现到国内银行卡。即使提现也会接到电话通知表示非常抱歉无法入账。之前还被银行主管问到是否能提供合同&#xff0c;交易信息&#xff0c;是否完税等等。因为他们对网商都不是太懂&#xff0c;知道paypal已经算不错了。但是…

【数据结构】队列-Queue

⭐ 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主页&#xff1a;小胡_不糊涂的个人主页 &#x1f4c0; 收录专栏&#xff1a;浅谈数据结构 &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; 队列 1.什么是队列2. 队列的使用3. …