sringcloud2.0学习-12-服务雪崩效应与Feign客户端超时配置

服务雪崩效应

1.什么是服务雪崩效应

   默认情况下,tomcat只有一个线程池去处理客户端的所有请求,这时候如果在高并发情况下,所有的请求全部访问同一个接口,导致tomcat线程池的所有线程都去处理这个一个接口服务,如果线程池的所有线程都被占用了,这时候会导致其他接口请求没有可用的线程来请求,新来的接口请求直接无响应,这就是服务雪崩效应效应。
服务雪崩可能会造成连环雪崩效应,最终导致整个微服务系统不可用

tomcat8线程池中最大活跃线程数默认是200 ?

2.服务雪崩演示

在这里插入图片描述
上图中,订单服务order 的/orderToMemberUserInfo接口通过Feign客户端调用 member服务 /getUserInfo接口,在/getUserInfo接口中,设置睡眠1.5秒之后再返回结果,修改order服务的线程池最大活跃线程数量,通过jmeter发起测试

2.1 演示代码
  • MemberServiceImpl
package com.lchtest.api.service.impl;

import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.lchtest.api.entity.UserEntity;
import com.lchtest.api.service.IMemberService;
import com.lchtest.common.base.BaseApiService;
import com.lchtest.common.base.ResponseBase;
/**
 * memberService的业务实现
 * @author pc
 *
 */
@RestController
public class MemberServiceImpl extends BaseApiService implements IMemberService {

	@Value("${server.port}")
	private String serverPort;

	@GetMapping("/")
	public String index(HttpServletRequest req) {
		System.out.println("我是首页.....");
		return "我是member服务" + serverPort;
	}
	
	@RequestMapping("/getMember")
	@Override
	public UserEntity getMember(String name) {
		UserEntity userEntity = new UserEntity();
		userEntity.setName(name);
		return userEntity;
	}

	
	// 测试服务雪崩效应,这里模拟接口处理延迟
	@RequestMapping("/getUserInfo")
	@Override
	public ResponseBase getUserInfo() {
		try {
			System.out.println("进入memberservice-getUserInfo(),开始处理/getUserInfo接口请求");
			// 会员服务接口产生1.5s延迟
			Thread.sleep(1500);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return setResultSuccess("订单服务接口调用会员服务接口成功.");
	}
}
  • Order服务相关代码:
    yaml配置文件 :设置最大活跃线程数为10;配置Feign客户端超时时间
#服务启动端口号
server:
  port: 8005
  #设置最多同时10个线程去处理请求
  tomcat:
    max-threads: 10
#服务名称(服务注册到eureka名称)  
spring:
    application:
        name: app-order
#服务注册到eureka地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8100/eureka        
    #把自己注册到注册中心
    register-with-eureka: true
    # 从eureka上获取注册信息
    fetch-registry: true
ribbon:
  # 不设置超时时间,调用会员服务1.5s延时的接口时会报 redaTimeOut 错误
  # 建立连接后从服务器读取到可用资源所用的时间
  ReadTimeout: 5000
  # 建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间 
  ConnectionTimeout: 5000

Feign客户端 MemberServiceFeign

package com.lchtest.api.feign;

import org.springframework.cloud.openfeign.FeignClient;
import com.lchtest.api.entity.UserEntity;
import com.lchtest.api.service.IMemberService;

/**
 * Feign客户端定义,继承IMemberService,这样就可以避免类似下面这样的重复代码了: @RequestMapping("/getMember")
 * public UserEntity getMember(String name);
 * 
 * @author pc
 *
 */
@FeignClient(name = "app-member")
public interface MemberServiceFeign extends IMemberService {
}

member服务接口项目中的接口定义:

public interface IMemberService {

	// 实体类放在接口项目里面比较好,可能其他项目也会依赖该实体类,代码实现放到接口的实现里面
	@RequestMapping("/getMember")
	public UserEntity getMember(@RequestParam("name") String name);
	
	@RequestMapping("/getUserInfo")
	public ResponseBase getUserInfo();
}

Order服务接口定义:

package com.lchtest.api.service;

import org.springframework.web.bind.annotation.RequestMapping;

import com.lchtest.common.base.ResponseBase;

public interface IOrderService {
	// 订单服务调用会员服务接口
	@RequestMapping("/orderToMember")
	public String orderToMember(String name);

