Linux問題 open too many files

部署到linux下的tomcat,今天發現包了“java.net.SocketException: Too many open files”,以前從來沒有遇到過,在此記錄一下:

徹底解決問題的是第三步, 所以,可以直接跳到第三步去看解決方法和步驟,當日第一、第二步是我不斷探索,嘗試解決問題的過程,雖然沒有找到點上,但是還是有些意義的,因爲linux切實有打開資源數量的限制,肯定需要修改的。

異常信息:

Java代碼 複製代碼 收藏代碼
  1. ............  
  2. Oct 17, 2011 5:22:41 PM org.apache.tomcat.util.net.JIoEndpoint$Acceptor run  
  3. SEVERE: Socket accept failed  
  4. java.net.SocketException: Too many open files  
  5.         at java.net.PlainSocketImpl.socketAccept(Native Method)  
  6.         at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:375)  
  7.         at java.net.ServerSocket.implAccept(ServerSocket.java:470)  
  8.         at java.net.ServerSocket.accept(ServerSocket.java:438)  
  9.         at org.apache.tomcat.util.net.DefaultServerSocketFactory.acceptSocket(DefaultServerSocketFactory.java:59)  
  10.         at org.apache.tomcat.util.net.JIoEndpoint$Acceptor.run(JIoEndpoint.java:210)  
  11.         at java.lang.Thread.run(Thread.java:636)  
  12. Oct 17, 2011 5:22:43 PM org.apache.tomcat.util.net.JIoEndpoint$Acceptor run  
  13. SEVERE: Socket accept failed  
  14. java.net.SocketException: Too many open files  
  15.         at java.net.PlainSocketImpl.socketAccept(Native Method)  
  16.         at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:375)  
  17.         at java.net.ServerSocket.implAccept(ServerSocket.java:470)  
  18.         at java.net.ServerSocket.accept(ServerSocket.java:438)  
  19.         at org.apache.tomcat.util.net.DefaultServerSocketFactory.acceptSocket(DefaultServerSocketFactory.java:59)  
  20.         at org.apache.tomcat.util.net.JIoEndpoint$Acceptor.run(JIoEndpoint.java:210)  
  21.         at java.lang.Thread.run(Thread.java:636)  
  22. Oct 17, 2011 5:22:44 PM org.apache.tomcat.util.net.JIoEndpoint$Acceptor run  
  23. SEVERE: Socket accept failed  
  24. java.net.SocketException: Too many open files  
  25.         at java.net.PlainSocketImpl.socketAccept(Native Method)  
  26.         at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:375)  
  27.         at java.net.ServerSocket.implAccept(ServerSocket.java:470)  
  28.         at java.net.ServerSocket.accept(ServerSocket.java:438)  
  29.         at org.apache.tomcat.util.net.DefaultServerSocketFactory.acceptSocket(DefaultServerSocketFactory.java:59)  
  30.         at org.apache.tomcat.util.net.JIoEndpoint$Acceptor.run(JIoEndpoint.java:210)  
  31.         at java.lang.Thread.run(Thread.java:636)  
  32. ............ 
  1. ............ 
  2. Oct 17, 2011 5:22:41 PM org.apache.tomcat.util.net.JIoEndpoint$Acceptor run 
  3. SEVERE: Socket accept failed 
  4. java.net.SocketException: Too many open files 
  5.         at java.net.PlainSocketImpl.socketAccept(Native Method) 
  6.         at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:375
  7.         at java.net.ServerSocket.implAccept(ServerSocket.java:470
  8.         at java.net.ServerSocket.accept(ServerSocket.java:438
  9.         at org.apache.tomcat.util.net.DefaultServerSocketFactory.acceptSocket(DefaultServerSocketFactory.java:59
  10.         at org.apache.tomcat.util.net.JIoEndpoint$Acceptor.run(JIoEndpoint.java:210
  11.         at java.lang.Thread.run(Thread.java:636
  12. Oct 17, 2011 5:22:43 PM org.apache.tomcat.util.net.JIoEndpoint$Acceptor run 
  13. SEVERE: Socket accept failed 
  14. java.net.SocketException: Too many open files 
  15.         at java.net.PlainSocketImpl.socketAccept(Native Method) 
  16.         at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:375
  17.         at java.net.ServerSocket.implAccept(ServerSocket.java:470
  18.         at java.net.ServerSocket.accept(ServerSocket.java:438
  19.         at org.apache.tomcat.util.net.DefaultServerSocketFactory.acceptSocket(DefaultServerSocketFactory.java:59
  20.         at org.apache.tomcat.util.net.JIoEndpoint$Acceptor.run(JIoEndpoint.java:210
  21.         at java.lang.Thread.run(Thread.java:636
  22. Oct 17, 2011 5:22:44 PM org.apache.tomcat.util.net.JIoEndpoint$Acceptor run 
  23. SEVERE: Socket accept failed 
  24. java.net.SocketException: Too many open files 
  25.         at java.net.PlainSocketImpl.socketAccept(Native Method) 
  26.         at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:375
  27.         at java.net.ServerSocket.implAccept(ServerSocket.java:470
  28.         at java.net.ServerSocket.accept(ServerSocket.java:438
  29.         at org.apache.tomcat.util.net.DefaultServerSocketFactory.acceptSocket(DefaultServerSocketFactory.java:59
  30.         at org.apache.tomcat.util.net.JIoEndpoint$Acceptor.run(JIoEndpoint.java:210
  31.         at java.lang.Thread.run(Thread.java:636
  32. ............ 

原因:
   linux下有有文件限制,結果文件數操作最大限制,導致程序異常:問題是程序中有個靜態方法打開文件時忘記關閉。兩種解決方法,一是設置linux的最大文件打開數量(無法根本解決問題),二是解決程序中的bugs,即消除有問題的代碼。

第一次解決
解決:
方法一、增大系統打開文件的數量(無法根本解決問題)、
   1、默認linux同時最大打開文件數量爲1024個,用命令查看如下:ulimit -a:查看系統上受限資源的設置(open files (-n) 1024):

Java代碼 複製代碼 收藏代碼
  1. [root@**** bin]# ulimit -a  
  2. core file size          (blocks, -c) 0 
  3. data seg size           (kbytes, -d) unlimited  
  4. scheduling priority             (-e) 0 
  5. file size               (blocks, -f) unlimited  
  6. pending signals                 (-i) 16384 
  7. max locked memory       (kbytes, -l) 32 
  8. max memory size         (kbytes, -m) unlimited  
  9. open files                      (-n) 1024 
  10. pipe size            (512 bytes, -p) 8 
  11. POSIX message queues     (bytes, -q) 819200 
  12. real-time priority              (-r) 0 
  13. stack size              (kbytes, -s) 10240 
  14. cpu time               (seconds, -t) unlimited  
  15. max user processes              (-u) 16384 
  16. virtual memory          (kbytes, -v) unlimited  
  17. file locks                      (-x) unlimited  
  18. [root@**** bin]# 
  1. [root@**** bin]# ulimit -a 
  2. core file size          (blocks, -c) 0 
  3. data seg size           (kbytes, -d) unlimited 
  4. scheduling priority             (-e) 0 
  5. file size               (blocks, -f) unlimited 
  6. pending signals                 (-i) 16384 
  7. max locked memory       (kbytes, -l) 32 
  8. max memory size         (kbytes, -m) unlimited 
  9. open files                      (-n) 1024 
  10. pipe size            (512 bytes, -p) 8 
  11. POSIX message queues     (bytes, -q) 819200 
  12. real-time priority              (-r) 0 
  13. stack size              (kbytes, -s) 10240 
  14. cpu time               (seconds, -t) unlimited 
  15. max user processes              (-u) 16384 
  16. virtual memory          (kbytes, -v) unlimited 
  17. file locks                      (-x) unlimited 
  18. [root@**** bin]# 

2、可以修改同時打開文件的最大數基本可以解決:ulimit -n 4096

Java代碼 複製代碼 收藏代碼
  1. [root@**** bin]# ulimit -n 4096 
  2. [root@**** bin]# ulimit -a  
  3. core file size          (blocks, -c) 0 
  4. data seg size           (kbytes, -d) unlimited  
  5. scheduling priority             (-e) 0 
  6. file size               (blocks, -f) unlimited  
  7. pending signals                 (-i) 16384 
  8. max locked memory       (kbytes, -l) 32 
  9. max memory size         (kbytes, -m) unlimited  
  10. open files                      (-n) 4096 
  11. pipe size            (512 bytes, -p) 8 
  12. POSIX message queues     (bytes, -q) 819200 
  13. real-time priority              (-r) 0 
  14. stack size              (kbytes, -s) 10240 
  15. cpu time               (seconds, -t) unlimited  
  16. max user processes              (-u) 16384 
  17. virtual memory          (kbytes, -v) unlimited  
  18. file locks                      (-x) unlimited  
  19. [root@**** bin]# 
  1. [root@**** bin]# ulimit -n 4096 
  2. [root@**** bin]# ulimit -a 
  3. core file size          (blocks, -c) 0 
  4. data seg size           (kbytes, -d) unlimited 
  5. scheduling priority             (-e) 0 
  6. file size               (blocks, -f) unlimited 
  7. pending signals                 (-i) 16384 
  8. max locked memory       (kbytes, -l) 32 
  9. max memory size         (kbytes, -m) unlimited 
  10. open files                      (-n) 4096 
  11. pipe size            (512 bytes, -p) 8 
  12. POSIX message queues     (bytes, -q) 819200 
  13. real-time priority              (-r) 0 
  14. stack size              (kbytes, -s) 10240 
  15. cpu time               (seconds, -t) unlimited 
  16. max user processes              (-u) 16384 
  17. virtual memory          (kbytes, -v) unlimited 
  18. file locks                      (-x) unlimited 
  19. [root@**** bin]# 

已經修改了最大打開文件數。

方法二、修改程序中的bugs:
程序中有個靜態的方法打開文件後,沒有關閉文件,導致每次請求都會去打開文件,在程序中填入關閉輸入流的操作即可以:
Java代碼 複製代碼 收藏代碼
  1. public static List<GpsPoint> getArrayList() throws IOException {  
  2.  
  3.         List<GpsPoint> pointList = null;  
  4.         // 讀取配置文件  
  5.         InputStream in = ParseGpsFile.class.getClassLoader().getResourceAsStream("GPS1.TXT");  
  6.           
  7.         // 讀路徑出錯,換另一種方式讀取配置文件  
  8.         if (null == in) {  
  9.               
  10.             System.out.println("讀取文件失敗");  
  11.               
  12.             return pointList;  
  13.         }  
  14.           
  15.         pointList = new ArrayList<GpsPoint>();  
  16.           
  17.         try {  
  18.             BufferedReader br = new BufferedReader(new InputStreamReader(in));  
  19.             String longtude = "";  
  20.             String latude = "";  
  21.             String elevation = "";  
  22.             while ((longtude = br.readLine()) != null) {  
  23.                   
  24.                 // 讀下一行數據,讀緯度  
  25.                 latude = br.readLine();  
  26.                   
  27.                 if (null == latude) {  
  28.                       
  29.                     // 退出循環  
  30.                     break;  
  31.                 }  
  32.                   
  33.                 // 讀下一行數據,讀海拔  
  34.                 elevation = br.readLine();  
  35.                 if (null == latude) {  
  36.                       
  37.                     // 退出循環  
  38.                     break;  
  39.                 }  
  40.                   
  41.                 // 加入一個點  
  42.                 pointList.add(gps2point(longtude, latude, elevation));  
  43.             }  
  44.               
  45.             in.close();  
  46.             System.out.println("\n\n");  
  47.         } catch (Exception e) {  
  48.               
  49.             in.close();  
  50.             e.printStackTrace();  
  51.         }  
  52.           
  53.         return pointList;  
  54.     } 
  1. public static List<GpsPoint> getArrayList() throws IOException { 
  2.  
  3.         List<GpsPoint> pointList = null
  4.         // 讀取配置文件 
  5.         InputStream in = ParseGpsFile.class.getClassLoader().getResourceAsStream("GPS1.TXT"); 
  6.          
  7.         // 讀路徑出錯,換另一種方式讀取配置文件 
  8.         if (null == in) { 
  9.              
  10.             System.out.println("讀取文件失敗"); 
  11.              
  12.             return pointList; 
  13.         } 
  14.          
  15.         pointList = new ArrayList<GpsPoint>(); 
  16.          
  17.         try
  18.             BufferedReader br = new BufferedReader(new InputStreamReader(in)); 
  19.             String longtude = ""
  20.             String latude = ""
  21.             String elevation = ""
  22.             while ((longtude = br.readLine()) != null) { 
  23.                  
  24.                 // 讀下一行數據,讀緯度 
  25.                 latude = br.readLine(); 
  26.                  
  27.                 if (null == latude) { 
  28.                      
  29.                     // 退出循環 
  30.                     break
  31.                 } 
  32.                  
  33.                 // 讀下一行數據,讀海拔 
  34.                 elevation = br.readLine(); 
  35.                 if (null == latude) { 
  36.                      
  37.                     // 退出循環 
  38.                     break
  39.                 } 
  40.                  
  41.                 // 加入一個點 
  42.                 pointList.add(gps2point(longtude, latude, elevation)); 
  43.             } 
  44.              
  45.             in.close(); 
  46.             System.out.println("\n\n"); 
  47.         } catch (Exception e) { 
  48.              
  49.             in.close(); 
  50.             e.printStackTrace(); 
  51.         } 
  52.          
  53.         return pointList; 
  54.     } 


問題徹底解決

-----
第二次解決:
實際測試後發現這個問題還沒有解決,最終又找了些方法,經過一段時間的測試,似乎解決了問題:

具體步驟如下:
linux爲redhat服務器版本(非個人版),必須設置的內容:

1、/etc/pam.d/login 添加
Java代碼 複製代碼 收藏代碼
  1. session required     /lib/security/pam_limits.so 
  1. session required     /lib/security/pam_limits.so 

# 注意看這個文件的註釋
具體文件的內容爲:
Java代碼 複製代碼 收藏代碼
  1. [root@**** ~]# vi /etc/pam.d/login  
  2. #%PAM-1.0 
  3. auth [user_unknown=ignore success=ok ignore=ignore default=bad] pam_securetty.so  
  4. auth       include      system-auth  
  5. account    required     pam_nologin.so  
  6. account    include      system-auth  
  7. password   include      system-auth  
  8. # pam_selinux.so close should be the first session rule  
  9. session    required     pam_selinux.so close  
  10. session    optional     pam_keyinit.so force revoke  
  11. session    required     pam_loginuid.so  
  12. session    include      system-auth  
  13. session    optional     pam_console.so  
  14. # pam_selinux.so open should only be followed by sessions to be executed in the user context  
  15. session    required     pam_selinux.so open  
  16.  
  17. ~  
  18. "/etc/pam.d/login" 15L, 644C 
  1. [root@**** ~]# vi /etc/pam.d/login 
  2. #%PAM-1.0 
  3. auth [user_unknown=ignore success=ok ignore=ignore default=bad] pam_securetty.so 
  4. auth       include      system-auth 
  5. account    required     pam_nologin.so 
  6. account    include      system-auth 
  7. password   include      system-auth 
  8. # pam_selinux.so close should be the first session rule 
  9. session    required     pam_selinux.so close 
  10. session    optional     pam_keyinit.so force revoke 
  11. session    required     pam_loginuid.so 
  12. session    include      system-auth 
  13. session    optional     pam_console.so 
  14. # pam_selinux.so open should only be followed by sessions to be executed in the user context 
  15. session    required     pam_selinux.so open 
  16.  
  17. "/etc/pam.d/login" 15L, 644C 

修改後的內容:

Java代碼 複製代碼 收藏代碼
  1. -bash: [root@****: command not found  
  2. [root@**** ~]# clear  
  3. [root@**** ~]# cat /etc/pam.d/login  
  4. #%PAM-1.0 
  5. auth [user_unknown=ignore success=ok ignore=ignore default=bad] pam_securetty.so  
  6. auth       include      system-auth  
  7. account    required     pam_nologin.so  
  8. account    include      system-auth  
  9. password   include      system-auth  
  10. # pam_selinux.so close should be the first session rule  
  11. session    required     pam_selinux.so close  
  12. session    optional     pam_keyinit.so force revoke  
  13. session    required     pam_loginuid.so  
  14. session    include      system-auth  
  15. session    optional     pam_console.so  
  16. # pam_selinux.so open should only be followed by sessions to be executed in the user context  
  17. session    required     pam_selinux.so open  
  18. # kevin.xie added, fixed 'too many open file' bug, limit open max files 1024, 2011-10-24 
  19. session required     /lib/security/pam_limits.so  
  20.  
  21. [root@**** ~]# 
  1. -bash: [root@****: command not found 
  2. [root@**** ~]# clear 
  3. [root@**** ~]# cat /etc/pam.d/login 
  4. #%PAM-1.0 
  5. auth [user_unknown=ignore success=ok ignore=ignore default=bad] pam_securetty.so 
  6. auth       include      system-auth 
  7. account    required     pam_nologin.so 
  8. account    include      system-auth 
  9. password   include      system-auth 
  10. # pam_selinux.so close should be the first session rule 
  11. session    required     pam_selinux.so close 
  12. session    optional     pam_keyinit.so force revoke 
  13. session    required     pam_loginuid.so 
  14. session    include      system-auth 
  15. session    optional     pam_console.so 
  16. # pam_selinux.so open should only be followed by sessions to be executed in the user context 
  17. session    required     pam_selinux.so open 
  18. # kevin.xie added, fixed 'too many open file' bug, limit open max files 1024, 2011-10-24 
  19. session required     /lib/security/pam_limits.so 
  20.  
  21. [root@**** ~]# 

2. /etc/security/limits.conf 添加
Java代碼 複製代碼 收藏代碼
  1. root          –    nofile       1006154 
  1. root          –    nofile       1006154 

root 是一個用戶,如果是想所有用戶生效的話換成 * ,設置的數值與硬件配置有關,別設置太大了。
修改前內容
Java代碼 複製代碼 收藏代碼
  1. [root@**** ~]# cat /etc/security/limits.conf  
  2. # /etc/security/limits.conf  
  3. #  
  4. #Each line describes a limit for a user in the form:  
  5. #  
  6. #<domain>        <type>  <item>  <value>  
  7. #  
  8. #Where:  
  9. #<domain> can be:  
  10. #        - an user name  
  11. #        - a group name, with @group syntax  
  12. #        - the wildcard *, for default entry  
  13. #        - the wildcard %, can be also used with %group syntax,  
  14. #                 for maxlogin limit  
  15. #  
  16. #<type> can have the two values:  
  17. #        - "soft" for enforcing the soft limits  
  18. #        - "hard" for enforcing hard limits  
  19. #  
  20. #<item> can be one of the following:  
  21. #        - core - limits the core file size (KB)  
  22. #        - data - max data size (KB)  
  23. #        - fsize - maximum filesize (KB)  
  24. #        - memlock - max locked-in-memory address space (KB)  
  25. #        - nofile - max number of open files  
  26. #        - rss - max resident set size (KB)  
  27. #        - stack - max stack size (KB)  
  28. #        - cpu - max CPU time (MIN)  
  29. #        - nproc - max number of processes  
  30. #        - as - address space limit  
  31. #        - maxlogins - max number of logins for this user  
  32. #        - maxsyslogins - max number of logins on the system  
  33. #        - priority - the priority to run user process with  
  34. #        - locks - max number of file locks the user can hold  
  35. #        - sigpending - max number of pending signals  
  36. #        - msgqueue - max memory used by POSIX message queues (bytes)  
  37. #        - nice - max nice priority allowed to raise to  
  38. #        - rtprio - max realtime priority  
  39. #  
  40. #<domain>      <type>  <item>         <value>  
  41. #  
  42.  
  43. #*               soft    core            0 
  44. #*               hard    rss             10000 
  45. #@student        hard    nproc           20 
  46. #@faculty        soft    nproc           20 
  47. #@faculty        hard    nproc           50 
  48. #ftp             hard    nproc           0 
  49. #@student        -       maxlogins       4 
  50.  
  51. # End of file  
  52. [root@**** ~]#  
  53. [root@**** ~]# cat /etc/security/limits.conf  
  54. # /etc/security/limits.conf  
  55. #  
  56. #Each line describes a limit for a user in the form:  
  57. #  
  58. #<domain>        <type>  <item>  <value>  
  59. #  
  60. #Where:  
  61. #<domain> can be:  
  62. #        - an user name  
  63. #        - a group name, with @group syntax  
  64. #        - the wildcard *, for default entry  
  65. #        - the wildcard %, can be also used with %group syntax,  
  66. #                 for maxlogin limit  
  67. #  
  68. #<type> can have the two values:  
  69. #        - "soft" for enforcing the soft limits  
  70. #        - "hard" for enforcing hard limits  
  71. #  
  72. #<item> can be one of the following:  
  73. #        - core - limits the core file size (KB)  
  74. #        - data - max data size (KB)  
  75. #        - fsize - maximum filesize (KB)  
  76. #        - memlock - max locked-in-memory address space (KB)  
  77. #        - nofile - max number of open files  
  78. #        - rss - max resident set size (KB)  
  79. #        - stack - max stack size (KB)  
  80. #        - cpu - max CPU time (MIN)  
  81. #        - nproc - max number of processes  
  82. #        - as - address space limit  
  83. #        - maxlogins - max number of logins for this user  
  84. #        - maxsyslogins - max number of logins on the system  
  85. #        - priority - the priority to run user process with  
  86. #        - locks - max number of file locks the user can hold  
  87. #        - sigpending - max number of pending signals  
  88. #        - msgqueue - max memory used by POSIX message queues (bytes)  
  89. #        - nice - max nice priority allowed to raise to  
  90. #        - rtprio - max realtime priority  
  91. #  
  92. #<domain>      <type>  <item>         <value>  
  93. #  
  94.  
  95. #*               soft    core            0 
  96. #*               hard    rss             10000 
  97. #@student        hard    nproc           20 
  98. #@faculty        soft    nproc           20 
  99. #@faculty        hard    nproc           50 
  100. #ftp             hard    nproc           0 
  101. #@student        -       maxlogins       4 
  102. # kevin.xie added, fixed 'too many open file' bug, limit open max files 1024, 2011-10-24 
  103. * - nofile 102400 
  104.  
  105. # End of file  
  106. [root@**** ~]# 
  1. [root@**** ~]# cat /etc/security/limits.conf 
  2. # /etc/security/limits.conf 
  3. #Each line describes a limit for a user in the form: 
  4. #<domain>        <type>  <item>  <value> 
  5. #Where: 
  6. #<domain> can be: 
  7. #        - an user name 
  8. #        - a group name, with @group syntax 
  9. #        - the wildcard *, for default entry 
  10. #        - the wildcard %, can be also used with %group syntax, 
  11. #                 for maxlogin limit 
  12. #<type> can have the two values: 
  13. #        - "soft" for enforcing the soft limits 
  14. #        - "hard" for enforcing hard limits 
  15. #<item> can be one of the following: 
  16. #        - core - limits the core file size (KB) 
  17. #        - data - max data size (KB) 
  18. #        - fsize - maximum filesize (KB) 
  19. #        - memlock - max locked-in-memory address space (KB) 
  20. #        - nofile - max number of open files 
  21. #        - rss - max resident set size (KB) 
  22. #        - stack - max stack size (KB) 
  23. #        - cpu - max CPU time (MIN) 
  24. #        - nproc - max number of processes 
  25. #        - as - address space limit 
  26. #        - maxlogins - max number of logins for this user 
  27. #        - maxsyslogins - max number of logins on the system 
  28. #        - priority - the priority to run user process with 
  29. #        - locks - max number of file locks the user can hold 
  30. #        - sigpending - max number of pending signals 
  31. #        - msgqueue - max memory used by POSIX message queues (bytes) 
  32. #        - nice - max nice priority allowed to raise to 
  33. #        - rtprio - max realtime priority 
  34. #<domain>      <type>  <item>         <value> 
  35.  
  36. #*               soft    core            0 
  37. #*               hard    rss             10000 
  38. #@student        hard    nproc           20 
  39. #@faculty        soft    nproc           20 
  40. #@faculty        hard    nproc           50 
  41. #ftp             hard    nproc           0 
  42. #@student        -       maxlogins       4 
  43.  
  44. # End of file 
  45. [root@**** ~]# 
  46. [root@**** ~]# cat /etc/security/limits.conf 
  47. # /etc/security/limits.conf 
  48. #Each line describes a limit for a user in the form: 
  49. #<domain>        <type>  <item>  <value> 
  50. #Where: 
  51. #<domain> can be: 
  52. #        - an user name 
  53. #        - a group name, with @group syntax 
  54. #        - the wildcard *, for default entry 
  55. #        - the wildcard %, can be also used with %group syntax, 
  56. #                 for maxlogin limit 
  57. #<type> can have the two values: 
  58. #        - "soft" for enforcing the soft limits 
  59. #        - "hard" for enforcing hard limits 
  60. #<item> can be one of the following: 
  61. #        - core - limits the core file size (KB) 
  62. #        - data - max data size (KB) 
  63. #        - fsize - maximum filesize (KB) 
  64. #        - memlock - max locked-in-memory address space (KB) 
  65. #        - nofile - max number of open files 
  66. #        - rss - max resident set size (KB) 
  67. #        - stack - max stack size (KB) 
  68. #        - cpu - max CPU time (MIN) 
  69. #        - nproc - max number of processes 
  70. #        - as - address space limit 
  71. #        - maxlogins - max number of logins for this user 
  72. #        - maxsyslogins - max number of logins on the system 
  73. #        - priority - the priority to run user process with 
  74. #        - locks - max number of file locks the user can hold 
  75. #        - sigpending - max number of pending signals 
  76. #        - msgqueue - max memory used by POSIX message queues (bytes) 
  77. #        - nice - max nice priority allowed to raise to 
  78. #        - rtprio - max realtime priority 
  79. #<domain>      <type>  <item>         <value> 
  80.  
  81. #*               soft    core            0 
  82. #*               hard    rss             10000 
  83. #@student        hard    nproc           20 
  84. #@faculty        soft    nproc           20 
  85. #@faculty        hard    nproc           50 
  86. #ftp             hard    nproc           0 
  87. #@student        -       maxlogins       4 
  88. # kevin.xie added, fixed 'too many open file' bug, limit open max files 1024, 2011-10-24 
  89. * - nofile 102400 
  90.  
  91. # End of file 
  92. [root@**** ~]# 

修改後的內容
Java代碼 複製代碼 收藏代碼
  1.  
  1. </pre>3. 修改 /etc/rc.local   添加 <div class="dp-highlighter"><div class="bar"><div class="tools">Java代碼 <a title="複製代碼" href="http://xieyanhua.iteye.com/blog/1198708#"><img alt="複製代碼" src="http://xieyanhua.iteye.com/images/icon_copy.gif" /></a> <a title="收藏這段代碼" href="http://xieyanhua.iteye.com/blog/1198708"><img class="star" alt="收藏代碼" src="http://xieyanhua.iteye.com/images/icon_star.png" /><img style="DISPLAY: none" class="spinner" src="http://xieyanhua.iteye.com/images/spinner.gif" alt="" /></a></div></div><ol class="dp-j"><li><span><span>echo </span><span class="number">8061540</span><span> > /proc/sys/fs/file-max  </span></span></li></ol></div><pre style="DISPLAY: none" class="java" title="MINA2 錯誤解決方法-- Linux下tomcat報錯“java.net.SocketException: Too many open files”" name="code" codeable_id="1198708" codeable_type="Blog" source_url="http://xieyanhua.iteye.com/blog/1198708" pre_index="10">echo 8061540 > /proc/sys/fs/file-max 

修改前內容
Java代碼 複製代碼 收藏代碼
  1. [root@**** ~]# cat /proc/sys/fs/file-max  
  2. 4096 
  3. [root@**** ~]# 
  1. [root@**** ~]# cat /proc/sys/fs/file-max 
  2. 4096 
  3. [root@**** ~]# 

修改後內容
Java代碼 複製代碼 收藏代碼
  1. [root@**** ~]# cat /proc/sys/fs/file-max  
  2. 4096000 
  3. [root@**** ~]# 
  1. [root@**** ~]# cat /proc/sys/fs/file-max 
  2. 4096000 
  3. [root@**** ~]# 

做完3個步驟,就可以了。


**************************************
補充說明:
/proc/sys/fs/file-max
該文件指定了可以分配的文件句柄的最大數目。如果用戶得到的錯誤消息聲明由於打開文件數已經達到了最大值,從而他們不能打開更多文件,則可能需要增加該值。可將這個值設置成有任意多個文件,並且能通過將一個新數字值寫入該文件來更改該值。
缺省設置:4096
/proc/sys/fs/file-nr
該文件與 file-max 相關,它有三個值:
已分配文件句柄的數目
已使用文件句柄的數目
文件句柄的最大數目
該文件是隻讀的,僅用於顯示信息。
關於“打開文件數”限制
Linux系統上對每一個用戶可使用的系統資源都是有限制的,這是多用戶系統必然要採用的一種資源管理手段,試想假如沒有這種機制,那麼任何一個普通用戶寫一個死循環程序,用不了多久系統就要“拒絕服務”了。
今天我遇到了tomcat日誌報的錯誤信息”too many open files”,第一意識就想到了是ulimit控制的”open files“限制。然而問題來了。我在/etc/profile里加入了 ulimit -n 4096保存之後,普通用戶登錄的時候均會收到一條錯誤信息ulimit: open files: cannot modify limit: Operation not permitted。然後普通用戶的open files限制還是默認值1024。
然後開始在互聯網上搜索關於ulimit的信息。互聯網果然方便,信息鋪天蓋地。大家也可以搜一下試一下。其中我瞭解到兩個以前不知道的相關內容。
第一個是內核參數 fs.file-max  ,影射爲 /proc/sys/fs/file-max
第二個是配置文件 /etc/security/limits.conf
其中大部分的信息中提到 將 /proc/sys/fs/file-max的值設置爲4096和ulimit -n 4096是相同的效果。對此我很懷疑,爲什麼呢?首先ulimit 是一個普通用戶也可以使用的命令,而fs.file-max只有root有權設置。其次,很明顯fs.file-max是一個全局的設置,而ulimit 是一個局部的設置,很明顯的是不相同的。
帶着疑慮,又在網上搜索了許久,未果(實際上是我搜索的關鍵字不夠準確)。
最後終於在內核文檔/usr/src/linux/Documentation/sysctl/fs.txt裏找到下面一段話:
file-max & file-nr:
The kernel allocates file handles dynamically, but as yet it doesn’t free them again. The value in file-max denotes the maximum number of file-handles that the Linux kernel will allocate. When you get lots of error messages about running out of file handles, you might want to increase this limit.
The three values in file-nr denote the number of allocated file handles, the number of unused file handles and the maximum number of file handles. When the allocated file handles come close to the maximum, but the number of unused file handles is significantly greater than 0, you’ve encountered a peak in your usage of file handles and you don’t need to increase the maximum.
這兩段話的大致意思是:
內核動態地分配和釋放“file handles”(句柄)。file-max的值是內核所能分配到的最大句柄數。當你收到大量關於句柄用完的錯誤信息時,你可以需要增加這個值以打破老的限制。
file-nr中的三個值的含意分別是:系統已經分配出去(正在使用)的句柄數,沒有用到的句柄數和所有分配到的最大句柄數。當分配出去的句柄數接近 最大句柄數,而“無用的句柄數”大於零時,表明你遇到了一個“句柄”使用高峯,這意爲着你不需要增加file-max的值。
看完這段話,相信大家都明白了。file-max是系統全局的可用句柄數。根據我後來又翻查的信息,以及對多個系統的查看求證,這個參數的默認值是跟內存大小有關係的,增加物理內存以後重啓機器,這個值會增大。大約1G內存10萬個句柄的線性關係。
再回過頭來看這兩段話,不知道你意識到了沒有,文中只提到了file-max的增加,而沒有提到了該值的減少。那些在操作ulimit時同時操 作了file-max的哥們兒,估計無一例外地將file-max設置成了4096或者2048。但以似乎也沒有因此而導致系統無法打開文件或者建議連 接。(實際上,我將file-max的值設備成256,然後使用shell編寫用vi打開500個文件角本運行,並沒有得到任何錯誤信息,查看file- nr的值,系統當前分配的句柄值已經遠超過了後面的最大值。所以我猜想對於file-max的任何減少的操作都是毫無意義的,姑且不去管他。實踐中需要減 少file-max的時候總是不多見的。 )實事證明我犯了一個致命的錯誤。我測試的時候使用的是root用戶,而當我再次使用普通用戶測試的時候,預料中的錯誤信息出現了:”Too many open files in system”。可見,file-max的減少對系統也是影響力的。前面的結論“所以我猜想對於file-max的任何減少的操作都是毫無意義的”是錯誤 的。
然後便是/etc/security/limits.conf文件,這個文件很簡單,一看就能明白。
於是我按照註釋中描述的格式兩個兩行:
*  soft  nofile  4096
*  hard  nofile  4096
恐怖的是,網上居然有人說改了這個設置是需要重啓系統的!實在是讓人想不通啊,鼎鼎大名的UNIX系統,怎麼可能因爲這麼小小的一個改動就需要 重啓系統呢?結果當我再次以普通用戶登錄的時候,那個”ulimit: open files: cannot modify limit: Operation not permitted”提示沒有了,查看ulimit -n,果然已經變成了4096。
linux lsof 修改句柄限制(轉)
在Linux下,我們使用ulimit -n 命令可以看到單個進程能夠打開的最大文件句柄數量(socket連接也算在裏面)。系統默認值1024。
對於一般的應用來說(象Apache、系統進程)1024完全足夠使用。但是如何象squid、mysql、java等單進程處理大量請求的應用來說就有點捉襟見肘了。如果單個進程打開的文件句柄數量超過了系統定義的值,就會提到“too many files open”的錯誤提示。如何知道當前進程打開了多少個文件句柄呢?下面一段小腳本可以幫你查看:
lsof -n |awk ‘{print $2}’|sort|uniq -c |sort -nr|more
在系統訪問高峯時間以root用戶執行上面的腳本,可能出現的結果如下:
# lsof -n|awk ‘{print $2}’|sort|uniq -c |sort -nr|more
131 24204
57 24244
57 24231
56 24264
其中第一行是打開的文件句柄數量,第二行是進程號。得到進程號後,我們可以通過ps命令得到進程的詳細內容。
ps -aef|grep 24204
mysql 24204 24162 99 16:15 ? 00:24:25 /usr/sbin/mysqld
哦,原來是mysql進程打開最多文件句柄數量。但是他目前只打開了131個文件句柄數量,遠遠底於系統默認值1024。
但是如果系統併發特別大,尤其是squid服務器,很有可能會超過1024。這時候就必須要調整系統參數,以適應應用變化。Linux有硬性限制和軟性限制。可以通過ulimit來設定這兩個參數。方法如下,以root用戶運行以下命令:
ulimit -HSn 4096
以上命令中,H指定了硬性大小,S指定了軟性大小,n表示設定單個進程最大的打開文件句柄數量。個人覺得最好不要超過4096,畢竟打開的文件句柄數越多響應時間肯定會越慢。設定句柄數量後,系統重啓後,又會恢復默認值。如果想永久保存下來,可以修改.bash_profile文件,可以修改 /etc/profile 把上面命令加到最後。



仍未處理的問題:
爲什麼redhat9的個人版按照以上的方式修改1024tcp連接限制依然不行呢?
是因爲個人版最多支持1024個tcp連接,還是修改方式、相關文件會有所不同?

以上內容,來源網絡並加自己親自測試,經過測試,似乎沒有再出現過問題,但不知道是否真的解決,有待更長時間的測試看看

第三次解決--還解決不了,就徹底無語了(經過壓力測試,運行7天再也沒有出現該問題)
問題的原因是
:原來的MINA2程序之關了IoSession,並沒有關閉IoConnector實例,但恰恰就是因爲沒有關閉每次打開的IoConnector實例,造成了"Too many open files ".
原來的程序:
Java代碼 複製代碼 收藏代碼
  1. /** 
  2.      * <pre><b>功能描述:</b>獲取異步的session實例。 
  3.      *  
  4.      * @author :Kevin.xie 
  5.      * <b>創建日期 :</b>2011-9-15 上午10:06:27 
  6.      * 
  7.      * @return 
  8.      * 
  9.      * <b>修改歷史:</b>(修改人,修改時間,修改原因/內容) 
  10.      * 
  11.      * </pre> 
  12.      */    
  13.     public static IoSession getSession1() {    
  14.     
  15.         // 創建客戶端連接器    
  16.         IoConnector connector = new NioSocketConnector();    
  17.         // 設置事件處理器    
  18.         connector.setHandler(new WebClientHandler());    
  19.         // 設置編碼過濾器和按行讀取數據模式    
  20.         connector.getFilterChain()    
  21.                 .addLast("codec", new ProtocolCodecFilter(new ObdDemuxingProtocolCodecFactory(false)));    
  22.         // 創建連接    
  23.         ConnectFuture future = connector.connect(new InetSocketAddress(ServerConfigBoundle.getServerIp(),    
  24.                 ServerConfigBoundle.getServerPort()));    
  25.         // 等待連接創建完成    
  26.         future.awaitUninterruptibly();    
  27.         // 獲取連接會話    
  28.         IoSession session = future.getSession();    
  29.             
  30.         return session;    
  31.     }    
  32.     
  33.    /** 
  34.      * <pre><b>功能描述:</b>必須要關閉Connector和IoSession
  35.      * @author :Kevin.xie 
  36.      * <b>創建日期 :</b>2011-10-20 上午10:20:54 
  37.      * 
  38.      * @param session 要關閉的session 
  39.      * 
  40.      * <b>修改歷史:</b>(修改人,修改時間,修改原因/內容) 
  41.      * 
  42.      * </pre> 
  43.      */    
  44.     public static void closeSession(IoSession session) {    
  45.     
  46.         if (session != null && !session.isClosing()) {    
  47.                 
  48.             // 沒有關閉,就關閉    
  49.             session.close(true);    
  50.             session = null;    
  51.         }    
  52.     }  
  1. /**
  2.      * <pre><b>功能描述:</b>獲取異步的session實例。
  3.      * 
  4.      * @author :Kevin.xie
  5.      * <b>創建日期 :</b>2011-9-15 上午10:06:27
  6.      *
  7.      * @return
  8.      *
  9.      * <b>修改歷史:</b>(修改人,修改時間,修改原因/內容)
  10.      *
  11.      * </pre>
  12.      */   
  13.     public static IoSession getSession1() {   
  14.    
  15.         // 創建客戶端連接器   
  16.         IoConnector connector = new NioSocketConnector();   
  17.         // 設置事件處理器   
  18.         connector.setHandler(new WebClientHandler());   
  19.         // 設置編碼過濾器和按行讀取數據模式   
  20.         connector.getFilterChain()   
  21.                 .addLast("codec", new ProtocolCodecFilter(new ObdDemuxingProtocolCodecFactory(false)));   
  22.         // 創建連接   
  23.         ConnectFuture future = connector.connect(new InetSocketAddress(ServerConfigBoundle.getServerIp(),   
  24.                 ServerConfigBoundle.getServerPort()));   
  25.         // 等待連接創建完成   
  26.         future.awaitUninterruptibly();   
  27.         // 獲取連接會話   
  28.         IoSession session = future.getSession();   
  29.            
  30.         return session;   
  31.     }   
  32.    
  33.    /**
  34.      * <pre><b>功能描述:</b>必須要關閉Connector和IoSession
  35.      * @author :Kevin.xie
  36.      * <b>創建日期 :</b>2011-10-20 上午10:20:54
  37.      *
  38.      * @param session 要關閉的session
  39.      *
  40.      * <b>修改歷史:</b>(修改人,修改時間,修改原因/內容)
  41.      *
  42.      * </pre>
  43.      */   
  44.     public static void closeSession(IoSession session) {   
  45.    
  46.         if (session != null && !session.isClosing()) {   
  47.                
  48.             // 沒有關閉,就關閉   
  49.             session.close(true);   
  50.             session = null;   
  51.         }   
  52.     }  

修改後的程序
Java代碼 複製代碼 收藏代碼
  1. /** 
  2.      *  
  3.      * <pre><b>功能描述:</b>獲取IoConnector和異步的session實例
  4.      * 無法關閉。特別的提醒,NioSocketConnector 也要關閉。 
  5.      * 函數名是 dispose()。這點特別重要。這次出現 too many open files 的問題根源在這裏
  6.      *  
  7.      * @author :Kevin.xie 
  8.      * <b>創建日期 :</b>2011-9-15 上午10:06:27 
  9.      * 
  10.      * @return 
  11.      * 
  12.      * <b>修改歷史:</b>(修改人,修改時間,修改原因/內容) 
  13.      * 
  14.      * </pre> 
  15.      */    
  16.     public static Map<String, Object> getConnectorAndSession() {    
  17.     
  18.         // 創建客戶端連接器    
  19.         IoConnector connector = new NioSocketConnector();    
  20.         // 設置事件處理器    
  21.         connector.setHandler(new WebClientHandler());    
  22.         // 設置編碼過濾器和按行讀取數據模式    
  23.         connector.getFilterChain()    
  24.                 .addLast("codec", new ProtocolCodecFilter(new ObdDemuxingProtocolCodecFactory(false)));    
  25.         // 創建連接    
  26.         ConnectFuture future = connector.connect(new InetSocketAddress(ServerConfigBoundle.getServerIp(),    
  27.                 ServerConfigBoundle.getServerPort()));    
  28.         // 等待連接創建完成    
  29.         future.awaitUninterruptibly();    
  30.         // 獲取連接會話    
  31.         IoSession session = future.getSession();    
  32.             
  33.         Map<String, Object> map = new HashMap<String, Object>();    
  34.         map.put(CONNECTOR_KEY, connector);    
  35.         map.put(SESSION_KEY, session);    
  36.             
  37.         return map;    
  38.     }    
  39.     
  40. /** 
  41.      *  
  42.      * <pre><b>功能描述:</b>必須要關閉Connector和IoSession
  43.      * 特別的提醒,NioSocketConnector 也要關閉。 
  44.      * 函數名是 dispose()。這點特別重要。這次出現 too many open files 的問題根源在這裏
  45.      * @author :Kevin.xie 
  46.      * <b>創建日期 :</b>2011-10-20 上午10:20:54 
  47.      * 
  48.      * @param connector 要關閉的IoConnector,不關閉會報 too many open files 錯誤
  49.      * @param session 要關閉的session 
  50.      * 
  51.      * <b>修改歷史:</b>(修改人,修改時間,修改原因/內容) 
  52.      * 
  53.      * </pre> 
  54.      */    
  55.     public static void closeConnectorAndSession(IoConnector connector, IoSession session) {    
  56.     
  57.         if (session != null && !session.isClosing()) {    
  58.                 
  59.             // 沒有關閉,就關閉    
  60.             session.close(true);    
  61.             session = null;    
  62.         }    
  63.             
  64.         if (connector != null && !(connector.isDisposing() || connector.isDisposed())) {    
  65.                 
  66.             // 沒有關閉,就關閉    
  67.             connector.dispose();    
  68.             connector = null;    
  69.         }    
  70.     }    
  71. ]   
  1. /**
  2.      * 
  3.      * <pre><b>功能描述:</b>獲取IoConnector和異步的session實例
  4.      * 無法關閉。特別的提醒,NioSocketConnector 也要關閉。
  5.      * 函數名是 dispose()。這點特別重要。這次出現 too many open files 的問題根源在這裏
  6.      * 
  7.      * @author :Kevin.xie
  8.      * <b>創建日期 :</b>2011-9-15 上午10:06:27
  9.      *
  10.      * @return
  11.      *
  12.      * <b>修改歷史:</b>(修改人,修改時間,修改原因/內容)
  13.      *
  14.      * </pre>
  15.      */   
  16.     public static Map<String, Object> getConnectorAndSession() {   
  17.    
  18.         // 創建客戶端連接器   
  19.         IoConnector connector = new NioSocketConnector();   
  20.         // 設置事件處理器   
  21.         connector.setHandler(new WebClientHandler());   
  22.         // 設置編碼過濾器和按行讀取數據模式   
  23.         connector.getFilterChain()   
  24.                 .addLast("codec", new ProtocolCodecFilter(new ObdDemuxingProtocolCodecFactory(false)));   
  25.         // 創建連接   
  26.         ConnectFuture future = connector.connect(new InetSocketAddress(ServerConfigBoundle.getServerIp(),   
  27.                 ServerConfigBoundle.getServerPort()));   
  28.         // 等待連接創建完成   
  29.         future.awaitUninterruptibly();   
  30.         // 獲取連接會話   
  31.         IoSession session = future.getSession();   
  32.            
  33.         Map<String, Object> map = new HashMap<String, Object>();   
  34.         map.put(CONNECTOR_KEY, connector);   
  35.         map.put(SESSION_KEY, session);   
  36.            
  37.         return map;   
  38.     }   
  39.    
  40. /**
  41.      * 
  42.      * <pre><b>功能描述:</b>必須要關閉Connector和IoSession
  43.      * 特別的提醒,NioSocketConnector 也要關閉。
  44.      * 函數名是 dispose()。這點特別重要。這次出現 too many open files 的問題根源在這裏
  45.      * @author :Kevin.xie
  46.      * <b>創建日期 :</b>2011-10-20 上午10:20:54
  47.      *
  48.      * @param connector 要關閉的IoConnector,不關閉會報 too many open files 錯誤
  49.      * @param session 要關閉的session
  50.      *
  51.      * <b>修改歷史:</b>(修改人,修改時間,修改原因/內容)
  52.      *
  53.      * </pre>
  54.      */   
  55.     public static void closeConnectorAndSession(IoConnector connector, IoSession session) {   
  56.    
  57.         if (session != null && !session.isClosing()) {   
  58.                
  59.             // 沒有關閉,就關閉   
  60.             session.close(true);   
  61.             session = null;   
  62.         }   
  63.            
  64.         if (connector != null && !(connector.isDisposing() || connector.isDisposed())) {   
  65.                
  66.             // 沒有關閉,就關閉   
  67.             connector.dispose();   
  68.             connector = null;   
  69.         }   
  70.     }   
  71. ]   


用完後一定要釋放資源:
Java代碼 複製代碼 收藏代碼
  1. Map<String, Object> resultMap = SocketUtils.getConnectorAndSession();  
  2.   IoSession session = (IoSession) resultMap.get(SocketUtils.SESSION_KEY);  
  3.   IoConnector connector = (IoConnector) resultMap.get(SocketUtils.CONNECTOR_KEY);  
  4. ............  
  5. ............          
  6.  
  7.   // 主動關閉連接  
  8.   SocketUtils.closeConnectorAndSession(connector, session); 
  1. Map<String, Object> resultMap = SocketUtils.getConnectorAndSession(); 
  2.   IoSession session = (IoSession) resultMap.get(SocketUtils.SESSION_KEY); 
  3.   IoConnector connector = (IoConnector) resultMap.get(SocketUtils.CONNECTOR_KEY); 
  4. ............ 
  5. ............         
  6.  
  7.   // 主動關閉連接 
  8.   SocketUtils.closeConnectorAndSession(connector, session); 


同時在配置文件 /etc/security/limits.conf  加了一個配置(該不該問題不大):
# kevin.xie added, fixed 'too many open file' bug', 2012-01-04
* soft nofile 65536
* hard nofile 65536
Java代碼 複製代碼 收藏代碼
  1. # 第二次解決添加的內容    
  2. # kevin.xie added, fixed 'too many open file' bug, limit open max files 1024, 2011-10-24    
  3. * - nofile 102400    
  4.     
  5. # 第三次(本次)解決添加的問題(不過這個應該可以不修改,沒有印證,也懶得修改了)    
  6. # kevin.xie added, fixed 'too many open file' bug', 2012-01-04    
  7. * soft nofile 65536    
  8. * hard nofile 65536   
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章