微服务学习 - 注册中心

认识微服务

微服务并不等于spring cloud, 而是一种经过良好设计的分布式架构方案

微服务中主要包含的技术包括:

  • 微服务治理技术(spring cloud)
  • 异步通信技术(mq)
  • 缓存技术(redis)
  • 分布式搜索技术
  • 持续集成技术(devOps技术)

服务架构的演变

单体架构 分布式架构
特征 将业务的所有功能集中在一个项目中开发, 打成一个包部署 根据业务功能对系统进行拆分, 每个业务模块作为独立项目开发,称为一个服务。
优点 架构简单,部署成本低 降低服务耦合,有利于服务升级扩展
缺点 耦合度高,扩展性差,维护困难 系统复杂度高,运维成本高

分布式架构也会带来一些新的问题:

  1. 服务拆分粒度如何?如何进行拆分更合理
  2. 服务集群地址如何维护
  3. 服务之间如何实现远程调用
  4. 服务的健康状态如何监控

微服务正是一种良好设计的分布式架构,用于解决上面的问题:

  • 单一职责:微服务拆分粒度更小,每一个服务都对应唯一的业务能力,做到单一职责,避免重复开发
  • 面向服务:微服务对外暴露接口(允许别的调用)
  • 自治:团队独立,技术独立,数据独立,部署独立
  • 隔离性强:服务之间做好隔离,容错,降级,避免出现级联问题。(避免服务之间互相影响功能)

现有主流微服务架构对比

技术 spring cloud spring cloud alibaba(兼容两种架构) dubbo
注册中心 eureka nacos,eureka zookeeper, redis
服务远程调用 feign(http协议) dubbo, feign dubbo协议
配置中心 SpringCloudConfig SpringCloudConfig,nacos
服务网关 SpringCloudGateway SpringCloudGateway
服务监控和保护 Hystrix(服务保护) Sentinel dubbo-admin,功能弱

认识spring cloud

  • spring cloud是目前国内使用最广泛的微服务框架
  • spring cloud集成了各种微服务功能组件,并基于spring boot实现了这些组件的自动装配,提供了更好的可用体验。
  • spring cloud和spring boot之间是有版本依赖的。 本教程使用的spring cloud版本为hoxton.SR10, spring boot版本为2.3.

服务的简单拆分

服务拆分的重要事项

  • 不同微服务,不要重复开发相同业务
  • 微服务数据独立,不要访问其他微服务的数据库
  • 微服务将自己的业务暴露为接口,供其他微服务调用

如何跨服务进行远程调用

本质就是进行一次http请求

RestTemplate是一个同步的 Rest API 客户端

  1. 将RestTemplate 在启动类注入容器
java 复制代码
@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
public class OrderApplication {

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

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
  1. 利用userId, 发送请求获取数据
java 复制代码
@Service
public class OrderService {

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private RestTemplate restTemplate;

    public Order queryOrderById(Long orderId) {
        // 1.查询订单
        Order order = orderMapper.findById(orderId);

        // 2. 利用restTemplate容器,发送http请求,完成微服务间通信
        User user = restTemplate.getForObject("http://localhost:8081/user/" + order.getUserId(), User.class);
        order.setUser(user);

        return order;
    }
}

eureka注册中心

3.1 服务调用关系

服务调用关系:

服务提供者:暴露接口给其他接口使用

服务消费者:调用其他服务的接口

提供者与消费者是相对的, 一个服务可以同时是提供和调用者

3.2 eureka原理

远程服务调用会出现的问题

  1. 服务消费者如何获取服务提供者的地址信息? 针对部署的时候的配置变化
    • 服务的提供者在启动时向eureka server(注册中心)注册自己的信息
    • eureka server会存储这些信息
    • 服务消费者根据服务名称从eureka拉取提供者信息
  2. 如果有多个服务提供者,服务者如何选择? 如果提供者是集群的形式存在,需要选择
    • 服务消费者会根据负载均衡策略从服务列表中选择一个服务进行调用
  3. 服务消费者,如何确认服务提供者的健康状态? 消费者不能被提供者下游机器状态影响自身功能实现
    • 服务提供者会每隔30s向eureka server发送心跳请求,报告自己的健康状态
    • eureka 会更新服务列表信息,只保留健康的服务信息
    • 消费者可以拉到最新的信息

3.3 搭建eureka服务

  1. 搭建服务注册中心:搭建eureka server
  2. 服务注册:将user-service, order-service都注册到eureka
  3. 服务发现:在order-service中完成服务拉取,并根据负载均衡算法挑选一个服务,实现远程调用

搭建eureka server的步骤

  1. 引入eureka依赖:
xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--  步骤1:引入eureka。  -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
</dependencies>
  1. 添加注解到启动类
java 复制代码
// 添加自动装配开关
@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class, args);
    }
}
  1. 将eureka也注册到eureka中
yaml 复制代码
# 这行配置指定了eureka服务器监听的端口号
server:
  port: 10086
# 定义本应用程序名称,用于被服务注册和发现
spring:
  application:
    name: eureka-server # eureka 服务名称
