微服务简介
首先理解一个概念——高可用,即保证服务器的高度可用,减少停工时间;原来的单体应用只有一个服务器,所有服务(功能)都在该服务器上,如果出现某些突发情况,服务器挂了,整个系统就停工了。而微服务保证多个服务存在于多个服务器,或多个服务器共同维护一个服务(集群),某一个服务挂了并不会过大的影响整体,不会导致整个系统的停工
微服务的实现
每个微服务对应一个服务器,一个数据库;但是不同服务互相直接调用起来非常麻烦而且没有条理,所以将所有模块注册到一个共同的地方,每个请求都找到注册中心,再由注册中心来发送到各个服务器
服务注册
注册中心的实现(Netfilx)
- 新建一个springboot项目模块,添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
- 为入口类添加注解
@EnableEurekaServer
,表示服务器端 - 配置文件
server:
port: 8761
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false #是否注册到注册中心
fetch-registry: false #是否调用其他服务
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
成功后可看到如下页面:
实现服务注册
- 创建一个服务,并引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
- 入口类添加注解
@EnableEurekaClient
,表示客户端,会找到服务器端并注册上去 - 配置
server:
port: 9001
spring:
application:
name: service-user #该服务在注册中心的名字
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
注册成功后可以在注册中心看到该服务:
共用服务
对于如响应实体类这样每个服务中都相同的类可以放在一个共用服务里面,而不是在每一个服务中写一遍,共用服务创建后在其他服务的pom文件中引入该依赖即可
实现服务之间直接调用
User
@GetMapping("get/{id}")
public ResponseVO getById(@PathVariable Integer id){
return ResponseVO.FORBIDDEN;
}
Order
@Autowired
private RestTemplate restTemplate;
@GetMapping("getUser/{id}")
public ResponseVO getById(@PathVariable Integer id){
ResponseEntity<ResponseVO> entity = restTemplate.getForEntity("http://localhost:9001/user/get/1",ResponseVO.class);
ResponseVO responseVO = entity.getBody();
return responseVO;
}
通过RestTemplate可以在某个服务需要用到另一个服务的数据时实现调用,但这种直接调用的方式绕过了注册中心,这样的方式将ip写死了,必须知道对方的ip或域名才能进行调用,如果部署的地址发生改变需要同时进行更改,不推荐使用
Ribbon
使用Ribbon实现服务调用
spring-cloud-starter-netflix-eureka-client 3.0版本的已经内置ribbon,所以ribbon也失去了版本维护,如果强行添加会导致jar包冲突,从而报错——No instances available for XXX;如果使用老版本需要添加spring-cloud-netflix-ribbon依赖
- 在RestTemplate的Bean上添加注解
@LoadBalanced
- 在使用restTemplate时,url参数不使用实际的域名和端口,而是使用注册在注册中心的名字
ResponseEntity<ResponseVO> entity = restTemplate.getForEntity("http://service-user/user/get/1",ResponseVO.class);
负载均衡
指将任务分配到多个操作单元执行
服务器端负载均衡
利用nginx对集群搭建的服务器,通过集群维护一个服务,此时由nginx在服务器端对请求进行负载均衡
客户端负载均衡
当一个客户端需要调用其他客户端时,将被调用方在多个服务器下运行,将任务分到不同操作单元
Ribbon就是客户端负载均衡的工具,使用ribbon可以通过注册中心将请求分配到不同操单元
通过设置运行环境可以实现将服务配置到多个端口下:
-D表示向虚拟机传递参数,后接server.port可以将该服务同时运行到9003端口
OpenFeign(声明式调用)
ribbon调用并不是最好的方式,推荐使用OpenFeign进行声明式调用
- 引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- 在调用方入口使用注解
@EnableFeignClients
,表示这个客户端启用声明式调用 - 创建一个新接口用于对某一个服务的调用,使用注解@FeignClient(),value是被调用的服务的名称,里面的方法使用springMVC的注解来对应被调用方的方法路径
@FeignClient("service-user")//value参数为被调用方的名称
public interface UserService {
@GetMapping("user/get/{id}")//被调用的方法路径
ResponseVO getById(@PathVariable Integer id);
}
- 使用该接口时直接注入
@Autowired
private UserService userService;
@GetMapping("getUser2/{id}")
public ResponseVO get2ById(@PathVariable Integer id){
ResponseVO responseVO = userService.getById(id);
return responseVO;
}