内容:
- rpc调用外部服务时,需要将req和resp的信息打印出来,以便于排查问题。
- 但是有的rpc服务的resp信息过于庞大,比如resp中有List<>信息,list很大很大时
- 会导致log.info打印信息时,产生GC,影响业务
通过将大对象拆分为小对象,解决GC耗时过长问题,进而解决GC过长对业务的影响(TP999过长导致超时、慢sql)等
1、背景
正常情况下,2M、3M就为大对象。会直接被分配至old region。如果此大对象为日志对象,被频繁的加入老年代,会引起Full Gc,影响接口性能或db性能。
2、解决
将大对象,part拆分为小对象再打印,这样young gc更快,影响更小
3、code实现(以List的拆分为例)
@Slf4j
@Component
public class PartLogUtils {
public <V> void partLog(List<V> info,
int count,
Logger logger,
String format) {
List<List<V>> result = splitInfo(info, count);
logInfo(result, logger, format);
}
private <V> List<List<V>> splitInfo(List<V> info, int count) {
List<List<V>> result = Lists.newArrayList();
if (CollectionUtils.isEmpty(info) || info.size() < count) {
result.add(info);
return result;
}
List<V> temp = Lists.newArrayList();
int index = 0;
for (V item : info) {
index++;
temp.add(item);
if (index % count == 0) {
result.add(temp);
temp = Lists.newArrayList();
}
}
if (temp.size() > 0) {
result.add(temp);
}
return result;
}
private <V> void logInfo(List<V> infoList, Logger logger, String format) {
for (V item : infoList) {
logger.info(format, GsonUtils.toJsonStr(item));
}
}
}
类A中使用
private final static Logger logger = LoggerFactory.getLogger(A.class);
PartLogUtils.partLog(resp, 2000, logger,"queryUserInfo:[{}]");