Internet_worm
Internet_worm的博客

导航

 

SpringCloud

微服务架构的核心问题:

1.服务很多,客户端该怎么访问?

2.这么多服务,服务之间如何通信?

3.这么多服务,如何管理?

4.服务宕机怎么处理?

解决方案

1.Spring cloud Netflix 一站式解决方案

核心 api 网关 zuul组建

2.Apache Dubbo Zookeeper 半自动,需要整合

3.Spring Cloud Alibaba 一站式解决方案

image
image
image
image

Springcloud 与 springboot的版本对应关系查询:

1.进入https://docs.spring.io/spring-cloud/docs

image

2.点击选择的springcloud版本,进入reference/html目录即可看到对应关系

image

常见对应关系

image

Eureka 服务注册与发现

EurekaServer 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>springcloud-learn</artifactId>
        <groupId>org.rf</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-eureka-7001</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>
    </dependencies>
</project>

EurekaServer application.yml

server:
  port: 7001

#Eureka 配置
eureka:
  instance:
    hostname: localhost #Eureka 服务端实例的名字
  client:
    registerWithEureka: false #是否向Eureka注册中心注册自己,服务器本身不需要注册自己
    fetchRegistry: false #如果未false,则表示自己为注册中心
    serviceUrl: #监控页面
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
#  server:
#    enableSelfPreservation: false #关闭Eureka的自我保护机制

EurekaServer 启动类

@SpringBootApplication
@EnableEurekaServer// EnableEurekaServer 注解表示这是一个服务启动类,允许其他服务发现
public class EurekaServer_7001 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServer_7001.class,args);
    }
}

ServerProvider (服务提供者)

ServerProvider 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>springcloud-learn</artifactId>
        <groupId>org.rf</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-provider-dept-8001</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.rf</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>
        <!--热部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <!-- 加入 Eureka ,向Eureka注册中心注册provider服务  -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>
        <!-- 完善监控信息 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>
</project>

ServerProvider application.yml

server:
  port: 8001
