服務容錯保護(Spring Cloud Hystrix)之請求合併
阿新 • • 發佈:2019-02-10
最近在看springCoud微服務實戰,因此做一些看書筆記吧,都是書上例子,方便理解。
微服務架構中依賴遠端呼叫實現服務之間的通訊,所以必然會考慮到通訊消耗與連線數。所以容錯保護提供了HystrixCollapser來實現請求合併。
原始碼在這裡,有空自己看吧。
下面通過例子來幫助自己理解,記下省的以後忘了。
首先:定義一個實體類User,不多說了。
再次:service 和Service的實現類
import com.ribbon.User; import java.util.List; /** * Created by qhe on 2018/7/27. */ public interface UserService { public User find(Long id); public List<User> findAll(List<Long> ids); }
package com.ribbon.user; import com.ribbon.User; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.client.RestTemplate; import java.util.List; /** * Created by qhe on 2018/7/27. */ public class UserServiceImpl implements UserService { @Autowired private RestTemplate restTemplate; @Override public User find(Long id) { return restTemplate.getForObject ("http//user-service/users/{1}",User.class,id); } @Override public List<User> findAll(List<Long> ids) { return restTemplate.getForObject ("http//user-service/users?ids={1}",List.class, StringUtils.join(ids,",")); } } 這裡定義了兩個介面,一個是單個請求,第二個是批量請求,並且用restTemplate實現了遠端呼叫。
然後第一步開始為請求合併實現一個批量請求
package com.ribbon.user; import com.netflix.hystrix.HystrixCommand; import com.ribbon.User; import java.util.List; import static com.netflix.hystrix.HystrixCommandGroupKey.Factory.asKey; /** * Created by qhe on 2018/7/27. */ public class UserBatchCommand extends HystrixCommand<List<User>> { UserService userService; List<Long> userIds; public UserBatchCommand(UserService userService,List<Long> userIds){ super(Setter.withGroupKey(asKey("userBatchCommand"))); this.userIds = userIds; this.userService = userService; } @Override protected List<User> run() throws Exception { return userService.findAll(userIds); } }
這裡實際上就是一個簡單的HystrixCommand實現。
第二步開始實現合併器
package com.ribbon.user;
import com.netflix.hystrix.HystrixCollapser;
import com.netflix.hystrix.HystrixCollapserKey;
import com.netflix.hystrix.HystrixCollapserProperties;
import com.netflix.hystrix.HystrixCommand;
import com.ribbon.User;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
/**
* Created by qhe on 2018/7/27.
*/
public class UserCollapseCommand extends HystrixCollapser<List<User>,User,Long> {
private UserService userService;
private Long userId;
public UserCollapseCommand(UserService userService,Long userId){
super(Setter.withCollapserKey(HystrixCollapserKey.Factory.asKey("userBatchCommand")).andCollapserPropertiesDefaults(
HystrixCollapserProperties.Setter().withTimerDelayInMilliseconds(100)//設定時間延遲屬性
));
this.userService = userService;
this.userId = userId;
}
@Override
public Long getRequestArgument() {
return userId;//返回給定的單個請求引數
}
/**
*collection引數中儲存了延遲時間窗中收集到的所有獲取單個User的請求。
* 通過獲取這些請求的引數來組織上面我們準備的批量請求命令UserBatchCommand例項
* @param collection
* @return
*/
@Override
protected HystrixCommand<List<User>> createCommand(Collection<CollapsedRequest<User, Long>> collection) {
List<Long> userIds = new ArrayList<>(collection.size());
userIds.addAll(collection.stream().map(CollapsedRequest::getArgument).collect(Collectors.toList()));
return new UserBatchCommand(userService,userIds);
}
/**
* 在批量請求命令UserBatchCommand例項被觸發執行完成之後,該方法開始執行,
* 其中users中儲存了creatCommand方法中組織的批量請求命令的返回結果,
* 而collection引數則代表了每個被合併的請求,
* 在這裡我們通過遍歷批量結果users物件,為collection中每個合併前的單個請求設定返回結果,
* 完成批量結果到單個請求結果的轉換
* @param users
* @param collection
*/
@Override
protected void mapResponseToRequests(List<User> users, Collection<CollapsedRequest<User, Long>> collection) {
int count = 0;
for (CollapsedRequest<User,Long> collapsedRequest:collection){
User user = users.get(count++);
collapsedRequest.setResponse(user);
}
}
}
通過合併器,我們可以把多個相同請求合併成一個請求,而這些服務消費者並不用做什麼知道什麼。
上面是通過繼承方式來實現合併,下面通過註解形式來實現,spring的幾乎所有功能都有程式碼實現和註解實現。
package com.ribbon.user;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.ribbon.User;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.List;
/**
* Created by qhe on 2018/7/27.
*/
@Service
public class UserServiceA {
@Autowired
RestTemplate restTemplate;
@HystrixCollapser(batchMethod = "findAll",collapserProperties = {
@HystrixProperty(name="timerDelayInMilliseconds",value = "100")})
public User find(Long id){return null;}
@HystrixCommand
public List<User> findAll(List<Long> ids){
return restTemplate.getForObject("http://user-service/user?ids={1}",List.class, StringUtils.join(ids,","));
}