微服务与分布式——SpringCloud

Posted 梦の澜

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了微服务与分布式——SpringCloud相关的知识,希望对你有一定的参考价值。

前提:

当项目逐渐变得庞大起来,简单的 spring 框架可能就不够用了,所以就需要用到分布式架构,我们这里简单介绍一下 springcloud 以及 springcloud 需要依赖的一些组件


目录:

1、分布式简介
2、Eureka 注册中心
3、Ribbon 负载均衡
4、Nacos 注册中心
5、Feign
6、gateway 网关
7、docker
8、RabbitMQ
9、SpringAMQP


1、分布式简介

问题一:什么是微服务
首先微服务≠SpringCloud,微服务是分布式架构的一种。所谓分布式架构就是把服务做拆分。而拆分的过程中会产生各种各样的问题需要去解决,springcloud只是解决了服务拆分时的服务治理问题,至于服务拆分后更为复杂的问题,并未给出解决方案,所以一个完整的微服务技术,包含的不仅仅是springcloud。我们下面看看微服务技术除了springcloud还包含哪些?

首先:原本所有的功能都写在一起,随后的版本越来越多,功能耦合的更加强,将来想升级维护就会很困难,所以一些大型的互联网技术都要进行服务的拆分。微服务在拆分的过程中会根据业务的功能模块,把大项目拆分成多个独立的项目,每个独立的项目独立进行开发和部署,每个独立的项目被称之为服务,每个大型的项目,一般包括数百上千的服务,最终形成服务集群


当一个请求来了,假如通过服务A调用服务B,服务B又调用服务C,这样当服务量比较多的时候,服务间的一些配置(比如服务的 ip )靠人会很难记住,所以引入注册中心,有了注册中心,服务之间互相调用所需要的一些配置,直接去找注册中心就ok了,去注册中心去拉取对应的服务信息,每个服务都有自己的配置文件,如果那些服务需要去更改配置文件,难道需要我们人工去逐一更改么,这样就太麻烦了,所以就会引入配置中心,通过配置中心来统一管理整个集群中成千上百的配置管理,配置中心可以支持配置的热更新。当微服务运行起来后,用户就可以访问我们的微服务了,这个时候还需要一个服务网关,整个集群这么多服务,用户哪里知道要访问哪个,而且也不是随便什么人都可以访问服务,服务网关一方面是对用户身份进行校验,另一方面可以把用户的请求路由到具体的服务上,路由过程中可以做一些负载均衡的操作,此时服务接收到请求后,处理请求,该去访问数据库访问数据库(数据库一般采用集群的方式,由于用户量普遍大于数据库容量,所以也会采取缓存数据库(基于内存的数据库),为了应对高并发,还需要把缓存数据库做成分布式缓存(也是集群),服务先去请求缓存,缓存未命中再去请求数据库)(数据库充当的角色一般是做数据的写操作,和事务的一些操作,总之是对数据安全要求较高的一些数据存储),随后再把查询到的数据返回给用户就ok了。当我们的业务可能会涉及到一些海量数据的搜索,此时基于缓存也无法实现,届时就需要引入分布式搜索。还需要一些异步通信的消息队列组件,其实对于分布式的服务,业务往往会跨越多个服务,一个请求来了,服务A调服务B,服务B调服务C整个业务的链路会很长,此时的业务执行时长就是整个链路的执行时长之和,所以其实性能会有一定下降,所以通过消息队列,不是去调用B而是去通知B你去执行啥啥啥,此时就不需要服务A再去等服务B执行完毕,就可以提前结束了,减少了整个链路的等待时间(大大提高了吞吐能力)。当服务出现异常时,引入分布式服务日志来对其进行记录(统一的进行统计,存储分析)将来出现问题也比较好解决了,同时还引入系统监控链路追踪(实时监控整个链路每个服务结点内存CPU的占用等等情况,一旦出现任何问题,就可以快速定位到某一个方法)

