同事反馈使用只要下载文件,日志中会打印Fatal glibc error: cannot get entropy for arc4random,之后系统自动重启,下载文件失败。
直接搜索Fatal glibc error: cannot get entropy for arc4random并未得到太多的有效信息。baidu和google还有bing我都尝试了。我是一个地道 的搜索引擎工程师。
查到一种方案为使用rngd自动补充熵池,尝试没有效果,无法解决。
继续排查,项目工程代码如下:
@GetMapping("/export")
@Operation(summary = "数据导出")
public void export(CableTunnelQueryParam queryParam, HttpServletResponse response) throws IOException {
log.info("start export:{}", JSONObject.toJSONString(queryParam));
try {
List<CableTunnelDO> list = cableTunnelService.listAll(queryParam);
// 输出
ExcelUtils.write(response,
"附件.xls",
"数据",
CableTunnelVO.class,
BeanUtils.toBean(list, CableTunnelVO.class));
} catch (Exception e) {
log.error("导出excel失败", e);
}
log.info("end export:{}", JSONObject.toJSONString(queryParam));
}
ExcelUtils.write代码如下
public static <T> void write(HttpServletResponse response, String filename, String sheetName,
Class<T> head, List<T> data, List<KeyValue<ExcelColumn, List<String>>> selectMap) throws IOException {
// 输出 Excel
EasyExcel.write(response.getOutputStream(), head)
.autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 基于 column 长度,自动适配。最大 255 宽度
.registerWriteHandler(new SelectSheetWriteHandler(selectMap)) // 基于固定 sheet 实现下拉框
.registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度
.sheet(sheetName).doWrite(data);
// 设置 header 和 contentType。写在最后的原因是,避免报错时,响应 contentType 已经被修改了
response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, StandardCharsets.UTF_8.name()));
response.setContentType("application/vnd.ms-excel;charset=UTF-8");
}
该代码在windows下运行正常。查看服务日志只打印了【start export】这行日志,后面的【导出excel失败】和【end export】均未打印,在【start export】后输出了一句Fatal glibc error: cannot get entropy for arc4random,紧接着系统无法访问,开始了自动重启。
在Docker宿主机和虚机内执行以下代码都可以正常获取随机数
cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n1
cat /dev/random | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n1
Dockerfile文件中已经使用了-Djava.security.egd=file:/dev/./urandom 代码如下
CMD java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar app.jar
之后在Docker启动中也增加了-v /dev/urandom:/dev/random
问题仍未解决。
我就是个java开发,对C还有C++并不了解,对glibc 和arc4random也不清楚是啥。随后便尝试切换了jdk镜像文件进行解决。
原镜像文件使用的是eclipse-temurin:8-jre,更新为openjdk:8-jdk-alpine
正常启动后,导出Excel报如下错误:
java.lang.NullPointerException: null
at sun.awt.FontConfiguration.getVersion(FontConfiguration.java:1264)
at sun.awt.FontConfiguration.readFontConfigFile(FontConfiguration.java:219)
at sun.awt.FontConfiguration.init(FontConfiguration.java:107)
at sun.awt.X11FontManager.createFontConfiguration(X11FontManager.java:774)
at sun.font.SunFontManager$2.run(SunFontManager.java:431)
at java.security.AccessController.doPrivileged(Native Method)
at sun.font.SunFontManager.<init>(SunFontManager.java:376)
at sun.awt.FcFontManager.<init>(FcFontManager.java:35)
at sun.awt.X11FontManager.<init>(X11FontManager.java:57)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.lang.Class.newInstance(Class.java:442)
at sun.font.FontManagerFactory$1.run(FontManagerFactory.java:83)
at java.security.AccessController.doPrivileged(Native Method)
at sun.font.FontManagerFactory.getInstance(FontManagerFactory.java:74)
网上查找原因:
根据报错信息是缺少某个字体,而docker打包镜像默认是没有该字体;或者因为使用了openjdk而没有使用oraclejdk,缺少依赖。
在Dockerfile中增加以下代码,重新打包运行成功。
RUN apk add --update;apk add ttf-dejavu;apk add fontconfig
问题解决。
对于Fatal glibc error: cannot get entropy for arc4random的根本原因我没有找到。如果有大佬了解什么原因还请指教。
关于为什么-Djava.security.egd=file:/dev/./urandom 中/dev/./urandom中有一个".",原因是这里是jdk中的一个bug,在这个bug的连接里有人反馈及时对securerandom.source设置为/dev/urandom它也仍然使用的/dev/random,有人提供了变通的解决方法,其中一个变通的做法是对securerandom.source,设置为/dev/./urandom才行
关于openjdk:8-jdk-alpine 参考
https://zhuanlan.zhihu.com/p/667075764
关于rngd补充熵池:
参考: