1.微服务的介绍

1.1系统架构演变

随着互联网的发展,网站应用的规模也在不断的扩大,进而导致系统架构也在不断的进行变化。   从互联网早起到现在,系统架构大体经历了下面几个过程: 单体应用架构--->垂直应用架构--->分布式架构--->SOA架构--->微服务架构,当然还有悄然兴起的Service Mesh(服务网格化)

接下来我们就来了解一下每种系统架构是什么样子的, 以及各有什么优缺点。

1.1.1单体应用架构

互联网早期,一般的网站应用流量较小,只需一个应用,将所有功能代码都部署在一起就可以,这样可以减少开发、部署和维护的成本。

比如说一个电商系统,里面会包含很多用户管理,商品管理,订单管理,物流管理等等很多模块,  我们会把它们做成一个web项目,然后部署到一台tomcat服务器上。

优点:

  • 项目架构简单,小型项目的话,开发成本低。
  • 项目部署在一个节点上,维护方便

缺点:

  • 全部功能集成在一个工程中,对于大型项目来讲不易开发和维护[修改代码]。
  • 项目模块之间紧密耦合,单点容错率低。
  • 无法针对不同模块进行针对性优化和水平扩展

1.1.2垂直应用架构

随着访问量的逐渐增大,单一应用只能依靠增加节点来应对,但是这时候会发现并不是所有的模块  都会有比较大的访问量。

还是以上面的电商为例子, 用户访问量的增加可能影响的只是用户和订单模块, 但是对消息模块的影响就比较小. 那么此时我们希望只多增加几个订单模块, 而不增加消息模块.  此时单体应用就做不到了, 垂直应用就应运而生了.

所谓的垂直应用架构,就是将原来的一个应用拆成互不相干的几个应用,以提升效率。比如我们可  以将上面电商的单体应用拆分成:

电商系统(用户管理 商品管理 订单管理)

后台系统(用户管理 订单管理 客户管理)

CMS系统(广告管理 营销管理)

这样拆分完毕之后,一旦用户访问量变大,只需要增加电商系统的节点就可以了,而无需增加后台  和CMS的节点。建立三个工程。

优点:

  • 系统拆分实现了流量分担,解决了并发问题,可以针对不同模块进行优化和水平扩展
  • 一个系统的问题不会影响到其他系统,提高容错率

缺点:

  • 系统之间相互独立, 无法进行相互调用
  • 系统之间相互独立, 会有重复的开发任务

1.1.3分布式架构

当垂直应用越来越多,重复的业务代码就会越来越多。这时候,我们就思考可不可以将重复的代码  抽取出来,做成统一的业务层作为独立的服务(service),然后由前端控制层(controller)调用不同的业务层服务呢?

这就产生了新的分布式系统架构。它将把工程拆分成表现层controller和服务层service两个部分,服务层中包含业务  逻辑。表现层只需要处理和页面的交互,业务逻辑都是调用服务层的服务来实现。

优点:

  • 抽取公共的功能为服务层,提高代码复用性

缺点:

  • 调用关系错综复杂,难以维护

1.1.4.SOA架构----阿里dubbo

在分布式架构下,当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心集群进行实时管理。此时,用于资源调度和治理中心(SOA Service Oriented Architecture,面向服务的架构)是关键。

优点:

  • 使用注册中心解决了服务间调用关系的自动调节

缺点:

  • 服务间会有依赖关系,一旦某个环节出错会影响较大( 服务雪崩 )
  • 服务关系复杂,运维、测试部署困难。

1.1.5微服务架构

微服务架构在某种程度上是面向服务的架构SOA继续发展的下一步,它更加强调服务的"彻底拆分"---->必须要springboot(独立的系统) 必须依赖于springboot技术。Springcloud如果没有springboot 那么springcloud也无法使用。 springboot可以独立使用。因为springboot里面内置了tomcat   独立运行。Java -jar xxx.jar

只适合大工程。移动互联网 电商项目 p2p 等,

系统管理--->系统微服务   入库管理 -----入库微服务 

优点:

  • 服务原子化拆分,独立打包、部署和升级,保证每个微服务清晰的任务划分,利于扩展
  • 微服务之间采用Restful等轻量级http协议相互调用

缺点:小型项目----微服务架构不合适。仓库系统---微服务。

  • 微服务系统开发的技术成本高《高》(容错、分布式事务等)

1.2微服务架构介绍

微服务架构, 简单的说就是将单体应用进一步拆分,拆分成更小的服务,每个服务都是一个可以独立运行的项目。

1.2.1 微服务架构的常见问题。

针对每个问题使用不同的组件来讲解。

一旦采用微服务系统架构,就势必会遇到这样几个问题:

  1. 这么多小服务,如何管理他们?  
  2. 这么多小服务,他们之间如何通讯?调用
  3. 这么多小服务,客户端怎么访问他们?前端
  4. 这么多小服务,一旦出现问题了,应该如何自处理?
  5. 这么多小服务,一旦出现问题了,应该如何排错?

Springcloud微服务就是针对上面这些问题 提出的解决方案。

对于上面的问题,是任何一个微服务设计者都不能绕过去的,因此大部分的微服务产品都针对每一个问题提供了相应的组件来解决它们。---学习如何解决上面的问题==组件。

1.2.2微服务架构的常见概念 

1.2.2.1服务治理

服务治理就是进行服务的自动化管理,其核心是服务的自动注册与发现。

服务注册:服务实例将自身服务信息注册到注册中心

服务发现:服务实例通过注册中心,获取到注册到其中的服务实例的信息,通过这些信息去请求它们提供的服务。

服务剔除:服务注册中心将出问题的服务自动剔除到可用列表之外,使其不会被调用到。

1.2.2.2 服务调用

