Skip to content

一:微服务架构

1.0:单体架构

将项目所有模块(功能)打成jar或者war,然后部署一个进程

image-20220606223149903

txt
优点:
1:部署简单: 由于是完整的结构体,可以直接部署在一个服务器上即可。
2:技术单一: 项目不需要复杂的技术栈,往往一套熟悉的技术栈就可以完成开发。
3:用人成本低: 单个程序员可以完成业务接口到数据库的整个流程。

缺点:
1:系统启动慢, 一个进程包含了所有的业务逻辑,涉及到的启动模块过多,导致系统的启动、重启时间周期过长;
2:系统错误隔离性差、可用性差,任何一个模块的错误均可能造成整个系统的宕机;
3:可伸缩性差:系统的扩容只能只对这个应用进行扩容,无法结合业务模块的特点进行伸缩。
4:线上问题修复周期长:任何一个线上问题修复需要对整个应用系统进行全面升级。
5. 跨语言程度差
6. 不利于安全管理,所有开发人员都拥有全量代码

1.1:微服务架构

微服务架构论文:https://martinfowler.com/articles/microservices.html

译文:https://mp.weixin.qq.com/s?__biz=MjM5MjEwNTEzOQ==&mid=401500724&idx=1&sn=4e42fa2ffcd5732ae044fe6a387a1cc3#rd

