一、公共類、不是必須的
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。這是一種策略。