实战前需了解:https://blog.csdn.net/wanzijy/article/details/125041622
Hystrix熔断器整合 - 搭建项目:https://blog.csdn.net/wanzijy/article/details/125496651
Hystrix熔断器整合 - 请求缓存:https://blog.csdn.net/wanzijy/article/details/125512072
Hystrix熔断器整合 - 请求合并:https://blog.csdn.net/wanzijy/article/details/125579664
Hystrix熔断器整合 - 服务隔离之线程池隔离:https://blog.csdn.net/wanzijy/article/details/125630353
Hystrix熔断器整合 - 服务隔离之信号量隔离:https://blog.csdn.net/wanzijy/article/details/125826690
Hystrix熔断器整合 - 服务熔断和服务降级:https://blog.csdn.net/wanzijy/article/details/125826853
Hystrix熔断器整合 - Feign实现服务容错:https://blog.csdn.net/wanzijy/article/details/125985304
Hystrix熔断器整合 - 可视化界面三部曲:https://blog.csdn.net/wanzijy/article/details/126005452
1. 项目结构
项目介绍:
- eureka-server 注册中心1
- eureka-server02 注册中心2
- product-service 商品服务
- order-service-rest 订单服务,用于远程调用商品服务
2. 父项目的pom.xml
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<spring-cloud.version>Hoxton.SR1</spring-cloud.version>
</properties>
<packaging>pom</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
3. eureka-server 模块
3.1 pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
3.2 application.yml
spring:
application:
name: eureka-server
server:
port: 8761
eureka:
instance:
hostname: eureka01 # 主机名,不配置的时候将根据操作系统的主机名来获取
prefer-ip-address: false # 是否使用 ip 地址注册
instance-id: ${spring.cloud.client.ip-address}:${server.port} # ip:port
client:
register-with-eureka: true
fetch-registry: true
# 设置服务注册中心地址,指向另一个注册中心
service-url: # 对外暴露的注册地址
defaultZone: http://eureka02:8762/eureka/
3.3 启动类
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
4. eureka-server02 模块
4.1 pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
4.2 application.yml
spring:
application:
name: eureka-server
server:
port: 8762
eureka:
instance:
hostname: eureka02 # 主机名,不配置的时候将根据操作系统的主机名来获取
prefer-ip-address: false # 是否使用 ip 地址注册
instance-id: ${spring.cloud.client.ip-address}:${server.port} # ip:port
client:
register-with-eureka: true
fetch-registry: true
# 设置服务注册中心地址,指向另一个注册中心
service-url: # 对外暴露的注册地址
defaultZone: http://eureka01:8761/eureka/
4.3 启动类
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication02 {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication02.class, args);
}
}
搭建完后同时启动上述两个项目,在刚开始启动时可能会在控制台报错。因为虽然说是同时启动上述两个项目,但是这次搭建的是双注册中心,Eureka01在启动时去向Eureka02注册,但是Eureka02可能还没启动成功,所以一开始会报错,反过来Eureka02向Eureka01注册时也是一样,稍微等待一会即可
Eureka01
Eureka02
如果上述双注册中心搭建不成功,看我的另一篇文章,检查里面要注意的地方:
5. product-service 模块
5.1 pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
5.2 application.yml
spring:
application:
name: product-service
server:
port: 7070
eureka:
instance:
prefer-ip-address: true # 是否使用 ip 地址注册
instance-id: ${spring.cloud.client.ip-address}:${server.port} # ip:port
client:
service-url: # 设置服务注册中心地址
defaultZone: http://eureka01:8761/eureka/,http://eureka02:8762/eureka/
register-with-eureka: true
fetch-registry: true
5.3 启动类
@SpringBootApplication
@EnableEurekaClient
public class ProductServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ProductServiceApplication.class, args);
}
}
5.4 pojo
@Data
public class Product {
private Integer id;
private String productName;
private Integer productNum;
private Double productPrice;
public Product(Integer id, String productName, Integer productNum, Double productPrice) {
this.id = id;
this.productName = productName;
this.productNum = productNum;
this.productPrice = productPrice;
}
public Product() {
}
}
5.5 service
5.5.1 接口
public interface ProductService {
List<Product> selectProductList();
List<Product> selectProductListByIds(List<Integer> ids);
Product selectProductListById(Integer id);
}
5.5.2 接口实现类
@Service
public class ProductServiceImpl implements ProductService{
@Override
public List<Product> selectProductList() {
return Arrays.asList(
new Product(1, "华为手机", 1, 5800D),
new Product(2, "联想笔记本", 1, 6888D),
new Product(3, "小米平板", 5, 2020D)
);
}
@Override
public List<Product> selectProductListByIds(List<Integer> ids) {
List<Product> products = new ArrayList<>();
ids.forEach(id -> products.add(new Product(id, "电视机" + id, 1, 8650D)));
return products;
}
@Override
public Product selectProductListById(Integer id) {
return new Product(id, "冰箱", 1, 2666D);
}
}
5.6 controller
@RestController
@RequestMapping("/product")
public class ProductController {
@Autowired
private ProductService productService;
@GetMapping("list")
public List<Product> selectProductList() {
return productService.selectProductList();
}
@GetMapping("listByIds")
public List<Product> selectProductListByIds(@RequestParam("id") List<Integer> ids) {
return productService.selectProductListByIds(ids);
}
@GetMapping("/{id}")
public Product selectProductById(@PathVariable("id") Integer id) {
return productService.selectProductListById(id);
}
}
搭建完后开启项目,分别访问以下链接,看项目是否搭建成功:
- http://localhost:7070/product/list
- http://localhost:7070/product/listByIds?id=1&id=2
- http://localhost:7070/product/1
比如:http://localhost:7070/product/list
6. order-service-rest 模块
使用 RestTemplate 远程调用 product-service
6.1 pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
<version>2.2.1.RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
6.2 application.yml
spring:
application:
name: order-service-rest
server:
port: 9090
eureka:
instance:
prefer-ip-address: true # 是否使用 ip 地址注册
instance-id: ${spring.cloud.client.ip-address}:${server.port} # ip:port
client:
service-url: # 设置服务注册中心地址
defaultZone: http://eureka01:8761/eureka/,http://eureka02:8762/eureka/
register-with-eureka: true
fetch-registry: true
6.3 启动类
@SpringBootApplication
@EnableEurekaClient
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
6.4 pojo
@Data
public class Product {
private Integer id;
private String productName;
private Integer productNum;
private Double productPrice;
public Product(Integer id, String productName, Integer productNum, Double productPrice) {
this.id = id;
this.productName = productName;
this.productNum = productNum;
this.productPrice = productPrice;
}
public Product() {
}
}
@Data
public class Order {
private Integer id;
private String orderNo;
private String orderAddress;
private Double totalPrice;
private List<Product> productList;
public Order(Integer id, String orderNo, String orderAddress, Double totalPrice, List<Product> productList) {
this.id = id;
this.orderNo = orderNo;
this.orderAddress = orderAddress;
this.totalPrice = totalPrice;
this.productList = productList;
}
public Order() {
}
}
6.5 service
6.5.1 接口
public interface ProductService {
List<Product> selectProductList();
List<Product> selectProductListByIds(List<Integer> ids);
Product selectProductListById(Integer id);
}
public interface OrderService {
Order selectOrderById(Integer id);
Order queryOrderById(Integer id);
Order searchOrderById(Integer id);
}
6.5.2 接口实现类
@Service
public class ProductServiceImpl implements ProductService{
@Autowired
private RestTemplate restTemplate;
@Override
public List<Product> selectProductList() {
return restTemplate.exchange(
"http://product-service/product/list",
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<Product>>() {
}).getBody();
}
@Override
public List<Product> selectProductListByIds(List<Integer> ids) {
StringBuffer sb = new StringBuffer();
ids.forEach(id -> sb.append("id=" + id + "&"));
return restTemplate.getForObject("http://product-service/product/listByIds?" + sb.toString(), List.class);
}
@Override
public Product selectProductListById(Integer id) {
return restTemplate.getForObject("http://product-service/product/" + id, Product.class);
}
}
@Service
public class OrderServiceImpl implements OrderService{
@Autowired
private ProductService productService;
@Override
public Order selectOrderById(Integer id) {
return new Order(id, "order-001", "中国", 22788D,
productService.selectProductList());
}
@Override
public Order queryOrderById(Integer id) {
return new Order(id, "order-002", "中国", 11600D,
productService.selectProductListByIds(Arrays.asList(1, 2)));
}
@Override
public Order searchOrderById(Integer id) {
return new Order(id, "order-003", "中国", 2666D,
Arrays.asList(productService.selectProductListById(5)));
}
}
6.6 controller
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private OrderService orderService;
@GetMapping("/{id}/product/list")
public Order selectOrderById(@PathVariable("id") Integer id) {
return orderService.selectOrderById(id);
}
@GetMapping("/{id}/product/listByIds")
public Order queryOrderById(@PathVariable("id") Integer id) {
return orderService.queryOrderById(id);
}
@GetMapping("/{id}/product")
public Order searchOrderById(@PathVariable("id") Integer id) {
return orderService.searchOrderById(id);
}
}
搭建完后开启项目,分别访问以下链接,看项目是否搭建成功:
- http://localhost:9090/order/1/product/list
- http://localhost:9090/order/1/product/listByIds
- http://localhost:9090/order/1/product
比如访问:http://localhost:9090/order/1/product
当所有项目启动完后,Eureka的可视化界面如下:
7. 模拟高并发环境
7.1 修改 product-service 模块的controller
使其每次访问时,都先阻塞两秒
try {
TimeUnit.SECONDS.sleep(2); // 阻塞两秒
} catch (InterruptedException e) {
e.printStackTrace();
}
7.2 修改 order-service-rest 模块的application
因为 Tomcat 的默认并发线程数是200,在模拟高并发是不太方便,所以将其修改得较小一点,使其比较容易模拟出高并发的环境
server:
port: 9090
tomcat:
max-threads: 10 # Tomcat 的默认并发线程数是200
因为接下来关于 Hystrix 的学习中,要使用到 Apache 的压力测试工具 JMeter ,可以去看我的另一篇关于 JMeter 的教学使用文章。学习完后,在 JMeter 中添加 http://localhost:9090/order/1/product/list 接口的压力测试