Eureka 搭建 高可用 订单支付集群

在springcloud之前我们听过最多的服务注册rpc框架就是 dubbo + zookepper。

今天我们说一下一个新的服务注册组件:eureka

本项目地址:git项目地址

一、核心概念

Eureka 作为 Spring Cloud 体系中最核心、默认的注册中心组件,研究它的运行机制,有助于我们在工作中更好地使用它。
Eureka 主要包括两个模块:Eureka Server 和 Eureka Client。
在这里插入图片描述
1. Eureka Server:注册中心服务端
以 REST API 的形式为服务实例提供了注册、管理和查询等操作。同时,Eureka Server 也为我们提供了可视化的监控页面,可以直观地看到各个 Eureka Server 当前的运行状态和所有已注册服务的情况。
注册中心服务端主要对外提供了三个功能:

  • 服务注册
    服务提供者启动时,会通过 Eureka Client 向 Eureka Server 注册信息,Eureka Server 会存储该服务的信息,Eureka Server 内部有二层缓存机制来维护整个注册表
  • 提供注册表
    服务消费者在调用服务时,如果 Eureka Client 没有缓存注册表的话,会从 Eureka Server 获取最新的注册表
  • 同步状态
    Eureka Client 通过注册、心跳机制和 Eureka Server 同步当前客户端的状态。

2. Eureka Client :服务注册客户端
简而言之就是具体提供服务的微服务,将自身的服务接口注册到eureka-Server端,以供调用。

自我保护机制
默认情况下,如果 Eureka Server 在一定的 90s 内没有接收到某个微服务实例的心跳,会注销该实例。但是在微服务架构下服务之间通常都是跨进程调用,网络通信往往会面临着各种问题,比如微服务状态正常,网络分区故障,导致此实例被注销。

固定时间内大量实例被注销,可能会严重威胁整个微服务架构的可用性。为了解决这个问题,Eureka 开发了自我保护机制,那么什么是自我保护机制呢?

Eureka Server 在运行期间会去统计心跳失败比例在 15 分钟之内是否低于 85%,如果低于 85%,Eureka Server 即会进入自我保护机制。
Eureka Server 触发自我保护机制后,页面会出现提示:
在这里插入图片描述
通过在 Eureka Server 配置如下参数,开启或者关闭保护机制,生产环境建议打开:

eureka.server.enable-self-preservation=true

二、使用eureka搭建高可用订单支付集群

本次演示一个简易的订单支付系统,架构分为:

  1. 客户端consumer(port:80)
  2. eureka-Sever注册中心(port:7001,7002)
  3. eureka-client支付微服务(port:8001,8002)
    采用多注册中心,多服务端实现系统高可用,及负载均衡。

数据库

CREATE TABLE `payment` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `serial` varchar(255) DEFAULT NULL COMMENT '名称',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

这里由于我们是一个集群系统,所以我们创建一个父工程:springcloud2020
并将共用的entities以及mapper,抽离到子Module cloud-api-commons里面,贴一下项目结构图:
在这里插入图片描述

1.支付模块构建

如上图所示,首先我们看一下支付模块也就是 微服务的提供者,eureka的client端:端口:8001
这里需要引入一个核心的eureka-client包:

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

server:
  port: 8001
spring:
  application:
    name: cloud-payment-service
  datasource:
    # 当前数据源操作类型
    type: com.alibaba.druid.pool.DruidDataSource
    # mysql驱动类
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/yao?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
    username: root
    password: 123456
