SpringCloud之大資料轉移RequestTooBigException:Connection terminated as request was larger than 10485760
阿新 • • 發佈:2018-11-09
在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直接分配的堆外記憶體)
到了這裡,你還不點贊嗎? 嘻嘻^-^