txt
In short, the microservice architectural style [1] is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms( 美 ['mekə,nɪzəm]  机制), often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies.

简而言之,微服务架构风格[1]这种开发方法,是以开发一组小型服务的方式来开发一个独立的应用系统的。其中每个小型服务都运行在自己的进程中,并经常采用HTTP资源API这样轻量的机制来相互通信。这些服务围绕业务功能进行构建,并能通过全自动的部署机制来进行独立部署。这些微服务可以使用不同的语言来编写,并且可以使用不同的数据存储技术。对这些微服务我们仅做最低限度的集中管理。

解读微服务特点:

1:微服务是一种项目架构思想(风格)

2:微服务架构是一系列小服务的组合(组件化与多服务)

3:任何一个微服务,都是一个独立的进程(独立开发、独立维护、独立部署)

4:轻量级通信http协议(跨语言,跨平台)

5:服务粒度(围绕业务功能拆分)

6:去中心化管理(去中心化”地治理技术、去中心化地管理数据)

1.2:微服务架构的优势

1.易于开发和维护 一个微服务只关注一个特定的业务功能,所以它的业务清晰、代码量较少。开发和维护单个微服务相对比较简单,整个应用是由若干个微服务构建而成,所以整个应用也会维持在可控状态;

2.单个微服务启动较快 单个微服务代码量较少,所以启动会比较快;

3.局部修改容易部署 单体应用只要有修改,就要重新部署整个应用,微服务解决了这样的问题。一般来说,对某个微服务进行修改,只需要重新部署这个服务即可;

4.技术栈不受限 在微服务中,我们可以结合项目业务及团队的特点,合理地选择技术栈

5.按需伸缩

1.3:微服务架构的缺点(挑战)

1、服务太多,导致服务间的依赖错综复杂,运维难度大

2、微服务放大了分布式架构的系列问题

  • 分布式事务(seata)、
  • 分布式锁怎么处理(redisson),
  • 服务注册与发现(nacos)、
  • 依赖服务不稳定(sentinel)导致服务雪崩怎么办?

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

1.4:SpringCloud与微服务关系

  • Springcloud为微服务思想提供了完美的解决方案

  • Springcloud是一些列框架的集合体(服务的注册与发现【注册中心】、服务间远程调用、服务降级、服务熔断、服务限流、分布式事务 等)

    txt
    一般我们说springcloud 其实指的是Springcloud-netflix,Springcloud并不是造轮子,只是把Netflix公司的组件做二次开发

1.5:SpringBoot和SpringCloud关系

  • SpringBoot专注于快速方便的开发单个个体微服务。

  • SpringCloud是关注全局的微服务协调、整理、治理的框架,它将SpringBoot开发的单体整合并管理起来。

  • SpringBoot可以离开SpringCloud独立使用开发项目,但是SpringCloud离不开SpringBoot,属于依赖关系。

二:服务注册与发现

2.1:服务注册与发现

服务注册,就是将提供某个服务的模块信息(通常是这个服务的ip和端口)注册到1个公共的组件上去(比如: zookeeper\consul\eureka\nacos)。

服务发现,就是新注册的这个服务模块能够及时的被其他调用者发现。不管是服务新增和服务删减都能实现自动发现。

2.2:注册中心对比

nacos:是阿里开源的,经过了阿里实践的

eureka:netflix公司的,现在不维护了,不开源了

Consul : HashiCorp 公司推出的开源产品,用于实现分布式系统的服务发现、服务隔离、服务配置

对比组件NacosEurekaConsulZookeeper
一致性对比支持AP和CP模型AP模型CP模型CP模型
健康检查tcp/http/client Beatclient BeatTCP/HTTP/gRPCkeep Alive
负载均衡策略RibbonRibbonFabio-
雪崩保护
自动注销实例支持支持不支持支持
访问协议HTTPHTTPHTTPTCP
监听支持支持支持支持支持
多数据中心支持支持支持不支持
跨注册中心同步支持不支持支持不支持
Springcloud集成支持支持支持不支持
Dubbo集成支持不支持不支持支持
K8s集成支持不支持支持不支持

三:nacos简介与安装

官网:https://nacos.io/zh-cn/docs/what-is-nacos.html

3.1:nacos功能与架构

nacos架构:

image-20220606223404981

nacos功能:

  • 名字服务 (Naming Service)

    txt
    命名服务是指通过指定的名字来获取资源或者服务的地址,提供者的信息

  • 配置服务 (Configuration Service)

    txt
    动态配置服务让您能够以中心化、外部化和动态化的方式管理所有环境的配置。动态配置消除了配置变更时重新部署应用和服务的需要。配置中心化管理让实现无状态服务更简单,也让按需弹性扩展服务更容易。

3.2:nacos安装

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

1:解压安装

2:配置

image-20220606224011455

3:创建数据库以及表(conf>nacos-mysql.sql)

4:配置startup.cmd,以standalone方式启动

image-20220606224034492

5:启动

3.3:nacos注册中心工作流程

image-20220606224056261

四:微服务入门案例

4.1:boot与cloud版本

txt
springboot:提供了快速开发微服务的能力
springcloud提供了微服务治理的能力(服务注册与发现、服务降级、限流、熔断、网关、负载均衡、配置中心...),为微服务开发提供了全家桶服务

springboot的版本查看地址:https://spring.io/projects/spring-boot#learn

springcloud的版本查看地址:https://spring.io/projects/spring-cloud#overview

详细版本对应信息查看:https://start.spring.io/actuator/info

image-20220606224453219

shell
注意:
如果采用springboot和springcloud(springcloud netflix)那么使用以上版本对应就ok了,
但是如果要使用alibaba的组件(nacos、sentinel、RocketMQ、Seata)必须使用springcloud alibaba

4.2:SpringCloud-alibaba

Springcloud与springcloud-alibaba关系

txt
◆ 我们通常说的SpringCloud,泛指Spring Cloud Netflix,也是springcloud第一代
◆ SpringCloud Alibaba是SpringCloud的子项目,是阿里巴巴结合自身微服务实践,
◆ SpringCloud Alibaba符合SpringCloud标准,依赖于springcloud

image-20220606224657875

4.3:确定版本

确定方式:通过查看springcloud alibaba 官网确定

https://github.com/alibaba/spring-cloud-alibaba/wiki/版本说明

Spring Cloud VersionSpring Cloud Alibaba VersionSpring Boot Version
Spring Cloud Hoxton.SR82.2.4.RELEASE2.3.2.RELEASE
Spring Cloud Greenwich.SR62.1.3.RELEASE2.1.13.RELEASE
Spring Cloud Hoxton.SR32.2.1.RELEASE2.2.5.RELEASE
Spring Cloud Hoxton.RELEASE2.2.0.RELEASE2.2.X.RELEASE
Spring Cloud Greenwich2.1.2.RELEASE2.1.X.RELEASE
Spring Cloud Finchley2.0.3.RELEASE2.0.X.RELEASE
Spring Cloud Edgware1.5.1.RELEASE(停止维护,建议升级)1.5.X.RELEASE

最终决定(版本号记忆):

springcloud-alibaba: 2.2.5.RELEASE

springcloud: Hoxton.SR8

springboot: 2.3.2.RELEASE

4.4:创建父工程

父工程锁定springboot、springcloud、springcloud-alibaba版本

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

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>2.2.5.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Hoxton.SR8</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

    </dependencies>
</dependencyManagement>

nacos学习文档:https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-docs/src/main/asciidoc-zh/nacos-discovery.adoc

4.5.1:pom.xml

xml
    <dependencies>
<!--    web的场景依赖    -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
<!--     端点监控的场景依赖   -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
<!--     nacos场景依赖   -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

    </dependencies>

4.5.2:application.yml

properties
spring:
  application:
    name: cloud-search   #服务名称 唯一
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        namespace: java2110
server:
  port: 9081

4.5.3:启动类加注解

java
package com.qf.search;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;


@SpringBootApplication
@EnableDiscoveryClient
public class SearchApp {
    public static void main(String[] args) {

        SpringApplication.run(SearchApp.class,args);
    }
}

补充内容: actuator 端点监控 或者 健康监控 sb 提供的一种 通过接口对外暴露信息的机制

yml
management:
  endpoint:    # 单个端口的 启用  或者 关闭 
    shutdown:    #  默认  没有启动 
      enabled: true      # 启用端口
#    info:
#      enabled: false    # info 端口  默认就是启用
#    logfile:
#      enabled: true
#    heapdump:
#      enabled: true


  endpoints:
    #enabled-by-default: true    # 启用所有端口
    web:
      exposure:
        include: "*"    # 暴露所有端口     可以通过 下方的 请求  查看到 暴露的端口信息
        exclude: info,health   # 不暴露的 端口    排除这些端口

通过访问 :http://localhost:9081/actuator 查看暴露的端口信息

当配置暴露所有web 端口

java
management:
  endpoints:
    web:
      exposure:
        include: "*"

image-20230614164731992

4.5.4:查询商品接口

java
@RestController
@RequestMapping("/search")
public class SearchController {

    @RequestMapping("/test")
    public String testSearch(String name,@RequestHeader("Foo") String foo){
        System.out.println(name);
        System.out.println(foo+"!!!!");
        return "search";
    }
}

4.5.5: 公共依赖模块 01-cloud-common

依赖

shell
<?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>cloud-parent</artifactId>
        <groupId>com.qf.java2110</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>01-cloud-common</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <!-- 健康检查的场景依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

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

实体类

java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Goods {

    private Integer id;

    private String goodsName;

    private Double price;
}
java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {

    private  Integer orderId;

    private Integer userId;

    private Date orderDate;

    private Integer productId;

    private Integer productNum;
}

4.6:服务消费者 02-cloud-customer

4.6.1:pom.xml

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>cloud-parent</artifactId>
        <groupId>com.qf.java2110</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>02-cloud-customer</artifactId>

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

        <dependencies>
            <dependency>
                <groupId>com.qf.java2110</groupId>
                <artifactId>01-cloud-common</artifactId>
                <version>1.0-SNAPSHOT</version>
            </dependency>
            <!--  web的场景依赖      -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>

            <!-- nacos服务注册与发现的场景依赖-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            </dependency>
        </dependencies>
</project>

4.6.2:application.yml

properties
spring:
  application:
    name: cloud-customer  #服务的应用名称
  cloud:
    nacos:
      discovery: #nacos配置
        server-addr: localhost:8848

server:
  port: 8081

4.6.3:启动类加注解

java
package com.qf.customer;

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

@SpringBootApplication
public class CustomerApp {
    public static void main(String[] args) {
        SpringApplication.run(CustomerApp.class,args);
    }

    @Bean
    //让ribbon拦截RestTemplate发出的所有的请求
    //ribbon获取url中的service name
    //从nacos注册中心获取实例列表
    //负责从实例列表中通过相应的负载均衡算法,获取一个实例
    //RestTemplate请求实例
    //@LoadBalanced      这个注解打开   就会依据 服务名 进行负载均衡
    public RestTemplate initRestTemplate(){
        return new RestTemplate();
    }
}

4.6.4:保存订单接口

java
package com.qf.customer.controller;

import com.qf.common.entity.Goods;
import com.qf.customer.feign.SearchApi;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName : CustomerController
 * @Author : glls
 * @Date: 2021/12/20 10:28
 * @Description :
 */
@RestController
@RequestMapping("/customer")
public class CustomerController {
    
    @Autowired
    private RestTemplate restTemplate;



    @RequestMapping("/test")
    public String testCustomer(){
        //案例1
        //String url="http://localhost:9081/search/test?name={1}";    //硬编码 写死了  实际开发不这样做
        //ResponseEntity<String> forEntity = restTemplate.getForEntity(url, String.class,"zs");


        //案例2
        //String url="http://localhost:9081/search/test?name={name}";    //硬编码 写死了  实际开发不这样做
        //Map<String, String> map = new HashMap<>();
        //map.put("name", "李四");
        //ResponseEntity<String> forEntity = restTemplate.getForEntity(url, String.class,map);
        //
        //案例3
        //String url="http://localhost:9081/search/test2";    //硬编码 写死了  实际开发不这样做
        //Map<String, String> map = new HashMap<>();
        //map.put("name", "李四");
        ////参数1 请求地址
        ////参数2 携带的数据  会被转为json ,所以  被调用的接口 需要使用 @RequestBody注解
        ////参数3  被调用的接口的返回值类型
        //ResponseEntity<String> forEntity = restTemplate.postForEntity(url, new Goods("huawei", 99.9),String.class);



        //案例4
        String url="http://cloud-search/search/test2";    //硬编码 写死了  实际开发不这样做

        //参数1 请求地址
        //参数2 携带的数据  会被转为json ,所以  被调用的接口 需要使用 @RequestBody注解
        //参数3  被调用的接口的返回值类型
        ResponseEntity<String> forEntity = restTemplate.postForEntity(url, new Goods(1,"huawei", 99.9),String.class);


        return "customer:"+forEntity.getBody();
    }


}

4.7:微服务集群演示

properties
#如果不指定端口,那么微服务启动时使用9081,如果指定端口,那么微服务就在指定端口启动
-Dserver.port=9082

image-20220607224535714

4.8:nacos领域模型

txt
nacos的服务由三元组唯一确定   (namespace、group、servicename)
nacos的配置由三元组唯一确定     (namespace、group、dataId)

不同的namespace是相互隔离的,相同namespace但是不同的group也是相互隔离的

默认的namespace是public ,不能删除
默认的group是DEFAULT-GROUP

1:创建namespace

image-20210817102910080

2:发布服务到指定的namespace

image-20210817103155453

五:RestTemplate

实现服务间远程调用

5.1:RestTemplate简介

txt
1:RestTemplate是java模拟浏览器发送http请求的工具类
2:RestTemplate基于`Apache`的`HttpClient`实现。HttpClient使用起来太过繁琐。spring提供了一种简单便捷的模板类来进行操作,这就是`RestTemplate`。

Openfeign

5.2:ForObject

返回的是响应结果

get请求

java
Map goods = restTemplate.getForObject(BaseURL+"findGoodsById?goodsId=12", Map.class);
System.out.println(goods.get("goodsName"));

post请求(发送的是json串)

java
Map goods = restTemplate.postForObject(BaseURL + "/save", new Goods("huawei", 99.99), Map.class);
System.out.println(goods.get("code"));

提示:

xml
1:微服务之间数据传输格式统一为json
2:entity的空构造方法要提供
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Goods  {

      private String goodsName;
      private double price;

}

5.3:ForEntity

返回的是响应体

get请求

java
ResponseEntity<Goods> forEntity = restTemplate.getForEntity(BaseURL + "findGoodsById?goodsId=12", Goods.class);

System.out.println("http status:"+forEntity.getStatusCode());
System.out.println("http response body:"+forEntity.getBody());

post请求

java
ResponseEntity<Map> responseEntity = restTemplate.postForEntity(BaseURL + "/save", new Goods("huawei", 99.99), Map.class);

System.out.println("http status:"+responseEntity.getStatusCode());
System.out.println("http response body:"+responseEntity.getBody());

六:负载均衡器Ribbon

txt
nacos:注册中心,解决服务的注册与发现
Ribbon:客户端的负载均衡器,解决的是服务实例列表的负载均衡的问题

6.1:Ribbon简介

txt
Ribbon是Netflix公司开源的一个负载均衡的项目,是一个"客户端"负载均衡器,运行在客户端上

6.2:Ribbon在项目中怎么使用

第一步:pom依赖

springcloud alibaba 对Ribbon做了兼容

image-20201018110223408

第二步:@LoadBalanced注解

java
@Bean
@LoadBalanced
public RestTemplate restTemplate(){

    return new RestTemplate();
}

6.3:Ribbon的工作流程

结合restTemplate 实现负载均衡 ribbon 是通过一个 拦截器 对服务发出的请求 进行拦截 获取到请求路径上的服务名

根据服务名 去nacos 获取服务的实例列表,再根据 IRule 负载均衡策略 选择一个具体的服务进行访问

6.4:Ribbon源码追踪

image-20210817135810619

LoadBalancerInterceptor

image-20210817135834178

RibbonLoadBalancerClient

image-20210817140127081

负载均衡

image-20210817140537724

txt
Ribbon核心组件IRule:根据特定算法从服务列表中选取一个需要访问的服务;
其中IRule是一个接口,有七个自带的落地实现类,可以实现不同的负载均衡算法规则:

image-20210716160640128

6.5:切换Ribbon负载均衡策略

image-20210817142501714

image-20210817142523916

6.6:服务实例列表同步更新

DynamicServerListLoadBalancer.updateListOfServers
//从nacos server获取最新的实例列表
NacosServerList.getServers

问题:服务消费者一旦成功调用一次,nacos server关闭后还能继续访问?

七:nacos集群搭建

7.1:nacos集群架构

image-20210817150519355

7.2:nacos集群搭建

伪集群:一台服务器搭建3台nacos 通过端口进行区分

7.2.1:集群规划

服务名ip端口备注
nacos实例1192.168.25.1018848
nacos实例2192.168.25.1018858
nacos实例3192.168.25.1018868
nginx192.168.25.10180反向代理nacos3个实例
mysql192.168.25.1013306存储nacos数据

7.2.2:详细步骤

第一步:上传nacos包到linux服务器并解压

shell
tar -zxvf nacos-server-1.4.1.tar.gz -C /export/server/

第二步:修改nacos数据源

shell
cd /export/server/nacos/conf/
vim application.properties

image-20210202093842513

创建数据库及表

第三步:修改/export/server/nacos/bin/startup.sh 的JAVA_OPT

image-20210719092644814

虚拟机内存调大到2G

sh
原设置:
JAVA_OPT="${JAVA_OPT} -server -Xms2g -Xmx2g -Xmn1g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
修改后:
JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx256m -Xmn128m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=160m"

第四步:配置/export/server/nacos/conf/cluster.conf配置文件

修改集群配置文件的文件名

cp cluster.conf.example cluster.conf

properties
192.168.25.101:8848
192.168.25.101:8858
192.168.25.101:8868

第五步:复制三份,同时修改监听端口

shell
[root@zhuxm01 server]# cp nacos/   nacos8848 -r
[root@zhuxm01 server]# cp nacos/   nacos8858 -r
[root@zhuxm01 server]# cp nacos/   nacos8868 -r

第六步:分别启动nacos实例

创建nacos-cluster-startup.sh

shell
sh /export/server/nacos8848/bin/startup.sh
sh /export/server/nacos8858/bin/startup.sh
sh /export/server/nacos8868/bin/startup.sh

第七步:测试

shell
spring.cloud.nacos.discovery.server-addr=192.168.234.122:8848,192.168.234.122:8858,192.168.234.122:8868

第八步:配置nginx反向代理(可选)

json
upstream  nacos-cluster {
       server    192.168.25.101:8848;
       server    192.168.25.101:8858;
       server    192.168.25.101:8868;
     }

server {
        listen       80;
        server_name  www.nacos.com;
        #charset koi8-r;
        #access_log  logs/host.access.log  main;
        location / {
           proxy_pass http://nacos-cluster/;
        }
}

八 Springcloud openfeign

介绍:作为Spring Cloud的子项目之一,Spring Cloud OpenFeign 是一种声明式、模板化的 HTTP 客户端,在 Spring Cloud 中使用 OpenFeign,可以做到使用 HTTP请求远程服务时能与调用本地方法一样的编码体验,开发者完全感知不到这是远程方法,更感知不到这是个 HTTP 请求。同时OpenFeign通过集成Ribbon实现客户端的负载均衡

nacos-server : 注册中心,解决是服务的注册与发现

Ribbon:客户端负载均衡器,解决的是服务集群负载均衡的问题

OpenFeign:声明式 HTTP 客户端 、代替Resttemplate组件,实现远程调用

8.1 快速入门

第一步:添加依赖

shell
        <!--添加远程调用组件  openfeign 的依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

第二步: 在启动开启 feign ,并扫描 feign接口的包

java
@EnableFeignClients(basePackages = {"com.qf.customer.feign"})

image-20220830095434364

第三步:创建feign接口

java
@FeignClient(value = "cloud-search")        // 指定远程调用的服务是谁
//@RequestMapping("/search")
public interface SearchApi {

	// 注意 这些方法的定义方式
    @PostMapping("/search/save")
    public Map save(@RequestBody Goods goods);

}

第四步:消费者 调用 feign 接口

java
    @Autowired
    private SearchApi searchApi;    // 注入 feign 接口  像调用本地接口一样 进行调用

    @RequestMapping("/save")
    public R save(){
        //feign接口远程调用其他服务
        Map save = searchApi.save(new Goods(1L,"手机",88.8));

        return R.ok().data(save);
    }

第五步 提前准备好的远程接口 cloud-search 服务

java
@PostMapping("/save")
    public Map save(@RequestBody Goods goods){

        System.out.println("调用了搜素服务的保存接口");
        System.out.println(goods);
        return new HashMap(){{
            put("isSuccess",true);
            put("msg","save success");
        }};
    }

    @PostMapping(value = "/update")
    public Map update(@RequestBody Goods goods) {

        System.out.println(goods);
        return new HashMap(){{
            put("isSuccess",true);
            put("msg","update success");
        }};

    }



    @GetMapping(value = "/delete")
    public Map deleteById(@RequestParam(value = "id") Long id) {
        System.out.println("删除id为"+id+"的积分信息");
        return new HashMap(){{
            put("isSuccess",true);
            put("msg","delete success");
        }};

    }

    @GetMapping(value = "/{id}")
    public Goods findJifenById(@PathVariable(value = "id") Long id) {
        System.out.println("已经查询到"+id+"积分数据");
        return new Goods(1L, "笔记本电脑",66.66);
    }


    @GetMapping(value = "/search")
    public Goods search(Long id,String name) {
        System.out.println("uid:"+id+"type:"+name);
        return new Goods(id, name,66.66);
    }


    @PostMapping(value = "/searchByEntity")
    public R searchMap(@RequestBody  Goods goods) {

        System.out.println(goods);

        List<Goods> goodsList = new ArrayList<>();
        goodsList.add(new Goods(110L,"手机",88.8));
        goodsList.add(new Goods(111L,"电脑",66.6));
        return  R.ok();
    }

8.2 feign 返回托底数据

Fallback可以帮助我们在使用Feign去调用另外一个服务时,如果出现了问题,走服务降级,返回一个错误数据,避免功能因为一个服务出现问题,全部失效。

比如 现在 customer 调用search ,search 出问题了 ,为了不影响 customer ,可以 在 customer 中 进行 服务降级 操作

4.4.1 FallBack方式

在 customer 下 创建 fallback 包 ,包下创建一个POJO类,实现Client接口。

java
@Component
public class SearchClientFallBack implements SearchClient {
    @Override
    public String search() {
        return "出现问题啦!!!";
    }

    @Override
    public Customer findById(Integer id) {
        return null;
    }

    @Override
    public Customer getCustomer(Integer id, String name) {
        return null;
    }

    @Override
    public Customer save(Customer customer) {
        return null;
    }
}

修改CLient接口中的注解,添加一个属性。

@FeignClient(value = "SEARCH",fallback = SearchClientFallBack.class)

添加一个配置文件。

yml
# feign和hystrix组件整合
feign:
  hystrix:
    enabled: true
    
    
#  然后  使用customer 通过 feign 接口  调用  search ,让search 出异常 ,  开始测试
# 调用 search 这个 方法   ,发现  返回的 是 SearchClientFallBack   中的 方法  返回值
 @GetMapping("/search")
    public String search(){
        int i = 5/0;
        return "search"+port;
    }

8.3 feign的常用配置

java
# feign和hystrix组件整合
feign:
  hystrix:
    enabled: true
  client:
    config:
      cloud-search:
        connectTimeout: 1000
        readTimeout: 2000
      default:
        connectTimeout: 1000
        readTimeout: 3000
// 当 开启 在  feign 中 使用 hystrix  时   下面的超时配置  优先级较高
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000

九 配置中心

1.概念介绍

​ 配置文件集中管理 即时生效

nacos的领域模型

image-20230610150004163

2.添加依赖

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

3.创建bootstrap.yml

yml
spring:
  application:
    name: cloud-customer
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848    # 配置中心的地址
        namespace: java2110    #命名空间
        file-extension: yml    #文件扩展名

4.在配置中心 创建远程的配置文件

要明确 配置文件的 namespace group 以及 dataId ,这三个值 是从上面的 bootstrap.yml 得到的,

上面只指定了namespace 所以 group 和 dataId就使用默认值,group的默认值是 DEFAULT_GROUP,dataId的默认值是

是通过公式来拼接prefix{spring.profiles.active}.$

yml
spring:
  application:
    name: cloud-customer      # ${prefix}
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848    # 配置中心的地址
        namespace: java2110    #命名空间
        file-extension: yml    #文件扩展名       ${file-extension}

咱们没有在 这里设置 spring.profiles.active 所以 最终得到的 领域模型: namespace:java2110 group:DEFAULT_GROUP dataId:cloud-customer.yml

image-20211221170227561

5.测试

在远程配置文件 编写配置 ,在controller 中证明读取了这个配置

image-20211221170405424
java
    @Value("${user.name}")
    private String name;

    @RequestMapping("/config")
    public String testConfig(){

        return name;
    }

然后 发现 在远程更改配置后,服务没有感知到 ,需要在 controller 上添加 @RefreshScope

6.在配置中心 添加更多的配置文件

yml
spring:
  application:
    name: cloud-customer
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
        namespace: java2110
        file-extension: yml
        extension-configs[0]:
          group: common
          data-id: common.yml
          refresh: true

image-20211221173057092