高可用
启动多台服务器,防止宕机
02商品服务
1.配置第一个商品服务的启动参数
java -jar item.jar --server.port=8001
1.配置第二个商品服务的启动参数
java -jar item.jar --server.port=8002
启动这两个端口的项目
查看注册表
05eureka
eureka集群的结构:对等结构
没有主从之分,所有服务器都是相同的角色:node peer
两个eureka不同的配置
1.主机名:eureka1 eureka2
2.打开注册和拉取
3.连接其他eureka服务器的地址
1.新建配置文件application-eureka1.yml和application-eureka2.yml
2.配置eureka1的启动参数
eureka:
instance:
hostname: eureka1
client:
register-with-eureka: true
fetch-registry: true
#1连接2
service-url:
defaultZone: http://eureka2:2002/eureka
java -jar e.jar
--spring.profiles.active=eureka1
--server.port=2001
3.配置eureka2 的启动参数
eureka:
instance:
hostname: eureka2
client:
register-with-eureka: true
fetch-registry: true
#2连接1
service-url:
defaultZone: http://eureka1:2001/eureka
java -jar e.jar
--spring.profiles.active=eureka2
--server.port=2002
启动两个05的eureka
eureka客户端注册时,向两个服务器注册
修改02,03,04三个微服务项目
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
当一个 eureka 服务宕机时,仍可以连接另一个 eureka 服务
RestTemplate
spring提供的一个rest api调用工具,对rest调用做了高度封装,暴露了非常简便的方法,来做rest远程调用:
getForObject(url,转换的类型.class,提交的参数数据)
postForObject(url,协议体数据,转换的类型.class)
Ribbon
spring cloud提供的工具
ribbon对RestTemplate 进行了增强,添加了负载均衡和重试的功能
新建一个项目module,springboot项目
自动引入依赖
创建项目完成后,在pom.xml中添加sp01-commons依赖
并将application.properties修改为application.yml
#06项目只是一个功能测试项目
#ribbon ,hystrix 功能
#两个工具测试完之后,这个项目会删除
spring:
application:
name: ribbon
server:
port: 3001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka,http://eureka2:2002/eureka
然后在主启动类里添加如下:
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
创建一个controller,类名叫RibbonController
package cn.huac.sp06.controller;
import cn.huac.sp01.pojo.Item;
import cn.huac.web.util.JsonResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
@Slf4j
public class RibbonController {
@Autowired
private RestTemplate rt;
@GetMapping("/item-service/{orderId}")
public JsonResult<List<Item>> getItems(@PathVariable String orderId){
//调用远程02项目 获得商品列表
//{1}是RestTemplate提供的占位符格式
return rt.getForObject("http://localhost:8001/{1}",JsonResult.class,orderId);
}
@PostMapping("/item-service/decreaseNumber")
public JsonResult decreaseNumber(@RequestBody List<Item> items){
return rt.postForObject(
"http://localhost?8001/decreaseNumber",
items,
JsonResult.class
);
}
}
测试,启动06
http://localhost:3001/item-service/35
使用postman,POST发送以下格式数据:
[{“id”:1, “name”:“abc”, “number”:23},{“id”:2, “name”:“def”, “number”:11}]
@RestController
public class RibbonController {
@Autowired
private RestTemplate rt;
@GetMapping("/item-service/{orderId}")
public JsonResult<List<Item>> getItems(@PathVariable String orderId) {
//向指定微服务地址发送 get 请求,并获得该服务的返回结果
//{1} 占位符,用 orderId 填充
return rt.getForObject("http://localhost:8001/{1}", JsonResult.class, orderId);
}
@PostMapping("/item-service/decreaseNumber")
public JsonResult decreaseNumber(@RequestBody List<Item> items) {
//发送 post 请求
return rt.postForObject("http://localhost:8001/decreaseNumber", items, JsonResult.class);
}
/
@GetMapping("/user-service/{userId}")
public JsonResult<User> getUser(@PathVariable Integer userId) {
return rt.getForObject("http://localhost:8101/{1}", JsonResult.class, userId);
}
@GetMapping("/user-service/{userId}/score")
public JsonResult addScore(
@PathVariable Integer userId, Integer score) {
return rt.getForObject("http://localhost:8101/{1}/score?score={2}", JsonResult.class, userId, score);
}
/
@GetMapping("/order-service/{orderId}")
public JsonResult<Order> getOrder(@PathVariable String orderId) {
return rt.getForObject("http://localhost:8201/{1}", JsonResult.class, orderId);
}
@GetMapping("/order-service")
public JsonResult addOrder() {
return rt.getForObject("http://localhost:8201/", JsonResult.class);
}
}
测试 其他项目
http://localhost:3001/user-service/7
http://localhost:3001/user-service/7/score?score=100
http://localhost:3001/order-service/123abc
http://localhost:3001/order-service/
Ribbon的负载均衡
负载均衡
1.对Rest Template进行增强,添加一个@LoadBalanced注解
2.改用调用地址为service-id
1.
@RestController
public class RibbonController {
@Autowired
private RestTemplate rt;
@GetMapping("/item-service/{orderId}")
public JsonResult<List<Item>> getItems(@PathVariable String orderId) {
//这里服务器路径用 service-id 代替,ribbon 会向服务的多台集群服务器分发请求
return rt.getForObject("http://item-service/{1}", JsonResult.class, orderId);
}
@PostMapping("/item-service/decreaseNumber")
public JsonResult decreaseNumber(@RequestBody List<Item> items) {
return rt.postForObject("http://item-service/decreaseNumber", items, JsonResult.class);
}
/
@GetMapping("/user-service/{userId}")
public JsonResult<User> getUser(@PathVariable Integer userId) {
return rt.getForObject("http://user-service/{1}", JsonResult.class, userId);
}
@GetMapping("/user-service/{userId}/score")
public JsonResult addScore(
@PathVariable Integer userId, Integer score) {
return rt.getForObject("http://user-service/{1}/score?score={2}", JsonResult.class, userId, score);
}
/
@GetMapping("/order-service/{orderId}")
public JsonResult<Order> getOrder(@PathVariable String orderId) {
return rt.getForObject("http://order-service/{1}", JsonResult.class, orderId);
}
@GetMapping("/order-service")
public JsonResult addOrder() {
return rt.getForObject("http://order-service/", JsonResult.class);
}
}
修改02item-service ,返回的结果中包含msg=“port=8002”
访问测试
访问测试,ribbon 会把请求分发到 8001 和 8002 两个服务端口上
http://localhost:3001/item-service/34
Ribbon重试
重试:一种容错方式,调用远程服务失败(异常,服务器崩溃,调用超时),可以自动重试调用
1.添加spring-retry依赖
2.设置重试参数
2.1 ribbon.MaxAutoRetries-单台服务器重试次数
2.2 ribbon.MaxAutoRetriesNextServer-更换服务器的次数
2.3 ribbon.OkToAllOperations-是否对所有类型请求都进行重试,默认只对GET重试
2.4 connectTimeout-建立连接的超时时间
2.5 readTimeout-已建立连接,已发送请求,等待响应的超时时间
2.4 2.5两个超时设置,不能在yml中配置,而是要使用java代码设置
首先去sp06-ribbon项目下pom.xml添加重试的依赖
版本boot已经设置好了,我们删掉,不需要
然后在sp06的主启动类里添加SimpleClientHttpRequestFactory对象,设置一下响应超时的时间
然后在02项目下设置延迟,要是延迟之后还没有响应,就重试
访问,测试 ribbon 重试机制
通过 ribbon 访问 item-service,当超时,ribbon 会重试请求集群中其他服务器
http://localhost:3001/item-service/37