在微服务架构中,通常存在多个服务之间的远程调用的需求。目前主流的远程调用技术有基于HTTP的RESTful接口以及基于TCP的RPC协议。

REST(Representational State Transfer)

这是一种HTTP调用的格式,更标准,更通用,无论哪种语言都支持http协议。 

RPC(Remote Promote Call)

Rpc  @Autowire Bservice  bservice.方法():

一种进程间通信方式。允许像调用本地服务一样调用远程服务。RPC框架的主要目标就是让远程服务调用更简单、透明。RPC框架负责屏蔽底层的传输方式、序列化方式和通信细节。开发人员在使用的时候只需要了解谁在什么位置提供了什么样的远程服务接口即可,并不需要关心底层通信细节和调用过程。

区别与联系

1.2.2.3 服务网关 

随着微服务的不断增多,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信可能出现:

  1. 客户端需要调用不同的url地址,增加难度
  2. 在一定的场景下,存在跨域请求的问题
  3. 每个微服务都需要进行单独的身份认证

针对这些问题,API网关顺势而生。

API网关直面意思是将所有API调用统一接入到API网关层,由网关层统一接入和输出。一个网关的基本功能有:统一接入、安全防护、协议适配、流量管控、长短链接支持、容错能力。有了网关之后,各个API服务提供团队可以专注于自己的的业务逻辑处理,而API网关更专注于安全、流量、路由等问题。

1.2.2.4 服务容错  

在微服务当中,一个请求经常会涉及到调用几个服务,如果其中某个服务不可用,没有做服务容错的话,极有可能会造成一连串的服务不可用,这就是雪崩效应

我们没法预防雪崩效应的发生,只能尽可能去做好容错。服务容错的三个核心思想是:

  1. 不被外界环境影响
  2. 不被上游请求压垮
  3. 不被下游响应拖垮

1.2.2.5 链路追踪  

随着微服务架构的流行,服务按照不同的维度进行拆分,一次请求往往需要涉及到多个服务。互联网应用构建在不同的软件模块集上,这些软件模块,有可能是由不同的团队开发、可能使用不同的编程语言来实现、有可能布在了几千台服务器,横跨多个不同的数据中心。因此,就需要对一次请求涉及的多个服务链路进行日志记录,性能监控即链路追踪

1.2.3微服务架构常见的解决方案

1.2.3.1 ServiceComb

Apache ServiceComb,前身是华为云的微服务引擎 CSE (Cloud Service Engine) 云服务,是全球首个Apache微服务顶级项目。它提供了一站式的微服务开源解决方案,致力于帮助企业、用户和开发者将企业应用轻松微服务化上云,并实现对微服务应用的高效运维管理.

1.2.3.2.SpringCloud springcloud 很多组件都是拿的是Netflix公司,这家公司这些组件停止维护和更新。)

Spring Cloud是一系列框架的集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。

Spring Cloud并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。已经停更了。Euruka(注册中),feign远程调用,hystrix 容错,zuul网关 

1.2.3.3SpringCloud Alibaba(引入springcloud很多组件都更新了。) springcloud alibaba

Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。

1.3 SpringCloud Alibaba介绍

Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。

依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以将 Spring Cloud 应用接入阿里微服务解决方案,通过阿里中间件来迅速搭建分布式应用系统。

1.3.1 主要功能

服务限流降级:默认支持 WebServletWebFlux OpenFeignRestTemplateSpring Cloud

Gateway Zuul Dubbo RocketMQ 限流降级功能的接入,可以在运行时通过控制台实时修

改限流降级规则,还支持查看限流降级 Metrics 监控。

服务注册与发现:适配 Spring Cloud 服务注册与发现标准nacos,默认集成了 Ribbon 的支持。

分布式配置管理:支持分布式系统中的外部化配置,配置更改时自动刷新。

消息驱动能力:基于 Spring Cloud Stream 为微服务应用构建消息驱动能力。

分布式事务:使用 @GlobalTransactional 注解, 高效并且对业务零侵入地解决分布式事务问题。

阿里云对象存储:阿里云提供的海量、安全、低成本、高可靠的云存储服务。支持在任何应用、任

何时间、任何地点存储和访问任意类型的数据。

分布式任务调度:提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。

同时提供分布式的任务执行模型,如网格任务。网格任务支持海量子任务均匀分配到所有

Workerschedulerx-client)上执行。

阿里云短信服务:覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建

客户触达通道。

1.3.2 组件

Sentinel:把流量作为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳

定性。

Nacos:一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。

RocketMQ:一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠

的消息发布与订阅服务。

DubboApache Dubbo™ 是一款高性能 Java RPC 框架。

Seata:阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。

Alibaba Cloud ACM:一款在分布式架构环境中对应用配置进行集中管理和推送的应用配置中心

产品。

Alibaba Cloud OSS: 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提

供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储

访问任意类型的数据。

Alibaba Cloud SchedulerX: 阿里中间件团队开发的一款分布式任务调度产品,提供秒级、精

准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。

Alibaba Cloud SMS: 覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速

搭建客户触达通道。

理论好好读读。

微服务拆分的原则

之前你维护的一体化架构就像是一个大的蜘蛛网,不同功能模块错综复杂地交织在一起,方法之间调用关系非常的复杂,导致你修复了一个 Bug 可能会引起另外多个 Bug,整体的维护成本非常高。同时,数据库较弱的扩展性也限制了服务的扩展能力

出于上述考虑,你要对架构做拆分。但拆分并不像听上去那么简单,这其实就是将整体工程重构甚至重写的过程。你需要将代码拆分到若干个子工程里面,再将这些子工程通过一些通信方式组装起来,这对架构是很大的调整,需要跨多个团队协作完成。

所以在开始拆分之前你需要明确几个拆分的原则,否则就会事倍功半甚至对整体项目产生不利的影响。

         原则一做到单一服务内部功能的高内聚和低耦合