mybatis:
  typeAliasesPackage: org.rf.springcloud.pojo
  configLocation: classpath:mybatis/mybatis-config.xml
  mapperLocations: classpath:mybatis/mapper/*.xml

spring:
  application:
    name: springcloud-provider-dept
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
    username: root
    password: 123456
#Eureka配置,注册服务
eureka:
  host:
    name: localhost
    port: 7001
  client:
    serviceUrl:
      defaultZone: http://${eureka.host.name}:${eureka.host.port}/eureka/
  instance:
    instanceId: springcloud-provider-dept-8001 #修改默认描述
#info 信息配置
info:
  app.name: springcloud-部门提供者服务
  company.name: www.rf.com

ServerProvider 启动类

@SpringBootApplication
@EnableEurekaClient //Eureka客户端,在服务启动后自动注册到Eureka中!
public class DeptProvider {
    public static void main(String[] args) {
        SpringApplication.run(DeptProvider.class,args);
    }
}

Eureka集群

Eureka集群其实就是让多个EurekaServer之间相互认识,搭建EurekaServer集群的操作其实也很简单,只需要让每一个EurekaServer关注另外两个EurekaServer,并将需要发布的服务同时发布到集群中的每一个服务即可

image

集群配置

EurekaServe1 关注EurkaServer2和EurekaServer3

server:
  port: 7001

#Eureka 配置
eureka:
  instance:
    hostname: eureka-test-7001.com #Eureka 服务端实例的名字
  client:
    registerWithEureka: false #是否向Eureka注册中心注册自己,服务器本身不需要注册自己
    fetchRegistry: false #如果未false,则表示自己为注册中心
    serviceUrl: #监控页面
      defaultZone: http://eureka-test-7002.com:7002/eureka/,http://eureka-test-7003.com:7003/eureka/
#  server:
#    enableSelfPreservation: false #关闭Eureka的自我保护机制

EurkaServer2关注EurkeServer1和EurkeServer3

server:
  port: 7002

#Eureka 配置
eureka:
  instance:
    hostname: eureka-test-7002.com #Eureka 服务端实例的名字
  client:
    registerWithEureka: false #是否向Eureka注册中心注册自己,服务器本身不需要注册自己
    fetchRegistry: false #如果未false,则表示自己为注册中心
    serviceUrl: #监控页面
      defaultZone: http://eureka-test-7001.com:7001/eureka/,http://eureka-test-7003.com:7003/eureka/
#  server:
#    enableSelfPreservation: false #关闭Eureka的自我保护机制

EurkeServer3 关注EurkeServer1和EurkeServer2

server:
  port: 7003

#Eureka 配置
eureka:
  instance:
    hostname: eureka-test-7003.com #Eureka 服务端实例的名字
  client:
    registerWithEureka: false #是否向Eureka注册中心注册自己,服务器本身不需要注册自己
    fetchRegistry: false #如果未false,则表示自己为注册中心
    serviceUrl: #监控页面
      defaultZone: http://eureka-test-7002.com:7002/eureka/,http://eureka-test-7001.com:7001/eureka/
#  server:
#    enableSelfPreservation: false #关闭Eureka的自我保护机制

将服务发布到每一个EurekaServer

server:
  port: 8001
mybatis:
  typeAliasesPackage: org.rf.springcloud.pojo
  configLocation: classpath:mybatis/mybatis-config.xml
  mapperLocations: classpath:mybatis/mapper/*.xml

spring:
  application:
    name: springcloud-provider-dept
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
    username: root
    password: 123456
#Eureka配置,注册服务
eureka:
  host:
    name: localhost
    port: 7001
  client:
    serviceUrl:
      defaultZone: http://eureka-test-7001.com:7001/eureka/,http://eureka-test-7002.com:7002/eureka/,http://eureka-test-7003.com:7003/eureka/
  instance:
    instanceId: springcloud-provider-dept-8001 #修改默认描述
#info 信息配置
info:
  app.name: springcloud-部门提供者服务
  company.name: www.rf.com

集群效果图如下

image

image

image

Eureka与Zookeeper

CAP原则

	CAP原则又称CAP定理,指的是在一个分布式系统中,[一致性](https://baike.baidu.com/item/一致性/9840083?fromModule=lemma_inlink)(Consistency)、[可用性](https://baike.baidu.com/item/可用性/109628?fromModule=lemma_inlink)(Availability)、[分区容错性](https://baike.baidu.com/item/分区容错性/23734073?fromModule=lemma_inlink)(Partition tolerance)。CAP 原则指的是,这三个[要素](https://baike.baidu.com/item/要素/5261200?fromModule=lemma_inlink)最多只能同时实现两点,不可能三者兼顾。

​ 维基百科中对于CAP理论的定义:

​ Consistency : Every read receives the most recent write or an err

​ Availability : Every request receives a (non-error) response -without the guarantee that it contains the most recent write

​ Partition tolerance :The system continues to operate despite an arbitrary number of messages being dropped (or delayed) by the network between nodes

​ 翻译:

一致性:对于客户端的每次读操作,要么读到的是最新的数据,要么读取失败。换句话说,一致性是站在分布式系统的角度,对访问本系统的客户端的一种承诺:要么我给您返回一个错误,要么我给你返回绝对一致的最新数据,不难看出,其强调的是数据正确。

可用性:任何客户端的请求都能得到响应数据,不会出现响应错误。换句话说,可用性是站在分布式系统的角度,对访问本系统的客户的另一种承诺:我一定会给您返回数据,不会给你返回错误,但不保证数据最新,强调的是不出错。

分区容忍性:由于分布式系统通过网络进行通信,网络是不可靠的。当任意数量的消息丢失或延迟到达时,系统仍会继续提供服务,不会挂掉。换句话说,分区容忍性是站在分布式系统的角度,对访问本系统的客户端的再一种承诺:我会一直运行,不管我的内部出现何种数据同步问题,强调的是不挂掉。

​ P(分区容忍)特性是分布式系统必须满足的一个特性,因此只能在A和C之间进行权衡,Zookeeper保证的是CP,而Eureka保证的是AP

Zookeeper保证CP

​ 当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但是不能接受服务器直接down掉不可用。也就是说服务注册功能对可用性的要求高于一致性,但是Zookeeper会出现这样的一些情况,当master节点因为网络故障与其他节点失去联系,剩余节点会重新进行leader选举,但是问题在于选举leader的时间太长,大约在30~120秒之间,而且在整个选举期间整个Zookeeper是不可用的,导致选举期间注册服务瘫痪。在云部署的环境下,因为网络问题是的Zookeeper集群失去master节点是较大概率发生的时间,虽然服务最终能够回复,但是漫长的选举时间导致的注册长期不可用是不能容忍的。

Eureka保证AP

​ Eureake在设计时就优先保证可用性。Eureka的各个节点都是平等的,几个节点挂掉并不会影响其他节点的正常工作,剩余的节点依旧可以提供注册和查询服务。而Eureka的客户端在想某个Eureka注册时,如果发现连接失败,则会自动切换到其他节点,只要有一台Eureka孩子啊,就能保证注册服务可用,但是查到的信息可能不是最新的,除此之外,Eureka还有一种自我保护机制,如果在15分钟内查过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会有以下几种情况:

  1. Eureka不再冲注册列表中移除因为长期没有收到心跳而应该过期的服务

  2. Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其他节点上,保证当前节点依然可用

  3. 当前网络稳定时,档期那实例新的注册信息会被同步到其他节点中

    ​ 因此,Eureka可以很好的应对因为网络故障部分节点失去联系的情况,而不会想zookeeper那样使整个注册服务瘫痪

Ribbon

Ribbon是什么

​ Springcloud Ribbon是给予Netflix Ribbon实现的一套客户端负载均衡工具,主要功能是提供客户端的软件负载均衡算法,将NetFlix的中间层服务连接在一起。Ribbon的客户端组建提供一系列完整的配置项,如连接超时、重试等等。简而言之,就是在配置文件中列出LoadBalancer(负载均衡)后面所有的机器,Ribbong会自动基于某种规则(轮询、随机等等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。

Ribbon能做什么

  • Load Balance在微服务活分布式集群中经常用到的一种应用。
  • 负载均衡简单的说就是将用户的请求平均分配到多个服务器上,从而达到系统的搞可用(HA)
  • 常见的负载均衡软件有Nginx、Lvs等
  • dubbo 、Springcloud 中均为我们提供了负载均衡,springcloud的负载均衡算法支持自定义
  • 负载均衡简单分类:
    • 集中式Load Balance
      • 即在服务的消费方和提供方之间使用独立的LB设施,如Nginx,由该设施负责把访问请求通过某种策略转发至服务器的提供方
    • 进程式Load Balance
      • 将LB逻辑集成到消费方,消费方从服务注册中心获得可用服务,然后自己从这些服务中选择合适的提供方
      • Ribbon就属于进程式LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方地址

在服务消费者中集成Ribbon

pom.xml 引入eureka客户端以及Ribbon

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>

application.yml 中引入eureka配置

server:
  port: 8080

eureka:
  client:
    registerWithEureka: false # 不向Eureka注册自己
    serviceUrl:
      defaultZone: http://eureka-test-7001.com:7001/eureka/,http://eureka-test-7002.com:7002/eureka/,http://eureka-test-7003.com:7003/eureka/

服务启动类添加EurekaClient注解

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

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

RestTemplate Bean上添加负载均衡注解

package org.rf.springcloud.config;

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 ConfigBean {
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

服务转发时不需要在写服务器地址,可以通过集群服务名获取服务信息

package org.rf.springcloud.controller;

import com.fasterxml.jackson.databind.ser.Serializers;
import lombok.experimental.Accessors;
import org.rf.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@RestController
@RequestMapping("/consumer/dept")
public class DeptConsumerController {
//    private static final String BASE_URL = "http://localhost:8001";
//    负载均衡通过集群服务名获取服务
    private static final String BASE_URL = "http://SPRINGCLOUD-PROVIDER-DEPT";
    @Autowired
    private RestTemplate restTemplate;

    @PostMapping("/add")
    public boolean add(Dept dept){
        return restTemplate.postForObject(BASE_URL+"/dept/add",dept,Boolean.class);
    }

    @GetMapping("/find/{deptNo}")
    public Dept findByDeptNo(@PathVariable Long deptNo){
        return restTemplate.getForObject(BASE_URL+"/dept/query/"+deptNo,Dept.class);
    }

    @GetMapping("/query/all")
    public List<Dept> queryAll(){
        return restTemplate.getForObject(BASE_URL+"/dept/query/all",List.class);
    }
}

代码持续更新中,源码仓库:https://gitee.com/develoven/springcloud.git**

posted on 2023-06-29 18:51  Internet_worm  阅读(50)  评论(0)    收藏  举报