微服务

认识微服务

单体架构:将业务的所有功能集中在一个项目中开发,打成一个包部署。优点:架构简单。部署成本低。缺点:耦合度高。

分布式架构:根据业务功能对系统进行拆分,每个业务模块作为独立项目开发,称为一个服务。优点:降低服务耦合。有利于服务升级拓展。

微服务是一种经过良好架构设计的分布式架构方案,微服务架构特征:

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

微服务这种方案需要技术框架来落地,全球的互联网公司都在积极尝试自己的微服务落地技术。在国内最知名的就是SpringCloud和阿里巴巴的Dubbo。

Springcloud

SpringCloud是目前国内使用最广泛的微服务框架。官网地址:https://spring.io/projects/spring-cloud

SpringCloud集成了各种微服务功能组件,并基于SpringBoot实现了这些组件的自动装配,从而提供了良好的开箱即用体验:

  • 服务注册发现:Eureka, Nacos, Consul
  • 服务远程调用:OpenFeign, Dubbo
  • 服务链路监控:Zipkin, Sleuth
  • 统一配置管理:SpringCloudConfig, Nacos
  • 统一网关路由:SpringcloudGateway、 Zuul
  • 流控、降级、保护:Hystix, Sentinel

服务拆分及远程调用

服务拆分注意事项

  • 不同微服务,不要重复开发相同业务
  • 微服务数据独立,不要访问其它微服务的数据库
  • 微服务可以将自己的业务暴露为接口,供其它微服务调用
  • 微服务需要根据业务模块拆分,做到单一职责,不要重复开发相同业务

RestTemplate

在启动类中创建restTemplate并注入Spring容器

@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();
}

}

调用

@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private RestTemplate restTemplate;
public Order queryOrderById(Long orderId) {
Order order = orderMapper.findById(orderId);
String url = "http://localhost:8081/user/"+order.getUserId();
User user = restTemplate.getForObject(url, User.class);
order.setUser(user);
return order;
}
}

提供者与消费者

  • 服务提供者:一次业务中,被其它微服务调用的服务。(提供接口给其它微服务)
  • 服务消费者:一次业务中,调用其它微服务的服务。(调用其它微服务提供的接口)
  • 提供者与消费者角色其实是相对的。一个服务可以同时是服务提供者和服务消费者

Eureka注册中心

在Eureka架构中,微服务角色有两类:

  • EurekaServer:服务端,注册中心。记录服务信息、心跳监控
  • EurekaClient:客户端。
    • Provider: 服务提供者注册自己的信息到EurekaServer。每隔30秒向EurekaServer发送心跳。
    • consumer: 服务消费者根据服务名称从EurekaServer拉取服务列表,基于服务列表做负载均衡,选中一个微服务后发起远程调用

搭建Eureka服务

  1. 创建项目,引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
  1. 启动类添加@EnableEurekaServer注解
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
  1. 配置文件application.yml
server:
port: 10086
spring:
application:
name: eurekaserver
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka

服务注册

  1. 引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
  1. 配置文件application.yml
server:
port: 8081
spring:
application:
name: userservice
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka

idea同一个工程启动多个服务:

  1. 右击要复制的服务,选择Copy Configuration
  2. 修改启动端口:点击Modify options,Add vm options,输入-Dserver.port=8083,点击启动即可

服务发现

  1. 启动类RestTemplate中添加@LoadBalanced,启动负载均衡策略。
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}

  1. 调用,将localhost:8081 替换为 spring.application.name设置的值
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private RestTemplate restTemplate;
public Order queryOrderById(Long orderId) {
Order order = orderMapper.findById(orderId);
String url = "http://userservice/user/"+order.getUserId();
User user = restTemplate.getForObject(url, User.class);
order.setUser(user);
return order;
}
}

Ribbon负载均衡

Ribbon的负载均衡规则是一个叫做IRule的接口来定义的,每一个子接口都是一种规则

通过定义IRule实现可以修改负载均衡规则,有两种方式:

  1. 代码方式,在启动类中,定义一个新的IRule
@Bean
public IRule randomRule(){
return new RandomRule();
}
  1. 配置文件方式,在application.yml中
userservice:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

Ribbon饥饿加载

Ribbon默认是采用懒加载,即第一次访问时才会去创建LoadBalanceClient,请求时间会很长。而饥饿加载则会在项目启动时创建,降低第一次访问的耗时,

ribbon:
eager-load:
enabled: true
clients:
- userservice

Nacos注册中心

Nacos是阿里巴巴的产品,现在是SpringCloud中的一个组件。相比Eureka功能更加丰富,在国内受欢迎程度较高。

官网:https://nacos.io/zh-cn/

Nacos文档:https://nacos.io/zh-cn/docs/what-is-nacos.html

github地址:https://github.com/alibaba/nacos

安装运行

2.5.2版本下载:https://github.com/alibaba/nacos/releases/tag/2.5.2

Windows启动nacos(standalone代表着单机模式运行,非集群模式)

D:\soft\nacos-server-2.5.2\nacos\bin>startup.cmd -m standalone
"nacos is starting with standalone"

,--.
,--.'|
,--,: : | Nacos 2.5.2
,`--.'`| ' : ,---. Running in stand alone mode, All function modules
| : : | | ' ,'\ .--.--. Port: 8848
: | \ | : ,--.--. ,---. / / | / / ' Pid: 24540
| : ' '; | / \ / \. ; ,. :| : /`./ Console: http://192.168.32.1:8848/nacos/index.html
' ' ;. ;.--. .-. | / / '' | |: :| : ;_
| | | \ | \__\/: . .. ' / ' | .; : \ \ `. https://nacos.io
' : | ; .' ," .--.; |' ; :__| : | `----. \
| | '`--' / / ,. |' | '.'|\ \ / / /`--' /
' : | ; : .' \ : : `----' '--'. /
; |.' | , .-./\ \ / `--'---'
'---' `--`---' `----'

服务注册到Nacos

  1. 在父工程中添加spring-cloud-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>
  1. 在子工程中添加nacos客户端依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
  1. 在application.yml中添加配置
spring:
cloud:
nacos:
server-addr: localhost:8848
  1. 启动之后在nacos控制台,服务管理-服务列表可以看到服务

nacos服务分级存储模型

服务跨集群调用问题:服务调用尽可能选择本地集群的服务,跨集群调用延迟较高。本地集群不可访问时,再去访问其它集群

设置实例的集群属性,在application.yml中添加配置 spring.cloud.nacos.discovery.cluster-name属性,SH表示集群名称为上海

spring:
cloud:
nacos:
server-addr: localhost:8848
discovery:
cluster-name: SH