服务容错保护(Spring Cloud Hystrix)之请求合并

最近在看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,","));
    }

猜你喜欢

转载自blog.csdn.net/hq091117/article/details/81233977