此时我们的微服务集群就会非常庞大,靠人去部署时不现实的,需要引入自动化部署,此时通过 Jenkins 对项目进行自动化的编译,基于 docker 再去进行打包形成镜像,再去通过 k8s 或者 rancher 进行部署,此时微服务技术 + 后续的持续集成,这就是完整的微服务技术栈!!!!!

整体微服务技术栈大体分为五部分:

微服务治理:也是我们常说的 springcloud


分布式缓存:


异步通信:MQ等技术


分布式搜索技术:


持续集成的技术:


架构演变:

最早系统的架构一般采用的是单体架构(将业务的所有功能集中在一个项目中开发,打成一个包部署)优点:架构简单,不用去搞复杂的架构理念,打成一个包部署成本低,此架构更适合用于一些面向企业内部的一些简单项目,因为单体架构一个严重缺陷:耦合度高!大型互联网项目,功能非常多,当改动一个功能模块时,可能会导致其他功能模块的崩溃,所以代码不方便动,由此可知单体架构是不适合大型的互联网项目的,
大型业务一般会采取分布式架构,每个功能作为独立的项目去进行开发,称为一个服务,拆分功能模块后,耦合度降低了,但是随之也会引发一定的问题,比如订单模块需要依赖于商品信息模块,但是这明显是俩服务,咋互相调用?除非能够一个服务向另一个服务发送请求(远程调用,跨越机器,跨越服务)


为了解决这些问题,提出了很多解决方案,近几年最火的莫过于微服务技术,微服务就是一种经过良好架构设计的分布式架构方案,微服务架构特征



三、认识springcloud,springcloud可以被认为是国内外使用最广泛得微服务框架,spring cloud对以下组件做出了整合,无需复杂配置,更方便使用

四、服务拆分:单体架构按照功能模块进行拆分,变成多个服务就ok了,生产种功能模块可能会继续变多,又需要我们去拆

练习:


练习:
现在有两个服务,一个是获取用户信息的服务,一个是获取订单信息的服务,这两个服务是分开的,各自有各自的数据库,那么如何实现根据订单id查询订单详情的同时获取到用户信息呢,这就是远程调用

首先我们可以想到的是用户服务可不可以调用订单信息的数据库,显然不行,因为要减少重复开发并且各个服务之间的数据库是隔离的,无法互相查看


所以这里需要用户服务远程调用订单服务,这样的方法我们之前是没有学过的,所以我们看一下如何实现


其实就是订单模块模拟浏览器一样 发送 http 请求,请求用户信息对应的接口获取到用户信息,最后根据订单的信息一拼接就ok了,所以问题就变成了如何在 java 代码中发起 http 请求,能发请求就能远程调用了,此时需要 spring 提供的 RestTemplate 发送 http 请求




两个概念:服务的提供者与消费者


问题:

一个服务既可以是消费者也可以是提供者


2、Eureka 注册中心

硬编码的问题


不做硬编码,如何获取提供者地址呢?

通过负载均衡来区别调用哪个具体的服务,为了防止其他服务挂了,会有对应的心跳机制



动手搭建:



创建模块


创建对应的三个文件

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>


server:
  port: 10086
spring:
  application:
    name: eurekaserver
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka/

启动类:

@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication 
    public static void main(String[] args) 
        SpringApplication.run(EurekaApplication.class, args);
    

启动后:


这个就是注册的实例:可以看到Eureka把自己也注册到了里面


服务注册:

spring:
  application:
    name: eurekaserver
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka/
<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

重启即可!


可以发现服务已经被注册进来了
同一个服务怎么引入两遍


输入--- -Dserver.port=8082 即可


启动后:


服务发现:




此后通过发送请求



两个user服务器都有日志,也就说明负载均衡把请求分摊到两个服务器上了


3、Ribbon

负载均衡原理:

springcloud 中实现负载均衡是通过 Ribbon 实现的


首先通过访问
肯定是访问不到user的两个服务的,所以途中一定有相关的请求方式的处理,那么 Ribbon 就是充当这个角色,Ribbon 拦截请求后,去找到真是的 ip 端口,第一步需要先知道服务的名称,也就是去找 Eureka 去找服务







调整负载均衡的方案:全局和局部



针对某个微服务:

userservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule# 负载均衡规则 

Ribbon的一个策略


可以看到发这样一个请求的时间是 809 ms,首次请求的时候,Ribbon需要请求Eureka 获取服务列表,首次请求时间较长,之后此服务列表就会被缓存到内存中,所以之后的请求速度就会加快,因为直接从内存去查就 ok 了,这就是懒加载

ribbon:
  eager-load:
    enabled: true
    clients: userservice

修改成饿加载后:随着 Tomcat 的初始化就开始获取注册列表,那么首次发请求的时候就会提高响应的速度,第二次的响应速度明显比第一个响应快的多


4、Nacos 注册中心

接下来我们介绍另外一个注册中心:Nacos 是阿里巴巴旗下产品,相比 Eureka 功能更加丰富

Nacos 下载:按照包,解压,通过控制台执行命令:

startup.cmd -m standalone


启动成功后,就可以通过 http://192.168.31.64:8848/nacos/index.html 进行访问了

转换为 Nacos 注册中心:

先找到父工程的 pom 文件,添加如下依赖:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-dependencies</artifactId>
    <version>2.2.6.RELEASE</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

再改动服务端:

  cloud:
    nacos:
      server-addr: localhost:8848
<dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

重新启动可以看到三个服务已经被注册到了 nacos 上

3、nacos服务多级存储模型

之前通过上面的实例我们可以得知,一个服务可以对应多个实例(占用不同的端口即可),不过随着业务规模的越来越扩大,我们就会考虑更多的问题,我们把所有的实例都部署到一个机房,这就像把鸡蛋都放在一个篮子里,篮子翻了,鸡蛋也就都碎了,机房如果因为天灾人祸出了问题,那整个服务不就完蛋了,那么如何解决问题,我们会把一个服务的多个实例部署到多个机房(部署到各地)

这样避免风险的能力被称之为容灾能力,nacos 借助这样的分地区的理念,每一个地区的实例被称之为集群

在nacos里面一级是服务,二级是集群,三级是实例,那为何nacos要引入这样的层级关系呢?我原来直接用服务找实例不好么,为什么要多加一个地域集群的划分

那么假设我有杭州的如下的这样的一个机房,部署了 oder-service 和 user-service 的实例,上海的机房具有同样的配置

那么我的 oder-service 要访问我的 user-service 那么他有两种访问的方式,一种是在本地的局域网内访问,另一种是去外面的机房的访问,那不用说肯定选本地的,局域网内的访问跨越的距离短,访问的速度更快,延迟比较低,跨越集群的访问,比如杭州访问上海的集群,跨越几百公里,延迟是非常高的,所以在访问过程中,尽可能访问本地的集群,在本地集群不可用的时候,再去访问其他地区的集群,但是我们目前还没有配置过集群属性,我们回到nacos控制台来看


进入详情可以看见

也就是没有集群,下面我们来看一下如何去配置实例的集群属性

首先在yml配置文件中添加:


模拟一下跨集群的部署方式
编辑 userservice 中 application 的 yml 文件


重启这两个服务,那么他就是 HZ 的集群了

那么服务3如何跑到上海集群

此时三个服务都启动起来了,我们回到nacos控制台看一下


可以发现HZ集群和SH集群都配置完毕成功了

上面的集群我们实现完成了,那么我下面要实现的是:orderservice 远程调用 userservice 优先选择本地的集群,因此 orderservice 同样需要配置一个集群属性

  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        cluster-name: HZ

下一步我们回到nacos的控制台

可以发现 orderservice 也已经位于 HZ 集群了,也就是说 orderservice 和 userservice 8081 8082 位于同一集群,我们期望的是,orderservice 在远程调用 userservice 时优先远程调用 8081 和 8082,下面我们通过浏览器访问 order 服务器看是不是我们想的那样

不同的 orderId 访问三次,返回我们查看 IDEA 的日志



通过日志可以看到,8081,8082,8083,都有对应的日志信息,说明他们都被访问了,明显看到并没有优先的选择本地集群,依旧采用的是轮询方式。我们知道选择服务的时候都是通过负载均衡来进行选择的,因为我们这里没有配置规则,所以默认就是轮询方式,所以要想实现优先访问本地服务的负载均衡规则,就需要去配置其规则,那么怎么修改呢

同样在 yml 文件去修改,在 order 服务的 yml 中加:

userservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule

重启 order 服务,再次通过浏览器访问五次 order 服务


可以看到 8083 的日志文件是空的,此时说明已经实现了优先访问本地集群的负载均衡规则了,
清空日志后我们再查看:


此时 8081 和 8082 所接受的请求 id 是不同上面的 5 次 请求
nacos 负载均衡的规则是:优先选择本地的集群,在本地集群多个实例中随机选择

此时如果停止 8081 8082 只剩下 8083,8083 在上海,8080在杭州,我们通过 nacos 控制台可以看到


userservice 的健康实例只有一个,再次访问

可以看到本地没有集群也可以得到相应,返回本地查看 IDEA 日志文件

可以看到请求被 8083 承担了

可以看到 order 服务的 日志文件中 报了一个警告,是提醒进行了一次跨界访问,提醒运维人员去查看

3、我们在日常企业中会遇到一些问题,设备的迭代,有性能好的机器,也有老弱病残的机器,所以我们会希望好的机器能够承受更多的用户请求,性能差一点的承担少一点的请求,我们目前看到的是,集群优先而后做随机,不管性能好坏,此时性能差的可能就会出问题,那么如何控制不同服务的请求量呢,通过修改服务实例的权重,可以控制访问频率,那么我们可以把性能好的集群,权重设置的大一点,性能差的机器,权重设的小一点

配置方法:找到 nacos 控制台,找到编辑,我们看到 user 服务杭州集群的两个实例的权重都是 1,权重一样,就是随机访问了


我们假设8081是老机器,8082 是新机器,我们给 8081 的权重调低

这样 8081 和 8082 的权重比就是 1 : 10 所以理论上来讲,8081 和 8082 被访问到的次数比也应该是 1 : 10,我们实际去跑一下

一个页面我们刷新 20 次,看看 IDEA 的日志

8081:

8082:

明显看到8081只被访问了一次,剩下的都被 8082 承担下来了

那么我们如果修改 8081 的权重为 0 会发生什么


可以看到请求都在 8082,也就是说权重调成 0 后,8081 压根就不会接受到请求了,这有啥作用,在我们以前我们想要对其做版本的升级,我们需要重启服务器,但是重启服务器用户都还访问着了,直接重启有点不好,所以我们版本升级需要等到月黑风高的时候用户都下线了,把服务器停机,偷偷的去做升级,但是现在有了权重,我有多个服务器,我先把 8081 的权重调成 0,然后渐渐的 8081 不承担用户请求了,我对它进行停机,用户并不会有感知,8081 停机后做版本的升级,然后做重启,先从小权重设置,这个时候放出少数用户做个测试,看看有没有问题,那么依次升级,用户是无感知的,可以做到平滑升级


4、nacos 环境隔离(namespace)

nacos 首先是一个注册中心,那么 nacos 其实还是一个数据中心,所以在 nacos 里面,做数据和服务的管理,他会有一个隔离的概念,有这么几个东西



这里的隔离是为了不同环境的服务是相互隔离开的,不同环境的数据也会隔离开。nacos 已经把服务划分成集群、实例,为啥还要划分隔离。服务、实例划分是基于业务去进行划分(地域),那么一些生产环境(开发环境、生产环境)namespace 就是来做这个事情的,至于 group ,我们可以把业务相关度比较高的服务放到一个组(订单和支付服务,相关度比较高可以放到一起)。这个模型是不强制的,可以设计成这样,也可以不设计成这样,下面演示一样,回到 nacos 控制台


这里我们没去配置,是没有分组的

我们点开命名空间,可以看到默认的命名空间叫做 public


回到服务列表,可以看到这俩服务是 public 的


没设置命名空间的情况下,都是为 public,那下面我们新建一个命名空间



此时回到服务列表,此时已经出现了两个命名空间


点击 dev 可以发现是没有任何服务的,是因为没有配置,我们所有的服务都是在 public 下配置的,那我怎么去修改服务的命名空间,需要到代码区域



我们需要复制下来刚刚命名空间的 id


此后重启 order 服务器,可以发现只有 order 是在 dev 命名空间下的,其他三个服务我们没有改

此时 order 服务爆红,说明此时的 order 服务已经挂掉了


可以发现此时的 orderservice 已经是 dev 命名空间下的了,此时 order 服务和 user 服务已经是两个空间下人了,已经没有机会了,不信我们访问试一下


明显看到报错了,看下 IDEA 中的日志


也就是说此时的 user 服务和 order 服务已经阴阳两隔,没有关系了,所以这里无法访问,这就是环境隔离

5、Nacos 注册中心和 Eureka 的对比


服务消费者会有对应的 服务列表缓存 首次拉取服务后,会缓存到对应的服务列表中,方便之后消费,为了防止服务信息的变更,所以服务列表每隔 30s 会向注册中心拉取服务信息,消费者拿到服务信息以后,再去负载均衡,再去发起调用即可,但是在 nacos 中还是和 Eureka 中有些许区别,目前为止两者是一样的,差别是服务提供者的健康检测,那么 nacos 会把服务的提供者,划分为临时实例和非临时实例,我们查看一下 nacos 控制台


可以看到所有实例默认情况下都是临时实例,临时实例 和 非临时在 nacos 中健康检测是不一样的,因为是临时的,所以我们将来可能随时把服务停掉,所以临时实例在 nacos 健康检测中使用的心跳机制(和 Eureka 一样),不跳了 直接踢掉,非临时就不会要求去找心跳检测,此时是 nacos 主动发送请求去询问:“你还活着吗”,即使非临时不在存活,nacos 也会等待其复活,也不会从注册中心中剔除,这就是差别之一


差别二就是:这个消费者是每隔 30s 拉取一次,如果在 30s 有提供者挂了,消费者不知道,再去消费就会出问题,所以 Eureka 做服务拉取,服务的更新效率比较差,更新的不够及时,nacos 做的是消息推送,也就是说 nacos 做的是 push + pull Eureka 只是做 pull,所以一旦有提供者挂了,就会立刻去给消费者 push 主动告诉消费者服务变更,这样时效性更好


下面通过代码去测试一下,临时实例和非临时实例的差别:

如何设置临时和非临时实例


通过:

        ephemeral: false # 非临时实例

此时我们把 order 服务关掉


此时控制台中就没有此服务了,此时再次启动 order 服务(此次就是非临时的实例了)


这时候,再把 order 服务停掉,一瞬间就会爆红,而且服务不会被剔除,等着你重启(除非你手动删除)


这时候我们再启动起来,就是健康状态了~


主动检测这边服务器压力比较大,所以更加推荐临时实例


Nacos 配置管理

目前我们了解到了的微服务架构


随着我们微服务越来越多,生产环境中,可能会达到成千上百的服务器,这个时候如果配置文件需要做一些修改,而这个配置文件和我们数十个微服务都有关系,那这个时候需要逐个微服务去调整这个配置,很麻烦。调整完配置关联的服务都需要重启,生产环境中,服务重启的影响还是很大的,所以说我们的需求是我们希望配置文件可以统一管理,同一改动并且不用重启,就可以更新这叫配置的热更新。我们需要配置管理的服务(他会记录微服务中一些核心的配置),服务启动起来会先去读取配置管理服务中的服务再去和本地的配置结合作为完成配置去使用,将来的核心配置发生修改,找到配置管理的服务,把需要改变的配置改一改就ok了,并且会主动通知各个服务我的配置发生了修改,配置变了,赶紧去修改,实现配置的热更新。我们借助 nacos 就能实现


演示一下,如何通过 nacos 实现配置的管理,我们回到 nacos 控制台

已经把配置文件发布到 nacos 上了,那么如何去拉取配置呢

