1.问题描述
2.问题分析
报错消息:A timeout exceeded while waiting to proceed with the request, please reduce your request rate
即 等待处理请求时超时,请降低请求速率。
实际项目中报该错误后,响应了 503 ,还会导致后面对minio的操作全部超时卡住,登录到minio的控制台时也无法打开与加载桶中的文件信息,提示超时错误。
1️⃣ 首先我考虑是不是请求过于频繁的原因,于是在每次对 minio 进行操作前加了500ms休眠,然后再进行请求,但依旧报该错误。说明不是请求频繁的原因。
2️⃣ 后来在报该错误后,我将项目停止运行,发现minio控制台又可以访问了。这时候我就意识到应该是项目中对minio的操作完成后一直挤占了资源,没有关闭流,导致minio由于这些操作一直与项目保持了多个连接。
于是我抽取出项目出错位置的核心代码进行测试:
import io.minio.GetObjectArgs; import io.minio.MinioClient; import java.io.InputStream; /** * @author 狐狸半面添 * @create 2023-02-12 15:06 */ public class MinioDemo { public static void main(String[] args) throws Exception { // Create a minioClient with the MinIO server playground, its access key and secret key. MinioClient minioClient = MinioClient.builder() // 指定连接的ip和端口 .endpoint("http://192.168.65.130:9000") // 指定 访问秘钥(也称用户id) 和 私有秘钥(也称密码) .credentials("minioadmin", "minioadmin") .build(); // 获取桶 String bucket = "waveedu"; // 指定获取文件的路径 String filePath = "林屿森LIN - 小幸运【吉他】 (伴奏).mp3"; try { //======================================================================= for (int i = 1; i < 100; i++) { // 获取输入流 InputStream inputStream = minioClient.getObject( GetObjectArgs .builder() .bucket(bucket) .object(filePath) .build() ); System.out.println("第 " + i + " 次请求完毕"); } //======================================================================= } catch (Exception e) { System.out.println(e.getMessage()); e.printStackTrace(); } } }
果不其然,在循环十二次后卡主,应该是由于前十二次循环没有关闭流,导致minio资源一直被占用,第十三次请求获取输入流超时了。
3.问题解决
通过这个demo就说明了关闭流的重要性,我们修改代码加入对流的关闭再进行测试:
import io.minio.GetObjectArgs; import io.minio.MinioClient; import java.io.InputStream; /** * @author 狐狸半面添 * @create 2023-02-12 15:06 */ public class MinioDemo { public static void main(String[] args) throws Exception { // Create a minioClient with the MinIO server playground, its access key and secret key. MinioClient minioClient = MinioClient.builder() // 指定连接的ip和端口 .endpoint("http://192.168.65.130:9000") // 指定 访问秘钥(也称用户id) 和 私有秘钥(也称密码) .credentials("minioadmin", "minioadmin") .build(); // 获取桶 String bucket = "waveedu"; // 指定获取文件的路径 String filePath = "林屿森LIN - 小幸运【吉他】 (伴奏).mp3"; try { //======================================================================= for (int i = 1; i < 100; i++) { // 获取输入流 InputStream inputStream = minioClient.getObject( GetObjectArgs .builder() .bucket(bucket) .object(filePath) .build() ); // 关闭流 inputStream.close(); System.out.println("第 " + i + " 次请求完毕"); } //======================================================================= } catch (Exception e) { System.out.println(e.getMessage()); e.printStackTrace(); } } }
这时候就没有问题了,能够正常全部循环完。
因此如果你遇到了这个报错,一定要仔细检查自己的代码中是否将所有与外界交互的流及时关闭,一定要自己去手动关闭,而不是等它自己关闭!!!
当我们用了虚拟机以外的资源,比如端口、显存、文件的时候(访问本地资源),超出了虚拟机能够释放资源的界限,这时候虚拟机并不能通过垃圾回收机制对你占用的资源进行释放,如果在没有关闭的情况下第一次运行程序是不会发生问题的,但是随着资源占有量逐渐增多而你又不自己进行close释放资源的话,垃圾只会越积越多,导致系统无法存储其他的资源,甚至会导致系统崩溃。如果你再次对未关闭流的文件进行读写,编译就会报错,告诉你这个文件被占用。