mybatis:
  mapper-locations: classpath*:mapper/*.xml
  type-aliases-package: com.cpown.springcloud.entities

eureka:
  instance:
    hostname: localhost #eureka服务注册地址
  client:
    #是否从eureka Server 抓取已有的注册信息,默认true,单节点无所谓,集群必须为true才能配合ribbon使用负载均衡
    fetch-registry: true
    #表示是否将自己加入eureka service true代表加入
    register-with-eureka: true
    service-url:
      #      #设置 eureka server 交互的地址查询服务和注册服务需要依赖的地址
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka

这里要注意的就是eureka的核心配置:defaultZone里面的是Eureka的注册中心地址,后边会说到,配了两个地址是一个高可用集群的操作。

package com.cpown.springcloud.controller;

import com.cpown.springcloud.dto.CommonResult;
import com.cpown.springcloud.entities.Payment;
import com.cpown.springcloud.service.PaymentServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

@RestController
@Slf4j
public class PaymentController {
    @Resource
    PaymentServiceImpl paymentService;
    @Value("${server.port}")
    private String serverPort;

    @GetMapping("/get/{id}")
    public CommonResult get(@PathVariable("id") Long id){
        log.info("8001查询数据:"+id);
        Payment payment = paymentService.selectByPrimaryKey(id);
        if(null != payment){
            return new CommonResult("请求成功,serverPort:"+serverPort,0000,payment);
        }else {
            return new CommonResult("请求失败,serverPort:"+serverPort,9999);
        }
    }

    @PostMapping("/create")
    public CommonResult create(@RequestBody Payment payment){
        log.info("8001新增数据"+payment);
        int insert = paymentService.insert(payment);
        log.info("8001新增数据结果:"+insert);
        if(insert>0){
            return new CommonResult("插入数据成功,serverPort:"+serverPort,0000,payment);
        }else {
            return new CommonResult("插入数据失败,serverPort:"+serverPort,9999);
        }
    }
}

我们的payment服务端游两个接口,我们启动自测一下:
在这里插入图片描述
接口是可用的。

在这里插入图片描述
这里需要在启动类添加@EnableEurekaClient注解 标明自己是 eureka服务里面的 Client,加了注解才能够将服务注册进eureka-server注册中心。

2.注册中心 eureka-server

注册中心代码不多:要注意的点有三个:

  1. 需要引入eureka-server
  <!--eureka server-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
  1. 需要使用注解@EnableEurekaServer表明当前服务是server端

在这里插入图片描述

  1. 配置eureka-server
server:
  port: 7001
#spring:
#  application:
#    name: cloud-eureka-service #eureka服务注册名称
eureka:
  instance:
    hostname: eureka7001 #eureka服务注册地址
  client:
    #false 表示自己就是注册中心,职责就是维护服务实例,不需要去检索服务
    fetch-registry: false
    #false 表示不想注册中心注册自己
    register-with-eureka: false
    service-url:
#      #设置 eureka server 交互的地址查询服务和注册服务需要依赖的地址
      defaultZone: http://eureka7002.com:7002/eureka/

注意:我们前边在支付模块里面配置的defaultZone,地址就是我们当前 注册中心的地址。
由于我们是集群配置,为了便于区分,我们将本地 localhost转换为相应的域名地址。让上面配置的host形式的serviceUrl能在本地正确访问到
在这里插入图片描述
我们启动一下:可以发现我们之前的支付模块服务已经注册进注册中心,也可使用localhost:7001直接访问在这里插入图片描述

三、实现高可用及负载均衡

我们一般实现注册中心高可用及负载均衡,至少应该脱离单机操作,实现多机器协作。

  1. 在前面支付模块的基础上,再创建一个支付微服务cloud-provider-payment8002,代码一样,功能一样,仅端口不一样。在这里插入图片描述
  2. 再构建一个注册中心cloud-eureka-sever7002

在这里插入图片描述
注意:这里的defaultZone地址配置的是我们 ,另一个注册中心地址7001;同样的在7001的配置文件中defaultZone地址为7002.
注册中心配置讲究一个,互相注册,相互守望。

defaultZone: http://eureka7001.com:7001/eureka/
  1. 在注册中心集群配置过后,相应的我们需要在 支付端将注册中心地址修改为两个。
    . 在这里插入图片描述

都配置号以后启动支付服务,以及注册中心:
在这里插入图片描述
在这里插入图片描述
可以看到,在注册中心7001和7002里面分别有两个CLOUD-PAYMENT-SERVICE(我们的支付项目配置的微服务名称 spring.application.name)
同时我们的7001和7002里面的DS Replicas分别显示了另一台地址,就代表集群构建成功了.

四、客户端调用模块 cloud-consumer-order80

最后我们创建客户端项目,客户端只有两个类:
在这里插入图片描述

package com.cpown.springcoloud.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;

/**
 * RestTemplate配置类
 */
@Configuration
public class ApplicationContextConfig {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

配置类:主要为了创建RestTemplate 的bean实例,方便后边调用接口。
@LoadBalanced注解很关键,如果需要实现负载均衡调用多台机器的话 需要使用此注解,可以直接使用微服务名称调用接口,不需要使用接口ip地址。如下:

package com.cpown.springcoloud.controller;

import com.cpown.springcloud.dto.CommonResult;
import com.cpown.springcloud.entities.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

/**
 * 订单调用controller
 */
@RestController
@Slf4j
public class OrderController {
    @Resource
    RestTemplate restTemplate;
    /**
     * 单机调用
     */
//    private static  final  String baseUrl = "http://localhost:8001";
    /**
     * 集群微服务调用
     * 可以直接使用微服务名称
     * 需要搭配 @LoadBalanced注解
     */
    private static  final  String baseUrl = "http://cloud-payment-service";


    @GetMapping("/consumer/payment/get/{id}")
    public CommonResult<Payment> get(@PathVariable("id") String id){
        return restTemplate.getForObject(baseUrl+"/get/"+id,CommonResult.class);
    }

    @GetMapping("/consumer/payment/create")
    public CommonResult<Payment> create(Payment payment){
        return restTemplate.postForObject(baseUrl+"/create",payment,CommonResult.class);
    }
}

至此,多有代码已结束,我们启动所有项目测试一下。

五、测试

由于默认采用的负载均衡策略是轮询,所以我们的请求,应该是交替调用 8001和8002服务的。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
没问题的。

六、补充

在我们的支付模块 8001和8002配置文件中添加如下配置,可以在监控页面直接看到,规范的服务名称,以及ip地址。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值