在SpringCloud微服务项目中,应公司项目需求,需要将A服务器的大数据(他们给我们oracle数据库地址、用户名密码、视图等信息)转移到公司服务器mysql数据库中。

首先,新加两个服务:分别是获取数据的服务(Spring-Cloud-GetData)、保存数据的服务(Spring-Cloud-SaveData)。

在我的项目中(Spring-Cloud-Web)服务先去调用Spring-Cloud-GetData获取数据的接口,再通过声明式服务调用Spring-Cloud-SaveData保存数据。在此期间,由于数据量太大,导致获取数据后报错:

server.RequestTooBigException: UT000020: Connection terminated as request was larger than 10485760

原因:我的声明式服务调用feign配置了请求压缩

#请求压缩
feign.compression.request.enabled=true
feign.compression.response.enabled=true

但是未指定max-request-size:默认是10485760,对于大数据来说,显然是不够的。

解决:

#请求压缩
feign.compression.request.enabled=true
feign.compression.response.enabled=true
feign.compression.request.mime-types=text/xml,application/xml,application/json
feign.compression.request.min-request-size=2048
feign.compression.request.max-request-size=2097152000

同时,由于数据量大,请求时间肯定要加多一点,不然肯定会被熔断的:

#ribbon请求连接的超时时间- 限制3秒内必须请求到服务,并不限制服务处理的返回时间
ribbon.ConnectTimeout=14400000
#请求处理的超时时间 下级服务响应最大时间,超出时间消费方(路由也是消费方)返回timeout
ribbon.ReadTimeout=14400000

同时,我将需要转移的数据的时间段分割,以达到分批转移的目的:

/**
 * 数据转移 oracle-->mysql
 */
@RequestMapping(value = "/saveStudentData")
public EqResult saveStudentData(@RequestParam String startTime,@RequestParam String endTime) throws Exception{
    EqResult eqResult = new EqResult();
        List<KeyValueForDate> list = SplitDateUtil.getKeyValueForDate(startTime,endTime);
        if(!list.isEmpty()){
            for(KeyValueForDate date : list){
                System.out.println("时间段:"+date.getStartDate()+"--至---"+date.getEndDate()+"--转移开始,第一步获取数据...");
                EqResult<List<Getstudent>> listEqResult = getStudentService.getStudent(date.getStartDate(),date.getEndDate());
                if(CheckUtil.checkEqresultSuccessAndData(listEqResult)){
                    System.out.println("时间段:"+date.getStartDate()+"--至---"+date.getEndDate()+"--转移开始,第二步转移数据...");
                    eqResult = indexService.saveStudent(listEqResult.getData());
                    if(CheckUtil.checkEqresultSuccess(eqResult)){
                        System.out.println("时间段:"+date.getStartDate()+"--至---"+date.getEndDate()+"--转移完成,判断是否进入下一轮...");
                    }else{
                        System.out.println("时间段:"+date.getStartDate()+"--至---"+date.getEndDate()+"--转移失败,第二步未转移数据...");
                    }
                }else{
                    System.out.println("时间段:"+date.getStartDate()+"--至---"+date.getEndDate()+"--转移失败,第一步未获取到数据...");
                }
            }
        }else{
            System.out.println("-----------时间段为空-------------");
        }
        return eqResult;
}

 工具类SplitDateUtil:

public class SplitDateUtil {
 
    @Test
    public void demo(){
        List<KeyValueForDate> list = SplitDateUtil.getKeyValueForDate("2015-08-23","2016-06-10");
        System.out.println("开始日期--------------结束日期");
        for(KeyValueForDate date : list){
            System.out.println(date.getStartDate()+"-----"+date.getEndDate());
        }
    }
 
