概念区分
内核维护的打开文件表(System Open File Table)
内核维护着一个打开文件表(看作一个数组),当某个进程打开一个文件时,内核会在这个表中添加一条记录,这个记录是一个结构体,包含了如下数据:文件的偏移量(进程操作(比如读)到文件的哪个位置)等等
一个进程可以打开同一个文件多次,那么就会内核的打开文件表中就会相应地增加多个记录。后文中我们把该表的记录叫做文件句柄
上面提到内核维护着一个打开文件表,其实进程也在PCB(Process Control Block)中维护着一个文件描述符表(File Descriptor Table)。当进程打开一个文件时,内核会在打开文件表中新增一条记录,同时进程也会在自已的文件描述符表中添加一条记录,该条记录中有一个指针,指向了内核的打开文件表中对应的记录。
一个进程可以打开同一个文件多次,那么就会在FDT中相应地增加多个记录。后文中我们将用打开文件数来表示进程的文件描述符的个数
Linux的参数调优
我们可能经常会遇到too many open files
报错,这是因为“进程的打开文件数(文件描述符)过多,超过了进程的上限(一般都是进程的文件描述符超过限制,目前还没遇到文件句柄超出)” 。所以,我们需要对进程的打开文件数上限做调整。
用户
如果没有对进程做显示的设置,进程的打开文件数上限会继承该进程所属的用户的打开文件数上限(正确的表述未找到,可以理解为该用户下单个进程的打开文件数上限)。
我们可以通过以下的方法设置用户的打开文件数上限
Copy $ vim /etc/security/limits.conf
...
<user> - nofile 65535
...
我们也可以通过* - nofile 65535
来设置所有用户(*
代表所有用户)的打开文件数上限。设置好之后我们可以通过命令ulimit -n
来查看当前用户的打开文件数上限。
其实,打开文件数上限有分Soft Limit
和Hard Limit
。上面的设置方法中第二列为-
,表示同时设置Soft Limit
与Hard Limit
。当然,我们也可以通过如下方法来设置用户的Soft Limit
与Hard Limit
,需要注意的是Soft Limit
不能超过Hard Limit
Copy $ vim /etc/security/limits.conf
...
<user> soft nofile 65535
<user> soft nofile 65534
...
命令ulimit -n
查看的其实是Soft Limit
。可以通过命令ulimit -Sn
查看Soft Limit
,通过命令ulimit -Hn
查看Hard Limit
。
系统的默认配置中,每个用户的Soft Limit
为1024,Hard Limit
为2048
Tips: 建议将用户的Soft Limit
与Hard Limit
设为一样,且所有用户都设大一些为65535
这样再说一点实用的小技巧,如果想查看其他用户的最大打开文件数,但是却不知道那个用户的密码。那么可以这样做:首先新建文件 ulimit.sh
,内容如下
Copy su -c "ulimit -n" <user>
然后为ulimit.sh
添加可执行属性,然后执行
进程
我们设置特定进程的打开文件数上限,但是注意进程的打开文件数不能超过用户的打开文件数 。
对于systemd管理的进程,我们可以通过下面的方法同时设置Soft Limit
与Hard Limit
Copy [Service]
LimitNOFILE=65535
可以通过cat /proc/<pid>/limits
查看进程的打开文件数上限,如下Max open files
一行
Copy $ cat /proc/<pid>/limits
Limit Soft Limit Hard Limit Units
...
Max open files 1024 4096 files
...
可以通过命令ls -l /proc/<pid>/fd | wc -l
统计进程已经打开的文件数(文件描述符数)
Linux下的指标
Copy $ cat /proc/sys/fs/file-max
3280853
该指标的官方定义为(官方链接待补充)
The value in file-max denotes the maximum number of file handles that the Linux kernel will allocate. When you get a lot of error messages about running out of file handles, you might want to raise this limit. The default value is 10% of RAM in kilobytes. To change it, just write the new number into the file
也就是说file-max
指的是内核中文件句柄数的最大值
Copy $ cat /proc/sys/fs/file-nr
6496 0 3280853
其中最后一个参数就是file-max
的值,第一个表示已经打开的文件句柄数,(第二个参数暂时还未清楚,好像一直为0 )
Copy $ ls /proc/<pid>/fd
0 1 2 4...
该目录下有很多以数字命名的链接文件,这些数字,其实就是进程的文件描述符表中的索引,即数组的索引。所以经常也把文件描述符看成是一个数字。 进程每打开一个文件,文件描述符就会加1。这个目录下看到的文件描述符不一定连续,因为有些文件可能已经关闭了。
Copy $ cat /proc/<pid>/limits
Limit Soft Limit Hard Limit Units
...
Max open files 1024 4096 files
...
其中有一行叫Max open files
,这里的open files
其实就是进程的文件描述符的上限。不过注意有分Soft Limit
和Hard Limit
,我们可以为进程设置这两个值,但是Soft Limit
必须小于等于Hard Limit
(设置方法见《Nofile》)。如果没有给进程设置,则会继承该进程所属用户的配置。执行命令ulimit -Sn
可以查看用户的Soft Limit
,执行命令ulimit -Hn
可以查看用户的Hard Limit
实践
接下来,我们写一个程序,打开一个文件一千次,然后查看内核的打开文件数与进程的文件描述符
执行前,我们先看一下内核的打开文件表,有6496个
Copy $ cat /proc/sys/fs/file-nr
6496 0 3280853
然后运行该程序
接着,我们再来查看内核的打开文件表,为7488,约增加了1000个(因为有别的进程会打开或关闭文件)
Copy $ cat /proc/sys/fs/file-nr
7488 0 3280853
我们查看该进程的id,为13196
Copy $ ps -ef | grep python
docker 13196 106787 0 21:45 pts/3 00:00:00 /usr/bin/python ./test.py
然后查看进程的文件描述符,有1004个
Copy $ ll /proc/13196/fd | wc -l
1004
$ ls /proc/13196/fd
0 12 144 169 193 217 241 266 290 314 339 363 388 411 436 460 485 509 533 558 582 606 630 655 68 703 728 752 777 800 825 85 874 899 922 947 971 996
1 120 145 17 194 218 242 267 291 315 34 364 389 412 437 461 486 51 534 559 583 607 631 656 680 704 729 753 778 801 826 850 875 9 923 948 972 997
10 121 146 170 195 219 243 268 292 316 340 365 39 413 438 462 487 510 535 56 584 608 632 657 681 705 73 754 779 802 827 851 876 90 924 949 973 998
100 122 147 171 196 22 244 269 293 317 341 366 390 414 439 463 488 511 536 560 585 609 633 658 682 706 730 755 78 803 828 852 877 900 925 95 974 999
1000 123 148 172 197 220 245 27 294 318 342 367 391 415 44 464 489 512 537 561 586 61 634 659 683 707 731 756 780 804 829 853 878 901 926 950 975
1001 124 149 173 198 221 246 270 295 319 343 368 392 416 440 465 49 513 538 562 587 610 635 66 684 708 732 757 781 805 83 854 879 902 927 951 976
1002 125 15 174 199 222 247 271 296 32 344 369 393 417 441 466 490 514 539 563 588 611 636 660 685 709 733 758 782 806 830 855 88 903 928 952 977
101 126 150 175 2 223 248 272 297 320 345 37 394 418 442 467 491 515 54 564 589 612 637 661 686 71 734 759 783 807 831 856 880 904 929 953 978
102 127 151 176 20 224 249 273 298 321 346 370 395 419 443 468 492 516 540 565 59 613 638 662 687 710 735 76 784 808 832 857 881 905 93 954 979
103 128 152 177 200 225 25 274 299 322 347 371 396 42 444 469 493 517 541 566 590 614 639 663 688 711 736 760 785 809 833 858 882 906 930 955 98
104 129 153 178 201 226 250 275 3 323 348 372 397 420 445 47 494 518 542 567 591 615 64 664 689 712 737 761 786 81 834 859 883 907 931 956 980
105 13 154 179 202 227 251 276 30 324 349 373 398 421 446 470 495 519 543 568 592 616 640 665 69 713 738 762 787 810 835 86 884 908 932 957 981
106 130 155 18 203 228 252 277 300 325 35 374 399 422 447 471 496 52 544 569 593 617 641 666 690 714 739 763 788 811 836 860 885 909 933 958 982
107 131 156 180 204 229 253 278 301 326 350 375 4 423 448 472 497 520 545 57 594 618 642 667 691 715 74 764 789 812 837 861 886 91 934 959 983
108 132 157 181 205 23 254 279 302 327 351 376 40 424 449 473 498 521 546 570 595 619 643 668 692 716 740 765 79 813 838 862 887 910 935 96 984
109 133 158 182 206 230 255 28 303 328 352 377 400 425 45 474 499 522 547 571 596 62 644 669 693 717 741 766 790 814 839 863 888 911 936 960 985
11 134 159 183 207 231 256 280 304 329 353 378 401 426 450 475 5 523 548 572 597 620 645 67 694 718 742 767 791 815 84 864 889 912 937 961 986
110 135 16 184 208 232 257 281 305 33 354 379 402 427 451 476 50 524 549 573 598 621 646 670 695 719 743 768 792 816 840 865 89 913 938 962 987
111 136 160 185 209 233 258 282 306 330 355 38 403 428 452 477 500 525 55 574 599 622 647 671 696 72 744 769 793 817 841 866 890 914 939 963 988
112 137 161 186 21 234 259 283 307 331 356 380 404 429 453 478 501 526 550 575 6 623 648 672 697 720 745 77 794 818 842 867 891 915 94 964 989
113 138 162 187 210 235 26 284 308 332 357 381 405 43 454 479 502 527 551 576 60 624 649 673 698 721 746 770 795 819 843 868 892 916 940 965 99
114 139 163 188 211 236 260 285 309 333 358 382 406 430 455 48 503 528 552 577 600 625 65 674 699 722 747 771 796 82 844 869 893 917 941 966 990
115 14 164 189 212 237 261 286 31 334 359 383 407 431 456 480 504 529 553 578 601 626 650 675 7 723 748 772 797 820 845 87 894 918 942 967 991
116 140 165 19 213 238 262 287 310 335 36 384 408 432 457 481 505 53 554 579 602 627 651 676 70 724 749 773 798 821 846 870 895 919 943 968 992
117 141 166 190 214 239 263 288 311 336 360 385 409 433 458 482 506 530 555 58 603 628 652 677 700 725 75 774 799 822 847 871 896 92 944 969 993
118 142 167 191 215 24 264 289 312 337 361 386 41 434 459 483 507 531 556 580 604 629 653 678 701 726 750 775 8 823 848 872 897 920 945 97 994
119 143 168 192 216 240 265 29 313 338 362 387 410 435 46 484 508 532 557 581 605 63 654 679 702 727 751 776 80 824 849 873 898 921 946 970 995
其中0
、1
、2
是每个进程都有的,代表stdin
、stdout
与stderr
,我们来查看3
,如下
Copy $ ll /proc/13196/fd/3
lrwx------ 1 docker docker 64 5月 24 21:46 /proc/13196/fd/3 -> /home/docker/peng/fd/afile
Reference
https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/5/html/tuning_and_optimizing_red_hat_enterprise_linux_for_oracle_9i_and_10g_databases/chap-oracle_9i_and_10g_tuning_guide-setting_file_handles
https://www.ibm.com/support/knowledgecenter/en/ssw_aix_71/com.ibm.aix.genprogc/using_file_descriptors.htm
http://www.opstool.com/article/166
https://blog.csdn.net/lizhidefengzi/article/details/71481195