# eureka.client:将eureka服务器注册为客户端
#   eureka服务器本身也是一个eureka的客户端 填的是eureka服务端的路径
eureka:
  client:
    service-url:
      defaultZone: http://localhost:10086/eureka/ 

服务注册的配置:

  1. 引入eureka客户端依赖
xml 复制代码
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
  1. 添加基础配置
yaml 复制代码
spring:
  application:
    name: order-service
eureka:
  client:
    service-url: # eureka 地址信息
      defaultZone: http://localhost:10086/eureka/ # eureka地址

访问eureka的管理页面 运行实例管理信息

idea中如何启动多个实例:通过复制配置,增加虚拟机端口的命令,来模仿集群的情况。

服务的发现

  1. 利用服务进行调用
java 复制代码
public Order queryOrderById(Long orderId) {
    // 1.查询订单
    Order order = orderMapper.findById(orderId);

    // 2. 调用服务。查询角色信息
    User user = restTemplate.getForObject("http://user-service/user/" + order.getUserId(), User.class);
    order.setUser(user);

    return order;
}
  1. 添加负载均衡注解
java 复制代码
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
    return new RestTemplate();
}

4. ribbon负载均衡

4.1 负载均衡的原理

LoadBalancerInterceptor 基于这个拦截器

4.2 负载均衡策略

默认的负载均衡规则是在相同机房数据内轮询 除此之外:ribbon还提供了很多中不同的负载均衡策略: 如 随机分配,轮询分配,

方法1:在application类中注册新的规则(全体微服务)

java 复制代码
@Bean
public IRule rule() {
    return new RandomRule();
}

方法2:在配置文件中配置(针对某一个微服务修改)

yaml 复制代码
user-service:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 随机负载均衡策略

4.3 饥饿加载

ribbon 默认采用懒加载,在第一次访问时,才会去创建loadbalanceclient,请求时间会比较长。 为了降低第一次访问的耗时,可以在启动时创建。

yaml 复制代码
ribbon:
  eager-load:
    enabled: true # 开启饥饿加载
    clients:
      - user-service # 开启服务名称(允许多个配置)

nacos注册中心

1. nacos的使用

  1. 引入依赖:
xml 复制代码
<dependencies>
    <!-- 父项目: 引入alibaba依赖 -->
    <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>
    
    <!-- 子项目:引入nacos组件依赖 -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
</dependencies>
  1. 添加配置 yml
yaml 复制代码
spring:
  application:
    name: userservice
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848 # nacos服务地址
  1. 添加注解:将注册中心引入
java 复制代码
@SpringBootApplication
public class OrderApplication {

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

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}
  1. 实际调用
java 复制代码
@Service
public class OrderService {

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private RestTemplate restTemplate;

    public Order queryOrderById(Long orderId) {
        // 1.查询订单
        Order order = orderMapper.findById(orderId);

        // 2. 调用服务
        User user = restTemplate.getForObject("http://userservice/user/" + order.getUserId(), User.class);
        order.setUser(user);

        // 3.返回
        return order;
    }
}

2. nacos的分级存储模型

  1. 一级是服务,例如userservice
  2. 二级是集群,例如杭州、上海、广州
  3. 三级是实例,我们在某个机房部署的服务器

如何去修改实例的集群属性: application.yml 中修改 spring.cloud.nacos.discovery.cluster-name属性即可

3. nacos的负载均衡

  1. 如何设置需要进行同集群优先的配置 userservice.ribbon.NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule
  2. 服务提供者如何配置自己的集群 spring.cloud.nacos.discovery.cluster-name=SH

nacosRule 奉行同集群优先,同集群之间按照随机访问的模式访问实例。 (同时也可以在后台设置权重。可以把权重设置为0,方便某些机器进行升级)

  1. 命名空间 不同的命名空间之间互相不能访问 application.yml 中修改 spring.cloud.nacos.discovery.namespace

  2. 注册拉取的变化 设置非临时实例的方法: spring.cloud.nacos.discovery.ephemeral: false

相关推荐
没有bug.的程序员1 天前
微服务的本质:不是拆服务,而是拆复杂度
java·jvm·spring·微服务·云原生·容器·架构
古城小栈1 天前
微服务测试:TestContainers 集成测试实战指南
微服务·架构·集成测试
古城小栈1 天前
云原生架构:微服务 vs 单体应用的选择
微服务·云原生·架构
IT界的奇葩1 天前
康威定律对微服务的启示
微服务·云原生·架构
pingzhuyan2 天前
微服务: springboot整合kafka实现消息的简单收发(上)
spring boot·微服务·kafka
Gavin在路上2 天前
dubbo源码之微服务治理的“隐形遥控器”——QOS 机制解析
微服务·架构·dubbo
嘻哈baby2 天前
Nacos服务注册与配置中心实战指南
微服务
2501_924064112 天前
2025年优测全链路压测平台:高并发卡顿环节精准定位实践
微服务·压测方案
赵榕2 天前
RabbitMQ发布订阅模式同一消费者多个实例如何防止重复消费?
分布式·微服务·rabbitmq
Selegant2 天前
告别传统部署:用 GraalVM Native Image 构建秒级启动的 Java 微服务
java·开发语言·微服务·云原生·架构