(十四)java版spring cloud微服务架构b2b2c电子商务平台-Hystrix项目中使用

一、公共类、不是必须的

package com.xxx.xxx.xxx.data.command.dubbo;

import com.netflix.hystrix.*;

public abstract class AbstractDubboCommand<T> extends HystrixCommand<T> {

    /**
     * @param commandKey
     */
    public AbstractDubboCommand(String commandKey) {
        super(DubboCommandSetter.setter(commandKey));
    }

    @Override
    public T getFallback(){
        //判断熔断器是否打开
        if(super.isCircuitBreakerOpen()){
            alert();
        }
        return fallback();
    }

    /**
     * 当熔断器打开时,报警。报警间隔时间为5分钟
     */
    public abstract void alert();

    /**
     * 降级处理
     * @return
     */
    public abstract T fallback();

    public boolean needCache(){
        return false;
    }
}

熔断器的设置

package com.xxx.xxx.xxx.data.command.dubbo;

import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommand.Setter;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixCommandKey;
import com.netflix.hystrix.HystrixCommandProperties;
import com.netflix.hystrix.HystrixThreadPoolKey;
import com.netflix.hystrix.HystrixThreadPoolProperties;
/**
 * Comand公共参数的设置
 *
 * @author liweihan
 * @time 2017-12-20 16:53
 */
public class DubboCommandSetter {

    public static Setter setter(String commandKeyName,String threadPoolKeyName) {
        return setter("DubboGroup",commandKeyName,threadPoolKeyName);
    }

    public static Setter setter(String commandKeyName) {
        return setter(commandKeyName,"Dubbo-Pool");
    }

    /**
     * @author liweihan
     * @time 2017/12/20 16:57
     * @description     相关参数设置
     * @param groupKeyName      服务分组名
     * @param commandKeyName    服务标识名称
     * @param threadPoolKeyName 线程池名称
     * @return
     */
    public static Setter setter(String groupKeyName,String commandKeyName,String threadPoolKeyName) {
        //服务分组
        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(groupKeyName);
        //服务标识
        HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey(commandKeyName);
        //线程池名称
        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(threadPoolKeyName);
        //线程配置
        HystrixThreadPoolProperties.Setter threadPoolProperties = HystrixThreadPoolProperties.Setter()
                .withCoreSize(150)
                .withKeepAliveTimeMinutes(5)
                .withMaxQueueSize(Integer.MAX_VALUE)
                .withQueueSizeRejectionThreshold(10000)
                ;

        //命令属性的配置
        HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter()
                .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)
//                .withExecutionIsolationThreadInterruptOnTimeout(true)
                .withExecutionTimeoutInMilliseconds(3000) //设置超时时间为3秒进入Fallback
                .withCircuitBreakerErrorThresholdPercentage(30)//失败率达到30%自动熔断
                .withRequestCacheEnabled(false);

        //返回
        return HystrixCommand.Setter
                .withGroupKey(groupKey)
				.andCommandKey(commandKey)
                .andThreadPoolKey(threadPoolKey)
                .andThreadPoolPropertiesDefaults(threadPoolProperties)
                .andCommandPropertiesDefaults(commandProperties);
    }

}

获得基础信息-Album的Command类

package com.xxx.xxx.xxx.data.command.dubbo;

import com.xxx.xxx.xxx.service.ServiceManager;
import com.xxx.xxx.xxx.util.CommonUtil;
import com.xxx.xxx.xxx.util.SerializationUtil;
import com.xxx.xxx.xxx.util.WxSmsUtils;
import com.xxx.xxx.xxx.midware.dubbo.api.dto.AlbumInfoDto;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author liweihan
 * @time 2017/10/12 15:12
 * @description 获取PGC/UGC专辑基础信息!
 */
public class GetAlbumInfoByDubboCommand extends AbstractDubboCommand<AlbumInfoDto> {
    public static final Logger logger = LoggerFactory.getLogger(GetAlbumInfoByDubboCommand.class);
    Long aid;
    ServiceManager serviceManager;