没有 nacos 的时候如何获取配置文件:


我们现在多了 nacos ,多了一个本地 yml 和 nacos 的 yml 的合并过程:


读取 nacos 的配置文件,需要知道 nacos 的地址,然而 nacos 的地址又在 application.yml 文件中,所以需要提前知道 nacos 地址,所以借助 bootstrap.yml 文件来获取 nacos 地址,此 yml 文件比 application.yml 文件的优先级高很多,所以项目启动后先读取 bootstrap.yml


所以 nacos 的配置信息,都需要放入到 bootstrap.yml

找到 userservice 的 pom 文件添加 nacos 配置管理依赖

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

添加 bootstrap.yaml 文件

spring:
  application:
    name: userservice
  profile:
    active: dev #环境
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos 地址
      config:
        file-extension: yaml #文件后缀名

删除 application 中重复的配置内容


测试是否读取到了 nacos 中的配置文件内容,通过 value 注解实现





可以看到 userservice 成功从 nacos 中拉取到了配置

2、nacos 配置的热更新

我们现在更新 nacos 里面的配置文件


再次访问 user 服务


发现没有更新还是刚刚的配置,我们希望的是,刷新后立马就要发生变化,所以需要我们手动配置一下




这是重启后的结果,但是我们再次修改配置文件:



刷新后直接就 ok 了

第二种方法:






也可以实现,所以这里更加推荐第二种注册方法

3、微服务的配置共享,有一个配置属性,在开发生产测试等环境下的值是一样,像这样的配置,每个配置文件都去写一份,有点浪费,如果要改动,每个配置文件都要改,所以希望在一个地方改,其他也就 ok 了,所以这就是微服务多环境共享

回到控制台,加一个配置


测试:8081位于开发环境,8082位于测试环境



可以发现 8082 只能读取到共享属性值

我们在看本地如果有一个叫做 name 的属性值:这里可以成功读取到

如果本地的 name 和共享环境冲突:优先读取共享环境中的 name


如果开发环境中也有重复的 name


4、nacos 集群搭建:

前面是 nacos 的基本用法,我们的 nacos 一直采用的是单点的方式,我们自己测试的时候还是可以的,企业中是不可以的,企业中 nacos 一点要做一个集群



5、Feign

Http 客户端 Feign

RestTemplate 方式调用存在的问题

这里请求的方式是通过 url 来进行访问的,resttemplate 代替我们去方式请求,再把结果转换成对应的类型,虽然这里的代码已经优化了,但是还是存在一些问题

1、代码可读性差,编程体验不统一
2、参数复杂 URL 难以维护,当 URL 的参数增多时,维护的难度很大

声明式就是在配置文件中声明好了,其他的事情都不需要你管了,都交给 Feign 来处理,就和 Spring 的声明式是一样的。咱们现在不是要发起 http 请求嘛,发起来麻烦,那么把发请求的信息声明出来就 ok 了,剩下的事情由 Feign 来做

具体做法:

第一步找到 orderservice 的依赖文件,在依赖文件中加入:

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

第二步:开启自动装配的功能,找到启动类

第三步:编写客户端做接口声明

@FeignClient("userservice")
public interface UserClient 
    @GetMapping("/user/id")
    User findById(@PathVariable("id") Long id); 



通过访问可以发现,feign 远程调用成功




可以发现,三个 user 服务都有收到请求,那么可以证明,这里 feign 里面自动做了负载均衡,因为 feign 中封装好了 ribbon

2、feign 的自定义配置


修改配置有两种方式:通过修改配置文件



可以看到这里的 feign 的信息是非常全的,这是通过 yaml 文件修改的

<

以上是关于微服务与分布式——SpringCloud的主要内容,如果未能解决你的问题,请参考以下文章

024.微服务之服务注册与发现(基于kubernetes / SpringCloud)

微服务与分布式——SpringCloud

构建SpringBoot,SpringCloud微服务架构分布式电商项目实战

SpringCloud微服务之初识微服务01

SpringCloud微服务之初识微服务01

微服务SpringCloud之注册中心Consul