也就是说每个服务只完成自己职责之内的任务,对于不是自己职责的功能交给其它服务来完成。说起来你可能觉得理所当然对这一点不屑一顾,但很多人在实际开发中,经常会出现一些问题。

比如,我之前的项目中有用户服务和内容服务,用户信息中有“是否为认证用户”字段。组内有个同事在内容服务里有这么一段逻辑:如果用户认证字段等于 1,代表是认证用户,那么就把内容权重提升。问题是判断用户是否为认证用户的逻辑应该内聚在用户服务内部,而不应该由内容服务判断,否则认证的逻辑一旦变更内容服务也需要一同跟着变更,这就不满足高内聚、低耦合的要求了。所幸我们在 Review 代码时及时发现了这个问题,并在服务上线之前修复了它。

           原则二,你需要关注服务拆分的粒度,先粗略拆分再逐渐细化

在服务拆分的初期,你其实很难确定服务究竟要拆分成什么样。但是从“微服务”这几个字来看,服务的粒度貌似应该足够小,甚至有“一方法一服务”的说法。不过服务多了也会带来问题,像是服务个数的增加会增加运维的成本。再比如原本一次请求只需要调用进程内的多个方法,现在则需要跨网络调用多个 RPC 服务,在性能上肯定会有所下降。

所以我推荐的做法是:拆分初期可以把服务粒度拆得粗一些,后面随着团队对于业务和微服务理解的加深,再考虑把服务粒度细化。比如对于一个社区系统来说,你可以先把和用户关系相关的业务逻辑,都拆分到用户关系服务中,之后,再把比如黑名单的逻辑独立成黑名单服务。

         原则三,拆分的过程,要尽量避免影响产品的日常功能迭代

也就是说,要一边做产品功能迭代,一边完成服务化拆分。

还是拿我之前维护的一个项目举例。我曾经在竞品对手快速发展的时期做了服务的拆分,拆分的方式是停掉所有业务开发全盘推翻重构,结果错失了产品发展的最佳机会,最终败给了竞争对手。

因此,我们的拆分只能在现有一体化系统的基础上不断剥离业务独立部署,剥离的顺序你可以参考以下几点:

    1. 优先剥离比较独立的边界服务(比如短信服务、地理位置服务),从非核心的服务出发减少拆分对现有业务的影响,也给团队一个练习、试错的机会;

    2. 当两个服务存在依赖关系时优先拆分被依赖的服务。比如内容服务依赖于用户服务获取用户的基本信息,那么如果先把内容服务拆分出来,内容服务就会依赖于一体化架构中的用户模块,这样还是无法保证内容服务的快速部署能力。

    所以正确的做法是理清服务之间的调用关系,比如内容服务会依赖用户服务获取用户信息,互动服务会依赖内容服务,所以要按照先用户服务再内容服务,最后互动服务的顺序来进行拆分。

     原则四,服务接口的定义要具备可扩展性

服务拆分之后,由于服务是以独立进程的方式部署,所以服务之间通信就不再是进程内部的方法调用而是跨进程的网络通信了。在这种通信模型下服务接口的定义要具备可扩展性,否则在服务变更时会造成意想不到的错误。

在之前的项目中,某一个微服务的接口有三个参数,在一次业务需求开发中,组内的一个同学将这个接口的参数调整为了四个,接口被调用的地方也做了修改,结果上线这个服务后却不断报错,无奈只能回滚。

这是因为这个接口先上线后参数变更成了四个,但是调用方还未变更还是在调用三个参数的接口,那就肯定会报错了。所以服务接口的参数类型最好是封装类,这样如果增加参数就不必变更接口的签名,而只需要在类中添加字段就可以了。

2.微服务环境搭建

我们本次是使用的电商项目中的商品微服务订单微服务为案例进行讲解。

2.1案例准备

2.1.1 技术选型

maven3.5.0+

数据库MySQL 5.7 以上

持久层: Mybatis-plus 《Mybatis  Mapper Mybatis-plus》

其他: SpringCloud Alibaba 技术栈  druid

2.1.2 模块设计

springcloud-alibaba 父工程 ----jar的版本管理  公共jar的引入

shop-common 公共模块【实体类】 《实体类,公共依赖,工具类。》

shop-product 商品微服务 【端口: 8080~8089  搭建集群

shop-order 订单微服务 【端口: 8090~8099  搭建集群

2.1.3 微服务调用

在微服务架构中,最常见的场景就是微服务之间的相互调用。我们以电商系统中常见的用户下单

例来演示微服务的调用:客户向订单微服务发起一个下单的请求,在进行保存订单之前需要调用商品微服务查询商品的信息。

我们一般把服务的主动调用方称为服务消费者,把服务的被调用方称为服务提供者

在这种场景下,订单微服务就是一个服务消费者, 商品微服务就是一个服务提供者。

2.2 创建父工程

创建一个maven工程,然后在pom.xml文件中添加下面内容

导入依赖:

将自动生成的依赖删除一下,还有他们的版本号要对应,下面地址是其他博客的写的版本对应

http://springboot,springCloud,springCloudAlibaba各版本之间的对应关系_lwdbcy的博客-CSDN博客icon-default.png?t=M7J4http://springboot,springCloud,springCloudAlibaba各版本之间的对应关系_lwdbcy的博客-CSDN博客

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <modules>
        <module>0818-ysh-commont</module>
        <module>0818-ysh-order</module>
        <module>0818-ysh-product</module>
        <module>0818-ysh-eureka</module>
        <module>0820-ysh-gateway</module>
    </modules>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.12.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.qy151</groupId>
    <artifactId>0818-ysh-parent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>0818-ysh-parent</name>
    <description>Demo project for Spring Boot</description>
    <!--第二步如果你的工程为父工程那么它的打包方式为pom-->
    <packaging>pom</packaging>
    <!--定义版本号-->
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF- 8</project.reporting.outputEncoding>
        <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
        <spring-cloud-alibaba.version>2.2.3.RELEASE</spring-cloud-alibaba.version>
    </properties>


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


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

    <!--dependencyManagement:它只负责jar的版本号管理,不负责jar的下载,交于子模块,子模块在使用时无需指定版本号
          :springboot springcloud  springcloudalibaba之间版本一定要匹配
    -->
    <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>
            <!--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>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

 2.3 创建基础模块

2.3.1 创建 common 模块,在pom.xml中添加依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <!--父组件的名称-->
    <parent>
        <artifactId>0818-ysh-parent</artifactId>
        <groupId>com.qy151</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <!--当前组件的名称-->
    <artifactId>0818-ysh-commont</artifactId>


    <dependencies>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

</project>

2.3.3 创建实体类

package com.qy151.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@Data
@TableName(value="shop_product")
public class Product {
    @TableId(type= IdType.AUTO)
    private Integer pid;
    private String pname;//商品名称
    private Double pprice;//商品价格
    private Integer stock;//库存
}
package com.qy151.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@Data
@TableName("shop_order")
public class Order {
    @TableId(type = IdType.AUTO)
    private Long oid; //订单id
    private Integer uid;//用户id
    private String username;//用户名
    private Integer pid;//商品id
    private String pname;//商品名称
    private Double pprice;//商品价格
    private Integer number;//购买数量
}

2.4 商品微服务--对商品进行操作

步骤:

1 创建模块 导入依赖

2 创建SpringBoot主类

3 加入配置文件

4 创建必要的接口和实现类(controller service dao)

2.4.1 创建pom.xml

<!--引入公共模块-->
    <dependency>
        <groupId>com.qy151</groupId>
        <artifactId>0818-ysh-commont</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>


    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>

2.4.2创建配置类并在配置文件中写入数据源

#为了后期扩展方便微服务的端口号设置为8080-8090之间
server.port=8081
#数据源
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.password=root
spring.datasource.username=root
spring.datasource.url=jdbc:mysql://localhost:3306/springcloud?serverTimezone=Asia/Shanghai
#日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

2.4.3添加主启动类

package com.qy151;

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

/**
 * @program: qy151-ysh-parent
 * @description:
 * @author: YSH
 * @create: 2022-08-18 11:28
 **/
@SpringBootApplication
public class ProductApp {
    public static void main(String[] args) {
        SpringApplication.run(ProductApp.class,args);
    }
}

2.4.4创建ProductController类

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @BelongsProject: 0818-ysh-parent
 * @BelongsPackage: com.qy151.controller
 * @unthor : YSH
 * @date : 2022/8/18 16:31
 */
@RestController
@RequestMapping("/product")
public class ProductController {

    @Autowired
    private ProductService productService;

    @GetMapping("/getById/{pid}")
    public Product getById(@PathVariable Integer pid){
        return productService.findById(pid);
    }
}

2.4.5创建ProductService接口

package com.qy151.service;

import com.qy151.entity.Product;

/**
 * @BelongsProject: 0818-ysh-parent
 * @BelongsPackage: com.qy151.dao.service
 * @unthor : YSH
 * @date : 2022/8/18 16:28
 */
public interface ProductService {
    Product findById(Integer pid);
}

2.4.6ProductServiceImpl实现类

package com.qy151.service.impl;

import com.qy151.dao.ProductMapper;
import com.qy151.entity.Product;
import com.qy151.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @BelongsProject: 0818-ysh-parent
 * @BelongsPackage: com.qy151.service.impl
 * @unthor : YSH
 * @date : 2022/8/18 16:30
 */
@Service
public class ProductServiceImpl implements ProductService {
    @Autowired
    private ProductMapper productMapper;

    @Override
    public Product findById(Integer pid) {

        return productMapper.selectById(pid);
    }
}

2.4.7创建创建ProductDao接口

package com.qy151.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.qy151.entity.Product;
import org.apache.ibatis.annotations.Mapper;

/**
 * @BelongsProject: 0818-ysh-parent
 * @BelongsPackage: com.qy151.dao
 * @unthor : YSH
 * @date : 2022/8/18 16:27
 */
@Mapper
public interface ProductMapper extends BaseMapper<Product> {
}

2.4.8 启动工程,等到数据库表创建完毕之后,加入测试数据 

INSERT INTO shop_product VALUE(NULL,'小米','1000','5000'); 
INSERT INTO shop_product VALUE(NULL,'华为','2000','5000'); 
INSERT INTO shop_product VALUE(NULL,'苹果','3000','5000'); 
INSERT INTO shop_product VALUE(NULL,'OPPO','4000','5000');

2.4.9.通过浏览器访问服务 

2.5创建订单微服务

2.5.1 创建一个名为 order 的模块,并添加springboot依赖

 <!--引入公共模块-->
        <dependency>
            <groupId>com.qy151</groupId>
            <artifactId>0818-ysh-commont</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>


        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

2.5.2创建启动类

ackage com.qy151;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

/**
 * @BelongsProject: 0818-springcloud-parent
 * @BelongsPackage: com.qy151.order
 * @unthor : YSH
 * @date : 2022/8/18 14:35
 */
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderApp {
    public static void main(String[] args) {
        SpringApplication.run(OrderApp.class,args);
    }
}

2.5.3创建配置文件application.properties 

# 为了后期扩展方便订单微服务的端口设置为8090~8099之间
server.port=8091
 
#数据源
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springcloud?serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root
 
#sql日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

2.5.4创建OrderDao接口

package com.qy151.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.qy151.entity.Order;
import org.apache.ibatis.annotations.Mapper;

/**
 * @BelongsProject: 0818-ysh-parent
 * @BelongsPackage: com.qy151.dao
 * @unthor : YSH
 * @date : 2022/8/18 16:39
 */