    /**
     * 根据一段时间区间,按月份拆分成多个时间段
     * @param startDate 开始日期
     * @param endDate  结束日期
     * @return
     */
    @SuppressWarnings("deprecation")
    public static List<KeyValueForDate> getKeyValueForDate(String startDate,String endDate) {
        List<KeyValueForDate> list = null;
        try {
            list = new ArrayList<KeyValueForDate>();
            String firstDay = "";
            String lastDay = "";
            Date d1 = new SimpleDateFormat("yyyy-MM-dd").parse(startDate);// 定义起始日期
            Date d2 = new SimpleDateFormat("yyyy-MM-dd").parse(endDate);// 定义结束日期
            Calendar dd = Calendar.getInstance();// 定义日期实例
            dd.setTime(d1);// 设置日期起始时间
            Calendar cale = Calendar.getInstance();
            Calendar c = Calendar.getInstance();
            c.setTime(d2);
            int startDay = d1.getDate();
            int endDay = d2.getDate();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            KeyValueForDate keyValueForDate = null;
            while (dd.getTime().before(d2)) {// 判断是否到结束日期
                keyValueForDate = new KeyValueForDate();
                cale.setTime(dd.getTime());
                if(dd.getTime().equals(d1)){
                    cale.set(Calendar.DAY_OF_MONTH, dd.getActualMaximum(Calendar.DAY_OF_MONTH));
                    lastDay = sdf.format(cale.getTime());
                    keyValueForDate.setStartDate(sdf.format(d1));
                    keyValueForDate.setEndDate(lastDay);
                }else if(dd.get(Calendar.MONTH) == d2.getMonth() && dd.get(Calendar.YEAR) == c.get(Calendar.YEAR)){
                    cale.set(Calendar.DAY_OF_MONTH,1);//取第一天
                    firstDay = sdf.format(cale.getTime());
                    keyValueForDate.setStartDate(firstDay);
                    keyValueForDate.setEndDate(sdf.format(d2));
                }else {
                    cale.set(Calendar.DAY_OF_MONTH,1);//取第一天
                    firstDay = sdf.format(cale.getTime());
                    cale.set(Calendar.DAY_OF_MONTH, dd.getActualMaximum(Calendar.DAY_OF_MONTH));
                    lastDay = sdf.format(cale.getTime());
                    keyValueForDate.setStartDate(firstDay);
                    keyValueForDate.setEndDate(lastDay);
                }
                list.add(keyValueForDate);
                dd.add(Calendar.MONTH, 1);// 进行当前日期月份加1
            }
            if(endDay<startDay){
                keyValueForDate = new KeyValueForDate();
                cale.setTime(d2);
                cale.set(Calendar.DAY_OF_MONTH,1);//取第一天
                firstDay = sdf.format(cale.getTime());
                keyValueForDate.setStartDate(firstDay);
                keyValueForDate.setEndDate(sdf.format(d2));
                list.add(keyValueForDate);
            }
        } catch (Exception e) {
            return null;
        }
        return list;
    }
 
}

 实体类KeyValueForDate:

public class KeyValueForDate{
    private String startDate;
    private String endDate;
    public String getStartDate() {
        return startDate;
    }
    public void setStartDate(String startDate) {
        this.startDate = startDate;
    }
    public String getEndDate() {
        return endDate;
    }
    public void setEndDate(String endDate) {
        this.endDate = endDate+" 23:59:59";
    }
}

备注,到这里我已经成功解决了所有问题,同时,将我在网上找的解决方案提供参考(未解决我的项目需求):

#限制3000MB大小
spring.http.multipart.max-file-size=3000MB
spring.http.multipart.max-request-size=3000MB
server.max-http-post-size=1048576000
spring.sleuth.keys.http.request-size=1048576000
spring.sleuth.keys.http.response-size=1048576000
server.max-http-header-size=1048576000

# 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理
# 每块buffer的空间大小,越小的空间被利用越充分,不要设置太大,以免影响其他应用,合适即可

server.undertow.buffer-size=2048
server.undertow.max-http-post-size=1048576000
# 每个区分配的buffer数量 , 所以pool的大小是buffer-size * buffers-per-region

server.undertow.buffers-per-region=2048

# 是否分配的直接内存(NIO直接分配的堆外内存)

 到了这里,你还不点赞吗?    嘻嘻^-^ 

 

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