    public GetAlbumInfoByDubboCommand(Long aid , ServiceManager serviceManager) {
        super("GetAlbumInfo");
        this.aid = aid;
        this.serviceManager=serviceManager;
    }
    @Override
    public AlbumInfoDto fallback() {
        String key = String.format(CommonUtil.Get_AlbumInfo_ByDubbo, aid);
        logger.info(" GetAlbumInfoByDubboCommand from dubbo fail,key:{}",key);
        byte[] obj =  serviceManager.getRedisClusterHyStrix().getBytes(key);
        try {
            AlbumInfoDto albumInfoDto =  (AlbumInfoDto)SerializationUtil.bytes2Object(obj);
            return albumInfoDto;
        }catch  (Exception e) {
            logger.error(" ====== GetAlbumInfoByDubboCommand from Hystrix'fallback error,key:{} . Exception:{}" ,key,e);
        }
        return null;
    }

    @Override
    protected AlbumInfoDto run() throws Exception {
        AlbumInfoDto albumInfoDto = null;
        long beginTime = System.currentTimeMillis();
        try {
            /**
             * http://mwiki.sohuno.com/pages/viewpage.action?pageId=32866496
             */
            albumInfoDto = serviceManager.getDubboAlbumService().albumInfo(aid,0,"","17");
        } catch (Exception e) {
            logger.error(" ====== GetAlbumInfoByDubboCommand ,调用dubbo出错!aid:{}",aid,e);
        }
        //统计一下该dubbo的访问次数
//        incr("dubbo_album");
        long endTime  = System.currentTimeMillis();
        if ((endTime - beginTime) > CommonUtil.TIME_OUT_DUBBO) {
            //统计一下该dubbo超时的访问次数
//            incr("dubbo_album_timeout");
            logger.warn(" ====== GetAlbumInfoByDubboCommand ,调用dubbo时间久!beginTime:{},endTime:{},cosTime:{},dubbo返回:{},aid:{}",
                    beginTime,endTime,(endTime-beginTime),albumInfoDto != null ? albumInfoDto.getReturnCode() : "null",aid);
        }
        if (albumInfoDto == null) {
            return fallback();
        }
        String key = String.format(CommonUtil.Get_AlbumInfo_ByDubbo, aid);
        if (albumInfoDto.getReturnCode() == 0) {
            serviceManager.getRedisClusterHyStrix().setex(key, CommonUtil.timeout, SerializationUtil.object2Bytes(albumInfoDto));
        } else {
            logger.info(" ====== GetAlbumInfoByDubboCommand,获取专辑信息时,dubbo返回:{},aid:{}",albumInfoDto.getReturnCode(),aid);
            serviceManager.getRedisClusterHyStrix().del(key); //不等于0说明专辑失效或删除,需要删除hystrix的缓存
        }
        return albumInfoDto;
    }

    @Override
    public void alert() {
        logger.error(" ================================================== GetAlbumInfoByDubboCommand into CircuitBreaker");
        String key = "AlbumInfo";
        if (StringUtils.isEmpty(serviceManager.getRedisClusterHyStrix().get(key))) {
            WxSmsUtils.getInstance().warnByWx("AlbumInfo-Into-[CircuitBreaker]");
            serviceManager.getRedisClusterHyStrix().setex(key,CommonUtil.WARN_WX_TIMEOUT,key);
        }
    }

    /**
     * @author liweihan
     * @time 2017/11/13 17:12
     * @description     统计一下某个dubbo方法的次数
     * @param key
     */
    public void incr(String key) {
        try {
            serviceManager.getRedisCluster().incr(key);
        } catch (Exception e) {
            logger.error(" ====== redis操作出现异常!key:{}",key,e);
        }
    }
}

获得基础信息-UserInfo的Command类

package com.xxx.xxx.xxx.data.command.dubbo;

import com.xxx.xxx.xxx.service.ServiceManager;
import com.xxx.xxx.xxx.util.CommonUtil;
import com.xxx.xxx.xxx.util.SerializationUtil;
import com.xxx.xxx.xxx.util.WxSmsUtils;
import com.xxx.xxx.xxx.midware.dubbo.api.dto.UserInfoDto;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author liweihan
 * @time 2017/10/11 15:12
 * @description 获取PGC/UGC用户基础信息!
 */