@Mapper
public interface OrderMapper extends BaseMapper<Order> {
}

2.5.5创建OrderService接口

package com.qy151.service;

import com.qy151.entity.Order;

/**
 * @BelongsProject: 0818-ysh-parent
 * @BelongsPackage: com.qy151.service
 * @unthor : YSH
 * @date : 2022/8/18 16:37
 */
public interface OrderService {
    int saveOrder(Order order);
}

2.5.6创建OrderServiceImpl实现类

package com.qy151.service.impl;

import com.qy151.dao.OrderMapper;
import com.qy151.entity.Order;
import com.qy151.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @BelongsProject: 0818-ysh-parent
 * @BelongsPackage: com.qy151.service.impl
 * @unthor : YSH
 * @date : 2022/8/18 16:37
 */
@Service
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderMapper orderMapper;

    @Override
    public int saveOrder(Order order) {
        return orderMapper.insert(order);
    }
}

2.5.7创建OrderController类

@RestController
@RequestMapping("order")
public class OrderController {
    @Autowired
    private OrderServiceImpl orderService;
    //注入工具类 --这个工具类没有交于容器管理,需要自己手动交于容器
    @Autowired
    private RestTemplate restTemplate;
    @GetMapping("buy/{pid}/{num}")
    public String buy(@PathVariable Integer pid,@PathVariable Integer num){
        System.out.println("=======购买开始===========");
        Order order=new Order();
        //设置购买的数量
        order.setNumber(num);
        //设置购买人的名字
        order.setUsername("YYY");
        //设置id
        order.setUid(1);
        //设置订单中商品的信息
        //由于商品的信息在商品微服务中,如果想要用,得调用
        //远程调用有两种方法1.http协议的restful风格的调用--适合微服务2.基于TCp协议的RPC--适合SOA分布式
        //所以我们用http协议--1.自己写代码完成http的调用
        // 2springboot提供一个工具类RestTemplate--属于http协议完成的调用
        Product forObject = restTemplate.getForObject("http://localhost:8081/product/getById/" + pid, Product.class);
        //获取商品的id
        order.setPid(pid);
        order.setPprice(forObject.getPprice());
        order.setPname(forObject.getPname());
        orderService.saveOrder(order);
        System.out.println("==========购买结束=========");
        return "下单成功";
    }
}

2.5.8启动工程并在浏览器上测试 

3.Nacos Discovery--服务治理

3.1 服务治理介绍

先来思考一个问题

通过上一章的操作,我们已经可以实现微服务之间的调用。但是我们把服务提供者的网络地址(ip,端口)等硬编码到了代码中,这种做法存在许多问题

  • 一旦服务提供者地址变化,就需要手工修改代码
  • 一旦是多个服务提供者,无法实现负载均衡功能
  • 一旦服务变得越来越多,人工维护调用关系困难

那么应该怎么解决呢, 这时候就需要通过注册中心动态的实现服务治理

3.1.1什么是服务治理

服务治理是微服务架构中最核心最基本的模块。用于实现各个微服务的自动化注册与发现

服务注册:在服务治理框架中,都会构建一个注册中心,每个服务单元向注册中心登记自己提供服

务的详细信息。并在注册中心形成一张服务的清单,服务注册中心需要以心跳30s  90s的方式去监测清单中 的服务是否可用,如果不可用,需要在服务清单中剔除不可用的服务。

服务发现:服务调用方向服务注册中心咨询服务,并获取所有服务的实例清单,实现对具体服务实

例的访问。

通过上面的调用图会发现,除了微服务,还有一个组件是服务注册中心,它是微服务架构非常重要

的一个组件,在微服务架构里主要起到了协调者的一个作用。注册中心一般包含如下几个功能:

1. 服务发现:

服务注册:保存服务提供者和服务调用者的信息

服务订阅:服务调用者订阅服务提供者的信息,注册中心向订阅者推送提供者的信息

2. 服务配置:

配置订阅:服务提供者和服务调用者订阅微服务相关的配置

配置下发:主动将配置推送给服务提供者和服务调用者

3. 服务健康检测

检测服务提供者的健康情况,如果发现异常,执行服务剔除

3.1.2常见的注册中心

Zookeeper

zookeeper是一个分布式服务框架,是Apache Hadoop 的一个子项目,它主要是用来解决分布式

应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用

配置项的管理等。

Eureka

EurekaSpringcloud Netflix中的重要组件,主要作用就是做服务注册和发现。但是现在已经

,停更不停用。

Consul

Consul是基于GO语言开发的开源工具,主要面向分布式,服务化的系统提供服务注册、服务发现

和配置管理的功能。Consul的功能都很实用,其中包括:服务注册/发现、健康检查、Key/Value

存储、多数据中心和分布式一致性保证等特性。Consul本身只是一个二进制的可执行文件,所以

安装和部署都非常简单,只需要从官网下载后,在执行对应的启动脚本即可。

Nacos (服务治理  配置中心)--我们使用nacos

Nacos是一个更易于构建云原生应用的动态服务发现配置管理服务管理平台。它是 Spring

Cloud Alibaba 组件之一,负责服务注册发现服务配置,可以这样认为nacos=eureka+config

3.2 nacos简介

Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速

实现动态服务发现、服务配置、服务元数据及流量管理。

从上面的介绍就可以看出,nacos的作用就是一个注册中心,用来管理注册上来的各个微服务。

3.3 nacos实战入门

接下来,我们就在现有的环境中加入nacos,并将我们的两个微服务注册上去。

nacos下载地址

Releases · alibaba/nacos · GitHuban easy-to-use dynamic service discovery, configuration and service management platform for building cloud native applications. - Releases · alibaba/nacoshttps://github.com/alibaba/nacos/releases

3.3.1 搭建nacos环境

1: 安装nacos

下载地址: https://github.com/alibaba/nacos/releases

下载zip格式的安装包,然后进行解压缩操作 

2: 启动nacos

进入Nacos 中bin文件

进入cmd执行:startup.cmd -m standalone

3: 访问nacos

打开浏览器输入http://localhost:8848/nacos,即可访问服务, 默认密码是nacos/nacos 

3.3.2 将商品微服务注册到nacos

接下来开始修改 product 模块的代码, 将其注册到nacos服务上

1 pom.xml中添加nacos的依赖

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

2.在主启动类上添加nacos的开启注解

package com.qy151;

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

/**
 * @program: qy151-ysh-parent
 * @description:
 * @author: YSH
 * @create: 2022-08-18 11:28
 **/
@SpringBootApplication
@EnableDiscoveryClient  //开启nacos注解
public class ProductApp {
    public static void main(String[] args) {
        SpringApplication.run(ProductApp.class,args);
    }
}

 3.在application.properties添加nacos的配置

#配置nacos注册中心的地址
spring.cloud.nacos.discovery.server-addr=localhost:8848
#指定是否把该服务注册到注册中心
#spring.cloud.nacos.discovery.register-enabled=false
#指定微服务的名称
spring.application.name=springcloud-ysh-product

4. 启动服务, 观察nacos的控制面板中是否有注册上来的商品微服务

3.3.3 将订单微服务注册到nacos

接下来开始修改 order 模块的代码, 将其注册到nacos服务上

1 pom.xml中添加nacos的依赖

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

2 在主启动类上添加nacos的开启注解

@SpringBootApplication
@EnableDiscoveryClient //开启nacos的注解
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class,args);
    }
}

3. 在application.properties中添加nacos服务的配置

#配置nacos注册中心的地址
spring.cloud.nacos.discovery.server-addr=localhost:8848
#指定是否把该服务注册到注册中心
#spring.cloud.nacos.discovery.register-enabled=false
#指定微服务的名称   切记不能用_分隔
spring.application.name=springcloud-ysh-order

4 启动服务, 观察nacos的控制面板中是否有注册上来的商品微服务

5 修改OrderController中的代码 

@RestController
@RequestMapping("order")
public class OrderController {
    @Autowired
    private OrderServiceImpl orderService;
    //注入工具类 --这个工具类没有交于容器管理,需要自己手动交于容器
    @Autowired
    private RestTemplate restTemplate;
    //spring 中提供一个工具类,该类可以从注册中心来取微服务的信息
    @Autowired
    private DiscoveryClient discoveryClient;
 
    @GetMapping("buy/{pid}/{num}")
    public String buy(@PathVariable Integer pid,@PathVariable Integer num){
        System.out.println("=======购买开始===========");
        Order order=new Order();
        //设置购买的数量
        order.setNumber(num);
        //设置购买人的名字
        order.setUsername("东方青苍");
        //设置id
        order.setUid(1);
       //拉取商品的信息
        //1.拉取服务名称对应的所有实例对象j
        List<ServiceInstance> instances = discoveryClient.getInstances("product");
        //获取第一个实例对象
        ServiceInstance serviceInstance = instances.get(0);
        //获取实例对象中的端口号和ip
        //获取端口号
//        serviceInstance.getPort();
        //获取ip地址
//        serviceInstance.getHost();
        //获取端口号和ip
        String s = serviceInstance.getUri().toString();
        Product forObject = restTemplate.getForObject(s+"/product/getById/" + pid, Product.class);
        //获取商品的id
        order.setPid(pid);
        order.setPprice(forObject.getPprice());
        order.setPname(forObject.getPname());
        orderService.saveOrder(order);
        System.out.println("==========购买结束=========");
        return "下单成功";
    }
}

DiscoveryClient是专门负责服务注册和发现的,我们可以通过它获取到注册到注册中心的所有服

务。

6.启动服务, 观察nacos的控制面板中是否有注册上来的订单微服务,然后通过访问消费者服务验证调用是否成功

3.4 实现服务调用的负载均衡

3.4.1 什么是负载均衡 nginx

通俗的讲, 负载均衡就是将负载(工作任务,访问请求)进行分摊到多个操作单元(服务器,组件)上进行执行

根据负载均衡发生位置的不同,一般分为服务端负载均衡客户端负载均衡

服务端负载均衡指的是发生在服务提供者一方,比如常见的nginx负载均衡

而客户端负载均衡指的是发生在服务请求的一方,也就是在发送请求之前已经选好了由哪个实例处理请求

我们在微服务调用关系中一般会选择客户端负载均衡,也就是在服务调用的一方来决定服务由哪个提供者执行

3.4.2 自定义实现负载均衡

2 通过nacos查看微服务的启动情况

3 修改 order-controller 的代码,实现负载均衡 

@RestController
@RequestMapping("order")
@Slf4j
public class OrderController01 {
    @Autowired
    private OrderService orderService;
    //该类默认没有交于spring管理
    @Autowired
    private RestTemplate restTemplate;
 
    //spring中提供了一个工具类,该类可以从注册中心拉取微服务信息。
    @Autowired
    private DiscoveryClient discoveryClient;
 
    @GetMapping("buy/{pid}/{number}")
    public CommonResult buy(@PathVariable Integer pid, @PathVariable Integer number){
        log.info(">>客户下单,这时候要调用商品微服务查询商品信息");
 
        Order order = new Order();
        //用户的信息可以根据token从redis中获取用户信息
        order.setUid(1);
        order.setUsername("YYY");
 
        //根据服务名称获取对应的所有实例对象      这里要与product微服务的名称一致
        List<ServiceInstance> instances = discoveryClient.getInstances("springcloud-wzh-product");
        //获取第一个实例对象
        int index = new Random().nextInt(instances.size());
        ServiceInstance instance = instances.get(index);
        log.info("从nacos获取springcloud-wzh-product服务的ip地址以及端口号{}",instance.getUri());
        
        String path = instance.getUri().toString();
        Product product = restTemplate.getForObject(path + "/product/getById/" + pid, Product.class);
 
        log.info(">>商品信息,查询结果:" + JSON.toJSONString(product));
 
        order.setPid(pid);
        order.setPname(product.getPname());
        order.setPprice(product.getPprice());
        order.setNumber(number);
 
        return orderService.save(order);
    }
}

第3步:启动两个服务提供者和一个服务消费者,多访问几次消费者测试效果 

3.4.3 基于Ribbon实现负载均衡 ---组件

1.什么是Ribbon

Netflix 发布的一个负载均衡器,有助于控制 HTTP TCP客户端行为。在 SpringCloud 中, nacos一般配合Ribbon进行使用,Ribbon提供了客户端负载均衡的功能,Ribbon利用从nacos中读 取到的服务信息,在调用服务节点提供的服务时,会合理(策略)的进行负载 SpringCloud中可以将注册中心和Ribbon配合使用,Ribbon自动的从注册中心中获取服务提供者的 列表信息,并基于内置的负载均衡算法,请求服务。

Netflix 发布的一个负载均衡器,Ribbon自动的从注册中心中获取服务提供者的 列表信息,并基于内置的负载均衡算法,请求服务。

2.Ribbon的主要作用

1)服务调用

基于Ribbon实现服务调用, 是通过拉取到的所有服务列表组成(服务名-请求路径的)映射关系。借助 RestTemplate 最终进行调用

2)负载均衡

当有多个服务提供者时,Ribbon可以根据负载均衡的算法自动的选择需要调用的服务地址

Ribbon是Spring Cloud的一个组件, 它可以让我们使用一个注解就能轻松的搞定负载均衡

1步:在RestTemplate 的生成方法上添加@LoadBalanced注解

@Bean
@LoadBalanced   //策略轮询
public RestTemplate getRestTemplate() { return new RestTemplate(); }

2步:修改服务调用的方法

@RestController
@RequestMapping("order")
@Slf4j
public class OrderController02 {
    @Autowired
    private OrderService orderService;
    //该类默认没有交于spring管理
    @Autowired
    private RestTemplate restTemplate;
 
    @GetMapping("buy/{pid}/{number}")
    public CommonResult buy(@PathVariable Integer pid, @PathVariable Integer number){
        log.info(">>客户下单,这时候要调用商品微服务查询商品信息");
 
        Order order = new Order();
        //用户的信息可以根据token从redis中获取用户信息
        order.setUid(1);
        order.setUsername("赵六");
        //1.在RestTemplate获取方法上@LoadBalanced注解 使用Ribbon完成负载均衡
        //2.修改RestTemplate调用代码 http://服务名称/资源路径
        //restTemplate调用处必须 http://服务提供者的名称/服务提供资源路径
        Product product = restTemplate.getForObject("http://0818-ysh-product/product/getById/" + pid, Product.class);
 
        log.info(">>商品信息,查询结果:" + JSON.toJSONString(product));
 
        order.setPid(pid);
        order.setPname(product.getPname());
        order.setPprice(product.getPprice());
        order.setNumber(number);
 
        return orderService.save(order);
    }
}

Ribbon支持的负载均衡策略  

Ribbon内置了多种负载均衡策略,内部负载均衡的顶级接口为

com.netflix.loadbalancer.IRule , 具体的负载策略如下图所示:

我们可以通过修改配置来调整Ribbon的负载均衡策略,具体代码如下

#指定ribbon负载均衡的策略: springcloud-ysh-product微服务名称.ribbon.NFLoadBalancerRuleClassName=负载均衡策略类
springcloud-ysh-product.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule

思考:上面使用ribbon完成负载均衡有什么缺点:  restTemplate---url地址。

//1.代码可读性较差. 

//2.编码风格不一样. 
习惯的编码风格service 调用dao  service中注入dao,dao对象调用相应的方法

3.5 基于OpenFeign实现服务调用

3.5.1 什么是OpenFeign  

OpenFeignSpring Cloud提供的一个声明式的伪Http客户端, 它使得调用远程服务就像调用本地服务一样简单, 只需要创建一个接口并添加一个注解即可。

Nacos很好的兼容了Feign Feign负载均衡默认集成了 Ribbon, 所以在Nacos下使用Fegin默认就实现了负载均衡的效果。

3.5.2 Feign的使用

1 加入Fegin的依赖

<!--feign的jar文件-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2 在主启动类上加入开启feign的注解

@SpringBootApplication
@EnableDiscoveryClient //开启nacos的注解
@EnableFeignClients //开启feign的注解
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class,args);
    }
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate() { return new RestTemplate(); }
}

3 创建feign的接口

package com.qy151.fengin;

import com.qy151.entity.Product;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

/**
 * @BelongsProject: 0818-ysh-parent
 * @BelongsPackage: com.qy151.fengin
 * @unthor : YSH
 * @date : 2022/8/19 11:28
 */
@FeignClient(value = "ysh-product")
public interface ProductFegin {

    @GetMapping("/product/getById/{pid}")
    public Product getById(@PathVariable Integer pid);
}

4 修改OrderController的代码 

@RestController
@RequestMapping("order")
@Slf4j
public class OrderController03 {
    @Autowired
    private OrderService orderService;
    
    @Autowired
    private ProductFeign productFeign;
 
    @GetMapping("buy/{pid}/{number}")
    public CommonResult buy(@PathVariable Integer pid, @PathVariable Integer number){
        log.info(">>客户下单,这时候要调用商品微服务查询商品信息");
 
        Order order = new Order();
        //用户的信息可以根据token从redis中获取用户信息
        order.setUid(1);
        order.setUsername("赵六");
        log.info("openfeign的代理类生成的类:{}"+productFeign);
        Product product = productFeign.getById(pid);
        //这里直接使用productFeign调用接口中的方法,和我们原来controller调用service一样啊
        log.info(">>商品信息,查询结果:" + JSON.toJSONString(product));
 
        order.setPid(pid);
        order.setPname(product.getPname());
        order.setPprice(product.getPprice());
        order.setNumber(number);
 
        return orderService.save(order);
    }
}

5 重启order微服务,查看效果 

4.使用eureka作为注册中心

4.1什么是eureka?

Eureka是Netflix开发的服务发现框架,SpringCloud将它集成在自己的子项目spring-cloud-netflix中,实现SpringCloud的服务发现功能。

4.2创建eureka

4.2.1.创建一个eureka服务端

4.2.2. 在eureka服务端引入相关的依赖 

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

4.2.3 修改application.properties配置文件

server.port=7000
 
spring.application.name=eureka-server
 
#实例的主机名  所在的主机ip
eureka.instance.hostname=localhost
 
#是否把eureka服务端注册到注册中心
eureka.client.register-with-eureka=false
 
#该服务是否从注册中心拉取服务
eureka.client.fetch-registry=false
 
#提供类微服务的地址
eureka.client.service-url.defaultZone=http://localhost:7000/eureka
 
 

4.2.4. 添加主启动类 

package com.qy151.eureka;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

/**
 * @BelongsProject: 0818-ysh-parent
 * @BelongsPackage: com.qy151.eureka
 * @unthor : YSH
 * @date : 2022/8/19 15:16
 */
@SpringBootApplication
@EnableEurekaServer //开启eureka服务端注解
public class EurekaServerApp {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApp.class,args);
    }
}

4.2.5修改0818-ysh-product和0818-ysh-order客户端配置文件

这里先把之前的nacos依赖注释掉,引入eureka依赖

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

4.2.6修改配置文件

分别修改application.properties配置文件,注释掉nacos的地址,添加eureka的地址

product的配置文件:

# 为了后期扩展方便商品微服务的端口设置为8080~8089之间
server.port=8081
 
#数据源
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springcloud?serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root
 
#sql日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#配置eureka注册中心的地址
eureka.client.service-url.defaultZone=http://localhost:7000/eureka
#配置nacos注册中心的地址
#spring.cloud.nacos.discovery.server-addr=localhost:8848
#指定是否把该服务注册到注册中心
#spring.cloud.nacos.discovery.register-enabled=false
#指定微服务的名称   务必不能用_分隔
spring.application.name=springcloud-ysh-product

order的配置文件:

# 为了后期扩展方便订单微服务的端口设置为8090~8099之间
server.port=8091
 
#数据源
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springcloud?serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
 
#sql日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
 
#配置eureka注册中心的地址
eureka.client.service-url.defaultZone=http://localhost:7000/eureka
#配置nacos注册中心的地址
#spring.cloud.nacos.discovery.server-addr=localhost:8848
#指定是否把该服务注册到注册中心
#spring.cloud.nacos.discovery.register-enabled=false
#指定微服务的名称   务必不能用_分隔
spring.application.name=springcloud-ysh-order
 
#指定ribbon负载均衡的策略: springcloud-wzh-product微服务名称.ribbon.NFLoadBalancerRuleClassName=负载均衡策略类
springcloud-ysh-product.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule

4.2.7. 重新启动所有微服务,测试是否正常使用 

5.nacos集群

  在实际开发过程中,如果使用Nacos的话,为了确保高可用,我们一般都会对其进行集群的部署。Nacos规定集群中Nacos节点的数量需要大于等于3个;同时,单机模式下Nacos的数据默认保存在其内嵌数据库中deby,不方便观察数据存储的基本情况。而且如果集群中启动多个默认配置下的Nacos节点,数据存储是存在一致性问题的。为了解决这个问题,Nacos采用了集中式存储的方式来支持集群化部署,目前只支持MySQL的存储;此外,我们还需要借助Nginx实现负载均衡。这一过程的部署架构图如下所示:

1.准备三个nacos服务器---为了操作方便统一部署到同一台电脑 【8849.8850.8851】

2.准备mysql---创建一个nacos-config--创建相应的表 

5.1创建数据库

5.1.1复制sql到nacos_mysql数据库中,完成创建表

5.1.2指定使用mysql作为数据存储

修改nacos8860\nacos-server-2.0.3\nacos\conf的application.properties配置文件

5.1.3配置集群文件 

修改nacos8849\nacos-server-2.0.3\nacos\conf下的 cluster.conf.example文件,并把后缀名去掉

5.1.4停止nacos并复制三份

不要忘记修改每一份的端口号

5.1.5启动三个nacos服务

如果某一个启动失败请参考
Nacos2.0.1数据持久化和伪集群学习--集群启动报错问题(Error creating bean with name ‘grpcSdkServer‘)_hy_luckyyang的博客-CSDN博客
如果全部启动失败请参考
nacos连接数据库,数据库必须要设置远程连接
 

nacos集群全部启动失败报 Failed to obtain JDBC Connection; nested exception is java.sql.SQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times. Giving up.

打开navicat连接数据库再启动nacos集群即可
访问其中一个nacos服务器查看是否搭建成功

5.1.6搭建nginx代理上面三个nacos服务

我这里为了方便都在window下操作。

1.修改conf目录下的nginx.conf配置文件

2.启动nginx

任务管理器可以查看是否开启成功 

3. 访问http://localhost:81/nacos查看是否代理成功 

5.1.7微服务注册到nacos集群上

1.修改微服务中的application.properties配置文件,把nacos注册中心的地址改为nginx所在ip和端口

 

2.重启微服务项目,查看是否成功

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