	// 订单服务调用会员服务接口
	@RequestMapping("/orderToMemberUserInfo")
	public ResponseBase orderToUserInfo();
	
	@RequestMapping("/orderInfo")
	public ResponseBase orderInfo();

}

ordder服务接口实现:OrderServiceImpl

package com.lchtest.api.service.impl;

import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.lchtest.api.entity.UserEntity;
import com.lchtest.api.feign.MemberServiceFeign;
import com.lchtest.api.service.IOrderService;
import com.lchtest.common.base.BaseApiService;
import com.lchtest.common.base.ResponseBase;


/**
 * 订单服务继承会员服务接口,用来实现Feign客户端,减少重复接口代码!
 * 
 * @author pc
 *
 */
@RestController
public class OrderServiceImpl extends BaseApiService implements IOrderService {

	@Autowired
	private MemberServiceFeign memberServiceFeign;
	
	@Value("${server.port}")
	private String serverPort;

	@GetMapping("/")
	public String index(HttpServletRequest req) {
		System.out.println("我是首页.....");
		return "我是order服务" + serverPort;
	}

	/**
	 * http://localhost:8005/orderToMember?name=admin
	 */
	@RequestMapping("/orderToMember")
	@Override
	public String orderToMember(String name) {
		UserEntity user = memberServiceFeign.getMember(name);
		return user == null ? "no user find" : user.toString();
	}

	/**
	 * 测试服务雪崩效应 -没有解决雪崩效应 对该接口在member服务中的实现设置延迟时间,假设该接口需要1.5s才能处理完
	 * 没有com.lchtest.api.fallback.MemberServiceFallback这个类的情况下
	 * @return
	 */
	@RequestMapping("/orderToMemberUserInfo")
	public ResponseBase orderToUserInfo() {
		System.out.println("orderToMemberUserInfo: 当前线程池名称" + Thread.currentThread().getName());
		return memberServiceFeign.getUserInfo();
	}

	
	@RequestMapping("/getOrderInfo")
	public String getOrderInfo() {
		System.out.println("getOrderInfo: 当前线程池名称" + Thread.currentThread().getName());
		return "getOrderInfo success.";
	}

	// 订单服务接口
	@Override
	public ResponseBase orderInfo() {
		return setResultSuccess();
	}

}

启动类:

package com.lchtest.api;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients //开启Feign客户端
//@EnableHystrix  //开启服务熔断
public class AppOrder {
	public static void main(String[] args) {
		SpringApplication.run(AppOrder.class, args);
	}
}

代码准备完毕,启动uereka注册中心,member服务,order服务,测试order接口正常:
在这里插入图片描述

2.2 jmeter设置以及服务雪崩效应演示
  • 启动jmeter,设置线程数,压测的接口等参数
    在
    双击启动jmeter,右键单击测试计划,点击添加->Threads-> 线程组,设置并发量:
    在这里插入图片描述在这里插入图片描述
    order服务设置tomcat能够同时处理请求的数量为10
    在这里插入图片描述
    右键单击之前创建的线程组,点击添加-> Sampler -> Http请求,创建http请求:
    在这里插入图片描述
    在这里插入图片描述
    点击绿色三角形按钮,开始压测:
    在这里插入图片描述
    然后浏览器打开调试模式,去访问没有延时的接口http://localhost:8005/getOrderInfo,可以看到这个接口迟迟不能响应,浏览器一直转圈,并提示正在等待localhost的响应,这种现象就是服务雪崩效应。
3. Feign客户端超时时间配置

SpringCloud Feign客户端默认开启ribbon(可以启动两个member服务,通过order服务调用member服务查看是否有负载均衡),并且默认超时时间为1s ,当Feign客户端调用一个接口时,如果接口在1s内没有能够及时返回响应,那么Feign客户端会报read time out错误:
在这里插入图片描述

可以设置Feign客户端超时时间来解决上面的报错,如下:

###设置feign客户端超时时间
ribbon:
###指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间。
 ReadTimeout: 5000
###指的是建立连接后从服务器读取到可用资源所用的时间。 
 ConnectTimeout: 5000

代码地址
使用到的项目:
springcloud2.0-eureak-server
springcloud2.0-feign-parent

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值