public class GetUserInfoByDubboCommand extends AbstractDubboCommand<UserInfoDto> {
    public static final Logger logger = LoggerFactory.getLogger(GetUserInfoByDubboCommand.class);
    Long userId;
    ServiceManager serviceManager;

    public GetUserInfoByDubboCommand(Long userId , ServiceManager serviceManager) {
        super("GetUserInfo");
        this.userId = userId;
        this.serviceManager=serviceManager;
    }
    @Override
    public UserInfoDto fallback() {
        String key = String.format(CommonUtil.Get_UserInfo_ByDubbo, userId);
        logger.info(" GetUserInfoByDubboCommand from dubbo fail,key:{}",key);
        byte[] obj =  serviceManager.getRedisClusterHyStrix().getBytes(key);
        try {
            UserInfoDto userInfoDto =  (UserInfoDto)SerializationUtil.bytes2Object(obj);
            return userInfoDto;
        }catch  (Exception e) {
            logger.error(" ====== GetUserInfoByDubboCommand from Hystrix'fallback error,key:{} . Exception:{}" ,key,e);
        }
        return null;
    }

    @Override
    protected UserInfoDto run() throws Exception {
        UserInfoDto userInfoDto = null;
        long beginTime = System.currentTimeMillis();
        try {
            /**
             * http://mwiki.sohuno.com/pages/viewpage.action?pageId=32866496
             */
            userInfoDto = serviceManager.getDubboUserService().userInfo(userId);
        } catch (Exception e) {
            logger.error(" ====== GetUserInfoByDubboCommand ,调用dubbo出错!userId:{}",userId,e);
        }
        //统计一下该dubbo的访问次数
//        incr("dubbo_userinfo");
        long endTime = System.currentTimeMillis();
        if ((endTime - beginTime) > CommonUtil.TIME_OUT_DUBBO_300) {
            //统计一下该dubbo的访问次数
//            incr("dubbo_userinfo_timeout");
            logger.warn(" ====== GetUserInfoByDubboCommand ,调用dubbo时间久!beginTime:{},endTime:{},cosTime:{},dubbo返回:{},userId:{}",
                    beginTime,endTime,(endTime-beginTime),userInfoDto != null ? userInfoDto.getReturnCode() : "null",userId);
        }
        if (userInfoDto == null) {
            return fallback();
        }
        String key = String.format(CommonUtil.Get_UserInfo_ByDubbo, userId);
        if (userInfoDto.getReturnCode() == 0) {
            serviceManager.getRedisClusterHyStrix().setex(key, CommonUtil.timeout, SerializationUtil.object2Bytes(userInfoDto));
        } else {
            logger.info(" ====== GetUserInfoByDubboCommand,获取用户信息时,dubbo返回:{},userId:{}",userInfoDto.getReturnCode(),userId);
            serviceManager.getRedisClusterHyStrix().del(key);
        }
        return userInfoDto;
    }

    @Override
    public void alert() {
        logger.error(" ================================================== GetUserInfoByDubboCommand into CircuitBreaker");
        String key = "GetUserInfo";
        if (StringUtils.isEmpty(serviceManager.getRedisClusterHyStrix().get(key))) {
            WxSmsUtils.getInstance().warnByWx("GetUserInfo-Into-[CircuitBreaker]");
            serviceManager.getRedisClusterHyStrix().setex(key,CommonUtil.WARN_WX_TIMEOUT,key);
        }
    }

    /**
     * @author liweihan
     * @time 2017/11/13 17:12
     * @description     统计一下某个dubbo方法的次数
     * @param key
     */
    public void incr(String key) {
        try {
            serviceManager.getRedisCluster().incr(key);
        } catch (Exception e) {
            logger.error(" ====== redis操作出现异常!key:{}",key,e);
        }
    }
}

再其他的类也是类似的用法,你可以调用Http,RPC等第三方接口!写法都是类似的。

此处熔断后,进入Fallback读取备用缓存数据,如果缓存没有的话,再给用户返回null。这是一种策略。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值