rm ในไดเรกทอรีที่มีไฟล์นับล้าน


104

ความเป็นมา: ฟิสิคัลเซิร์ฟเวอร์อายุประมาณสองปีไดรฟ์ SATA 7200-RPM เชื่อมต่อกับการ์ด RAID 3Ware, ext3 FS ที่ติดตั้งในเวลากลางวันและข้อมูล = สั่งไม่อยู่ภายใต้การโหลดที่บ้าคลั่งเคอร์เนล 2.6.18-92.1.22.el5, uptime 545 วัน . ไดเรกทอรีไม่มีไดเรกทอรีย่อยใด ๆ มีเพียงไฟล์เล็ก ๆ (~ 100 byte) หลายล้านไฟล์และบางอันก็มีขนาดใหญ่กว่า (ไม่กี่ KB)

เรามีเซิร์ฟเวอร์ที่มีนกกาเหว่าอยู่เล็กน้อยในช่วงสองสามเดือนที่ผ่านมา แต่เราสังเกตเห็นเพียงวันเดียวเมื่อมันเริ่มไม่สามารถเขียนไปยังไดเรกทอรีได้เนื่องจากมันมีไฟล์มากเกินไป มันเริ่มโยนข้อผิดพลาดนี้ใน / var / log / messages:

ext3_dx_add_entry: Directory index full!

ดิสก์ที่สงสัยมีจำนวนไอโหนดเหลืออยู่:

Filesystem            Inodes   IUsed   IFree IUse% Mounted on
/dev/sda3            60719104 3465660 57253444    6% /

ดังนั้นฉันเดาว่านั่นหมายความว่าเรามีขีด จำกัด จำนวนรายการที่สามารถอยู่ในไฟล์ไดเรกทอรีได้ ไม่ทราบว่าจะมีไฟล์กี่ไฟล์ แต่จะไม่เป็นเช่นนั้นเท่าที่คุณจะเห็นมากกว่าสามล้านหรือมากกว่านั้น ไม่ว่าจะเป็นสิ่งที่ดีใจคุณ! แต่นั่นเป็นส่วนหนึ่งของคำถามของฉัน: ขีด จำกัด บนนั้นคืออะไร? ปรับได้ไหม ก่อนที่ผมจะได้รับการตะโกนใส่ฉันต้องการที่จะปรับมันลง ; ไดเรกทอรีมหาศาลนี้ทำให้เกิดปัญหาทุกประเภท

อย่างไรก็ตามเราติดตามปัญหาในรหัสที่สร้างไฟล์เหล่านั้นทั้งหมดและเราได้ทำการแก้ไขแล้ว ตอนนี้ฉันติดอยู่กับการลบไดเรกทอรี

ตัวเลือกที่นี่:

  1. rm -rf (dir)

    ฉันลองสิ่งนี้ก่อน ฉันยอมแพ้และฆ่ามันหลังจากมันวิ่งไปหนึ่งวันครึ่งโดยไม่มีผลกระทบใด ๆ

  2. ยกเลิกการเชื่อมโยง (2) ในไดเรกทอรี: การพิจารณาที่คุ้มค่าแน่นอน แต่คำถามคือการลบไฟล์ในไดเรกทอรีด้วย fsck เร็วกว่าการลบผ่านการยกเลิกการเชื่อมโยง (2) นั่นคือวิธีใดวิธีหนึ่งฉันต้องทำเครื่องหมาย inodes เหล่านั้นว่าไม่ได้ใช้ นี้ถือว่าแน่นอนว่าฉันสามารถบอก fsck ที่จะไม่ปล่อยรายการไปยังไฟล์ใน / หายไป + พบ; มิฉะนั้นฉันเพิ่งย้ายปัญหาของฉัน นอกเหนือจากความกังวลอื่น ๆ ทั้งหมดหลังจากอ่านเกี่ยวกับเรื่องนี้อีกเล็กน้อยปรากฏว่าฉันอาจต้องเรียกฟังก์ชั่น FS ภายในบางอย่างเนื่องจากไม่มีตัวแปร unlink (2) ที่ฉันสามารถหาได้ ไดเรกทอรีที่มีรายการอยู่ในนั้น ฮี้
  3. while [ true ]; do ls -Uf | head -n 10000 | xargs rm -f 2>/dev/null; done )

    อันที่จริงนี่เป็นเวอร์ชั่นย่อ ตัวจริงที่ฉันใช้อยู่ซึ่งเพิ่งเพิ่มการรายงานความคืบหน้าและการหยุดแบบคลีนเมื่อเราเรียกใช้ไฟล์ที่ไม่ได้ลบคือ:

    ส่งออก i = 0;
    เวลา (ในขณะที่ [จริง]; ทำ
      ls -Uf | หัว -n 3 | grep -qF '.png' || หยุดพัก;
      ls -Uf | หัว -n 10000 | xargs rm -f 2> / dev / null;
      ส่งออก i = $ (($ i + 10,000));
      echo "$ i ... ";
    เสร็จสิ้น)

    ดูเหมือนว่าจะทำงานได้ดี เมื่อฉันเขียนสิ่งนี้มันได้ลบไฟล์ 260,000 ไฟล์ในสามสิบนาทีที่ผ่านมา

ตอนนี้สำหรับคำถาม:
  1. ดังกล่าวข้างต้นขีด จำกัด รายการต่อไดเรกทอรีสามารถปรับได้หรือไม่
  2. เหตุใดจึงใช้ "ของจริง 7m9.561s / ผู้ใช้ 0m0.001s / sys 0m0.001s" เพื่อลบไฟล์เดียวซึ่งเป็นไฟล์แรกในรายการที่ส่งคืนโดยls -Uอาจใช้เวลาสิบนาทีในการลบ 10,000 รายการแรกที่มี คำสั่งใน # 3 แต่ตอนนี้มันลากอย่างมีความสุข? สำหรับเรื่องนั้นมันถูกลบ 260,000 ในเวลาประมาณสามสิบนาที แต่ตอนนี้ใช้เวลาอีกสิบห้านาทีเพื่อลบอีก 60,000 ทำไมการแกว่งตัวครั้งใหญ่ในความเร็ว?
  3. มีวิธีที่ดีกว่าในการทำสิ่งนี้หรือไม่? ไม่เก็บไฟล์นับล้านไฟล์ในไดเรกทอรี ฉันรู้ว่ามันโง่และมันจะไม่เกิดขึ้นกับนาฬิกาของฉัน Googling ปัญหาและการค้นหาผ่าน SF และ SO มีการเปลี่ยนแปลงมากมายfindที่ไม่ได้เร็วกว่าวิธีของฉันอย่างเห็นได้ชัดด้วยเหตุผลหลายประการ แต่แนวคิดการลบผ่าน fsck มีขาบ้างหรือไม่ หรืออย่างอื่นอย่างสิ้นเชิง? ฉันกระตือรือร้นที่จะได้ยินความคิดนอกกรอบ (หรือภายในกล่องที่ไม่เป็นที่รู้จัก)
ขอบคุณที่อ่านนิยายเล่มเล็ก ๆ อย่าลังเลที่จะถามคำถามและฉันจะตอบอย่างแน่นอน ฉันจะอัปเดตคำถามด้วยจำนวนไฟล์สุดท้ายและระยะเวลาที่สคริปต์ลบรันเมื่อฉันมี

เอาต์พุตสคริปต์สุดท้าย!:

2970000...
2980000...
2990000...
3000000...
3010000...

real    253m59.331s
user    0m6.061s
sys     5m4.019s

ดังนั้นไฟล์สามล้านไฟล์จึงถูกลบภายในเวลาไม่เกินสี่ชั่วโมง


1
RM (GNU coreutils) 8.4 มีตัวเลือกนี้: "-v, --verbose อธิบายสิ่งที่จะถูกดำเนินการ" มันจะแสดงไฟล์ทั้งหมดที่ถูกลบ
Cristian Ciupitu

2
ที่จริงแล้วนั่นเป็นวิธีที่เรียบร้อยในการทำแถบความคืบหน้า: เนื่องจากแต่ละไฟล์จะมีความยาวสามสิบเจ็ดตัวอักษร (36 + a '\ n') ฉันสามารถเขียนโปรแกรมแยกวิเคราะห์ได้อย่างง่ายดายและเนื่องจาก printf () คือ ราคาถูกและคำสั่ง rm มีชื่อของไฟล์ที่โหลดอยู่แล้วไม่มีการปรับประสิทธิภาพเป็นพิเศษ ดูเหมือนว่าไม่ใช่ผู้เริ่มต้นสำหรับการทำ shebang ทั้งหมดเนื่องจากฉันไม่เคยได้รับ "rm" ทำอะไรแบบนั้นอยู่ดี แต่มันสามารถทำงานได้ค่อนข้างดีเหมือนแถบความคืบหน้าภายใน 10,000 อาจเป็น "." สำหรับทุก ๆ ร้อยไฟล์?
BMDan

8
rm -rfv | pv -l >/dev/null. pv ควรพร้อมใช้งานในที่เก็บEPEL
Cristian Ciupitu

5
pv ยอดเยี่ยมมาก ฉันทิ้งร่องรอยการติดตั้ง pv ไว้ในการปลุก
BMDan

ฉันมีปัญหาเดียวกันนี้เมื่อไม่นานมานี้ ขอขอบคุณ!
richo

คำตอบ:


30

data=writebackตัวเลือกภูเขาสมควรที่จะพยายามเพื่อป้องกันไม่ให้รายการบันทึกของระบบแฟ้ม สิ่งนี้ควรทำในช่วงเวลาลบเท่านั้นมีความเสี่ยงอย่างไรก็ตามหากเซิร์ฟเวอร์กำลังปิดหรือรีบูตระหว่างการดำเนินการลบ

ตามหน้านี้ ,

บางแอปพลิเคชันแสดงความเร็วที่เพิ่มขึ้นอย่างมากเมื่อใช้งาน ตัวอย่างเช่นการปรับปรุงความเร็วสามารถเห็นได้ (... ) เมื่อแอปพลิเคชันสร้างและลบไฟล์ขนาดเล็กจำนวนมาก

ตัวเลือกที่มีการตั้งค่าทั้งในfstabหรือในระหว่างการดำเนินการติดแทนที่ด้วยdata=ordered data=writebackระบบไฟล์ที่มีไฟล์ที่จะลบจะต้องมีการติดตั้งใหม่


1
เขาสามารถเพิ่มเวลาได้จากcommit ตัวเลือก : "ค่าเริ่มต้นนี้ (หรือค่าต่ำ) จะส่งผลเสียต่อประสิทธิภาพการทำงาน แต่ดีต่อความปลอดภัยของข้อมูลการตั้งค่าเป็น 0 จะมีผลเช่นเดียวกับที่ปล่อยไว้ที่ค่าเริ่มต้น (5 วินาที) ) การตั้งค่าให้มีค่ามากจะช่วยเพิ่มประสิทธิภาพ "
Cristian Ciupitu

1
Writeback ดูเป็นตัวเอกยกเว้นเอกสารที่ฉันดู ( gentoo.org/doc/en/articles/l-afig-p8.xml#doc_chap4 ) กล่าวอย่างชัดเจนว่ายังคงเป็นข้อมูลเมตาของวารสารซึ่งฉันเข้าใจว่าเป็นข้อมูลทั้งหมดที่ฉัน เปลี่ยนแปลง (ฉันไม่ได้เปลี่ยนข้อมูลในไฟล์ด้วยตัวเอง) ฉันเข้าใจตัวเลือกไม่ถูกต้องหรือไม่
BMDan

ประการสุดท้าย FYI ที่ไม่ได้กล่าวถึงในลิงก์นั้นคือข้อเท็จจริงที่ว่า data = writeback อาจเป็นช่องโหว่ความปลอดภัยขนาดใหญ่เนื่องจากข้อมูลที่ชี้ไปตามรายการที่ระบุอาจไม่มีข้อมูลที่เขียนโดยแอปหมายความว่าอาจทำให้เกิดความผิดพลาดได้ ในข้อมูลเก่าที่อาจมีความอ่อนไหว / เป็นส่วนตัว ไม่ใช่ความกังวลที่นี่เนื่องจากเราเพียงเปิดใช้งานชั่วคราว แต่ฉันต้องการเตือนทุกคนถึงข้อแม้นั้นในกรณีที่คุณหรือคนอื่น ๆ ที่วิ่งข้ามคำแนะนำนั้นไม่ทราบ
BMDan

กระทำ: ที่เนียนสวย! ขอบคุณสำหรับตัวชี้
BMDan

2
data=writebackยังคงเมทาดาทาวารสารก่อนที่จะเขียนลงในระบบไฟล์หลัก ตามที่ฉันเข้าใจแล้วมันไม่ได้บังคับใช้การสั่งซื้อระหว่างสิ่งต่าง ๆ เช่นการเขียนแผนที่ขอบเขตและการเขียนข้อมูลลงในขอบเขตเหล่านั้น อาจมีข้อ จำกัด ในการสั่งซื้ออื่น ๆ ที่ผ่อนคลายเช่นกันหากคุณเห็นว่าได้รับประโยชน์อย่างสมบูรณ์จากสิ่งนี้ แน่นอนว่าการติดตั้งโดยไม่ต้องใช้สมุดบันทึกเลยอาจเป็นประสิทธิภาพที่สูงขึ้น (อาจทำให้การเปลี่ยนแปลงข้อมูลเมตาเกิดขึ้นใน RAM โดยไม่จำเป็นต้องมีอะไรบนดิสก์ก่อนที่จะยกเลิกการเชื่อมโยง op)
Peter Cordes

80

ในขณะที่สาเหตุสำคัญของปัญหานี้คือประสิทธิภาพการทำงาน ext3 ที่มีไฟล์นับล้าน แต่สาเหตุที่แท้จริงของปัญหานี้แตกต่างกัน

เมื่อไดเร็กทอรีต้องการแสดง readdir () จะถูกเรียกใช้บนไดเร็กทอรีซึ่งให้รายชื่อไฟล์ readdir เป็นการเรียก posix แต่การเรียกใช้ระบบ Linux จริงที่นี่ถูกเรียกว่า 'getdents' Getdents รายการไดเรกทอรีรายการโดยการเติมบัฟเฟอร์ด้วยรายการ

ปัญหานี้เกิดจากความจริงที่ว่า readdir () ใช้ขนาดบัฟเฟอร์คงที่ 32Kb เพื่อดึงไฟล์ เมื่อไดเรกทอรีใหญ่ขึ้นและใหญ่ขึ้น (ขนาดเพิ่มขึ้นเมื่อมีการเพิ่มไฟล์) ext3 จะช้าลงและช้าลงเมื่อดึงรายการและขนาดบัฟเฟอร์ 32Kb ของ readdir เพิ่มเติมก็เพียงพอแล้วที่จะรวมเศษส่วนของรายการในไดเรกทอรี สิ่งนี้ทำให้ readdir วนซ้ำไปซ้ำมาและเรียกใช้การเรียกระบบที่มีราคาแพงซ้ำแล้วซ้ำอีก

ตัวอย่างเช่นในไดเร็กทอรีทดสอบที่ฉันสร้างขึ้นด้วยไฟล์มากกว่า 2.6 ล้านไฟล์การรัน "ls -1 | wc-l" แสดงเอาต์พุต strace ขนาดใหญ่ของการเรียกระบบ getdent จำนวนมาก

$ strace ls -1 | wc -l
brk(0x4949000)                          = 0x4949000
getdents(3, /* 1025 entries */, 32768)  = 32752
getdents(3, /* 1024 entries */, 32768)  = 32752
getdents(3, /* 1025 entries */, 32768)  = 32760
getdents(3, /* 1025 entries */, 32768)  = 32768
brk(0)                                  = 0x4949000
brk(0x496a000)                          = 0x496a000
getdents(3, /* 1024 entries */, 32768)  = 32752
getdents(3, /* 1026 entries */, 32768)  = 32760
...

นอกจากนี้เวลาที่ใช้ในไดเรกทอรีนี้ก็มีความสำคัญเช่นกัน

$ time ls -1 | wc -l
2616044

real    0m20.609s
user    0m16.241s
sys 0m3.639s

วิธีทำให้กระบวนการนี้มีประสิทธิภาพมากขึ้นคือการเรียกใช้ getdents ด้วยตนเองพร้อมกับบัฟเฟอร์ที่ใหญ่กว่า สิ่งนี้ช่วยปรับปรุงประสิทธิภาพอย่างมาก

ตอนนี้คุณไม่ควรเรียกใช้ getdents ด้วยตนเองดังนั้นจึงไม่มีอินเทอร์เฟซให้ใช้งานได้ตามปกติ (ตรวจสอบหน้า man เพื่อให้ getdents เห็น!) อย่างไรก็ตามคุณสามารถเรียกมันด้วยตนเองและทำให้ระบบของคุณมีประสิทธิภาพมากขึ้น

วิธีนี้ช่วยลดเวลาที่ใช้ในการดึงไฟล์เหล่านี้ได้อย่างมาก ฉันเขียนโปรแกรมที่ทำสิ่งนี้

/* I can be compiled with the command "gcc -o dentls dentls.c" */

#define _GNU_SOURCE

#include <dirent.h>     /* Defines DT_* constants */
#include <err.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>

struct linux_dirent {
        long           d_ino;
        off_t          d_off;
        unsigned short d_reclen;
        char           d_name[256];
        char           d_type;
};

static int delete = 0;
char *path = NULL;

static void parse_config(
        int argc,
        char **argv)
{
    int option_idx = 0;
    static struct option loptions[] = {
      { "delete", no_argument, &delete, 1 },
      { "help", no_argument, NULL, 'h' },
      { 0, 0, 0, 0 }
    };

    while (1) {
        int c = getopt_long(argc, argv, "h", loptions, &option_idx);
        if (c < 0)
            break;

        switch(c) {
          case 0: {
              break;
          }

          case 'h': {
              printf("Usage: %s [--delete] DIRECTORY\n"
                     "List/Delete files in DIRECTORY.\n"
                     "Example %s --delete /var/spool/postfix/deferred\n",
                     argv[0], argv[0]);
              exit(0);                      
              break;
          }

          default:
          break;
        }
    }

    if (optind >= argc)
      errx(EXIT_FAILURE, "Must supply a valid directory\n");

    path = argv[optind];
}

int main(
    int argc,
    char** argv)
{

    parse_config(argc, argv);

    int totalfiles = 0;
    int dirfd = -1;
    int offset = 0;
    int bufcount = 0;
    void *buffer = NULL;
    char *d_type;
    struct linux_dirent *dent = NULL;
    struct stat dstat;

    /* Standard sanity checking stuff */
    if (access(path, R_OK) < 0) 
        err(EXIT_FAILURE, "Could not access directory");

    if (lstat(path, &dstat) < 0) 
        err(EXIT_FAILURE, "Unable to lstat path");

    if (!S_ISDIR(dstat.st_mode))
        errx(EXIT_FAILURE, "The path %s is not a directory.\n", path);

    /* Allocate a buffer of equal size to the directory to store dents */
    if ((buffer = calloc(dstat.st_size*3, 1)) == NULL)
        err(EXIT_FAILURE, "Buffer allocation failure");

    /* Open the directory */
    if ((dirfd = open(path, O_RDONLY)) < 0) 
        err(EXIT_FAILURE, "Open error");

    /* Switch directories */
    fchdir(dirfd);

    if (delete) {
        printf("Deleting files in ");
        for (int i=5; i > 0; i--) {
            printf("%u. . . ", i);
            fflush(stdout);
            sleep(1);
        }
        printf("\n");
    }

    while (bufcount = syscall(SYS_getdents, dirfd, buffer, dstat.st_size*3)) {
        offset = 0;
        dent = buffer;
        while (offset < bufcount) {
            /* Don't print thisdir and parent dir */
            if (!((strcmp(".",dent->d_name) == 0) || (strcmp("..",dent->d_name) == 0))) {
                d_type = (char *)dent + dent->d_reclen-1;
                /* Only print files */
                if (*d_type == DT_REG) {
                    printf ("%s\n", dent->d_name);
                    if (delete) {
                        if (unlink(dent->d_name) < 0)
                            warn("Cannot delete file \"%s\"", dent->d_name);
                    }
                    totalfiles++;
                }
            }
            offset += dent->d_reclen;
            dent = buffer + offset;
        }
    }
    fprintf(stderr, "Total files: %d\n", totalfiles);
    close(dirfd);
    free(buffer);

    exit(0);
}

แม้ว่าสิ่งนี้จะไม่ต่อสู้กับปัญหาพื้นฐาน (ไฟล์จำนวนมากในระบบไฟล์ที่ทำงานได้ไม่ดี) เป็นไปได้ว่าจะเร็วกว่าตัวเลือกอื่น ๆ

สำหรับความคิดล่วงหน้าเราควรลบไดเรกทอรีที่ได้รับผลกระทบและสร้างใหม่หลังจากนั้น ไดเรกทอรีมีขนาดเพิ่มขึ้นเรื่อย ๆ และยังคงทำงานได้ไม่ดีแม้จะมีไฟล์อยู่สองสามอันเนื่องจากขนาดของไดเรกทอรี

แก้ไข:ฉันทำความสะอาดนี้ไม่น้อย เพิ่มตัวเลือกในการอนุญาตให้คุณลบในบรรทัดคำสั่งที่รันไทม์และลบกลุ่มของสิ่งที่ทางเดินซึ่งการมองย้อนกลับไปเป็นคำถามที่ดีที่สุด แสดงให้เห็นว่ายังมีการผลิตหน่วยความจำเสียหาย

ตอนนี้คุณสามารถทำได้ dentls --delete /my/path

ผลลัพธ์ใหม่ อ้างอิงจากไดเรกทอรีที่มี 1.82 ล้านไฟล์

## Ideal ls Uncached
$ time ls -u1 data >/dev/null

real    0m44.948s
user    0m1.737s
sys 0m22.000s

## Ideal ls Cached
$ time ls -u1 data >/dev/null

real    0m46.012s
user    0m1.746s
sys 0m21.805s


### dentls uncached
$ time ./dentls data >/dev/null
Total files: 1819292

real    0m1.608s
user    0m0.059s
sys 0m0.791s

## dentls cached
$ time ./dentls data >/dev/null
Total files: 1819292

real    0m0.771s
user    0m0.057s
sys 0m0.711s

รู้สึกประหลาดใจชนิดนี้ยังคงทำงานได้ดี!


1
ข้อกังวลเล็กน้อยสองข้อ: อย่างหนึ่ง[256]น่าจะเป็น[FILENAME_MAX]และสองข้อ Linux ของฉัน (2.6.18 == CentOS 5.x) ดูเหมือนจะไม่รวมรายการ d_type ใน dirent (อย่างน้อยตาม getdents (2))
BMDan

1
คุณช่วยอธิบายเพิ่มเติมเกี่ยวกับการปรับสมดุล btree เล็กน้อยและทำไมการลบเพื่อช่วยป้องกันมัน? ฉันลองใช้ Google กับมัน แต่น่าเสียดายที่ไม่มีประโยชน์
ovgolovin

1
เพราะตอนนี้ดูเหมือนว่าสำหรับฉันถ้าเราจะลบคำสั่งเราบังคับให้มีการปรับสมดุลในขณะที่เราลบใบไม้ด้านหนึ่งและออกจากที่อื่น: en.wikipedia.org/wiki/B-tree#Rebalancing_after_deletion
ovgolovin

1
ฉันหวังว่าฉันจะไม่รบกวนคุณในเรื่องนี้ แต่ถึงกระนั้นฉันก็เริ่มคำถามเกี่ยวกับการลบไฟล์ตามลำดับstackoverflow.com/q/17955459/862380ซึ่งดูเหมือนจะไม่ได้รับคำตอบซึ่งจะอธิบายปัญหาด้วยตัวอย่างซึ่งจะเข้าใจได้สำหรับโปรแกรมเมอร์ธรรมดา หากคุณมีเวลาและความรู้สึกเช่นนั้น บางทีคุณอาจเขียนคำอธิบายที่ดีกว่านี้ก็ได้
ovgolovin

2
นี่เป็นโค้ดที่น่าทึ่ง มันเป็นเครื่องมือเดียวที่ฉันสามารถค้นหารายการและลบไฟล์เซสชั่น 11,000,000 (สิบเอ็ดล้านไฟล์) ที่สร้างขึ้นในไดเรกทอรีซึ่งอาจมากกว่าหนึ่งปี กระบวนการ Plesk ที่ควรควบคุมพวกเขาโดยใช้ find และลูกเล่นอื่น ๆ ในคำตอบอื่น ๆ ที่นี่ไม่สามารถทำการทดสอบให้เสร็จสมบูรณ์ได้ มันเป็นบรรณาการให้กับต้นไม้ไบนารีที่ระบบไฟล์ใช้ในการจัดเก็บไดเรกทอรีที่เซสชันสามารถทำงานได้ทั้งหมด - คุณสามารถสร้างไฟล์และดึงข้อมูลได้โดยไม่ล่าช้า รายการเพียงแค่ใช้ไม่ได้
เจสัน

31

เป็นไปได้ไหมที่จะสำรองไฟล์อื่น ๆ ทั้งหมดจากระบบไฟล์นี้ไปยังที่เก็บข้อมูลชั่วคราวทำการฟอร์แมตพาร์ติชันแล้วกู้คืนไฟล์


3
ฉันชอบคำตอบนี้จริงๆ เป็นเรื่องจริงในกรณีนี้ไม่ใช่ แต่มันไม่ใช่สิ่งที่ฉันคิด ไชโย!
BMDan

สิ่งที่ฉันคิดด้วย นี่คือคำตอบสำหรับคำถาม 3. เหมาะถ้าคุณถามฉัน :)
โจชัว

12

ไม่มีขีด จำกัด ต่อไดเรกทอรีไฟล์ใน ext3 เพียงขีด จำกัด ของระบบไฟล์ inode (ฉันคิดว่ามีการ จำกัด จำนวนไดเรกทอรีย่อยว่า)

คุณอาจยังคงมีปัญหาหลังจากลบไฟล์

เมื่อไดเรกทอรีมีไฟล์นับล้านไฟล์รายการไดเรกทอรีจะใหญ่มาก รายการไดเรกทอรีจะต้องได้รับการสแกนสำหรับการดำเนินการลบทุกครั้งและต้องใช้เวลาหลายครั้งสำหรับแต่ละไฟล์ขึ้นอยู่กับตำแหน่งของรายการ แต่น่าเสียดายที่แม้ว่าไฟล์ทั้งหมดจะถูกลบออกรายการไดเรกทอรียังคงขนาด ดังนั้นการดำเนินการเพิ่มเติมที่ต้องมีการสแกนรายการไดเรกทอรีจะยังคงใช้เวลานานแม้ว่าไดเรกทอรีจะว่างเปล่า วิธีเดียวในการแก้ไขปัญหานั้นคือเปลี่ยนชื่อไดเรกทอรีสร้างใหม่ด้วยชื่อเก่าและถ่ายโอนไฟล์ที่เหลือไปยังใหม่ จากนั้นลบอันที่ถูกเปลี่ยนชื่อ


อันที่จริงฉันสังเกตเห็นเพียงพฤติกรรมนี้หลังจากลบทุกอย่าง โชคดีที่เรามีไดเรกทอรีอยู่แล้วจาก "สายเพลิง" เหมือนเดิมดังนั้นฉันจึงสามารถทำได้
BMDan

2
ที่กล่าวว่าหากไม่มีการ จำกัด ไฟล์ต่อไดเรกทอรีทำไมฉันถึงได้ "ext3_dx_add_entry: ดัชนีไดเรกทอรีเต็ม!" เมื่อยังมีไอโหนดบนพาร์ติชั่นนั้น? ไม่มีไดเรกทอรีย่อยในไดเรกทอรีนี้
BMDan

3
อืมฉันได้ทำการวิจัยเพิ่มเติมอีกเล็กน้อยและดูเหมือนว่ามีจำนวน จำกัด ของบล็อกที่ไดเรกทอรีสามารถใช้ จำนวนไฟล์ที่แน่นอนนั้นขึ้นอยู่กับบางสิ่งเช่นความยาวชื่อไฟล์ gossamer-threads.com/lists/linux/kernel/921942นี้ดูเหมือนจะบ่งชี้ว่าด้วยบล็อก 4k คุณควรจะสามารถมีไฟล์ได้มากกว่า 8 ล้านไฟล์ในไดเรกทอรี ชื่อไฟล์ยาวเป็นพิเศษหรือไม่
Alex J. Roberts

ชื่อไฟล์แต่ละชื่อมีความยาว 36 ตัวอักษร
BMDan

ดีว่าฉันออกจากความคิด :)
อเล็กซ์โรเบิร์ตเจ


4

พบว่าไม่ได้ผลสำหรับฉันแม้หลังจากเปลี่ยนพารามิเตอร์ของ ext3 fs ตามที่ผู้ใช้ข้างต้นแนะนำ วิธีการบริโภคหน่วยความจำมากเกินไป สคริปต์ PHP นี้ใช้เคล็ดลับ - ใช้งาน CPU ได้อย่างรวดเร็วและไม่มีนัยสำคัญใช้หน่วยความจำไม่สำคัญ:

<?php 
$dir = '/directory/in/question';
$dh = opendir($dir)) { 
while (($file = readdir($dh)) !== false) { 
    unlink($dir . '/' . $file); 
} 
closedir($dh); 
?>

ฉันโพสต์รายงานข้อผิดพลาดเกี่ยวกับปัญหานี้ด้วยการค้นหา: http://savannah.gnu.org/bugs/?31961


สิ่งนี้ช่วยฉัน !!
jestro

3

ฉันเพิ่งประสบปัญหาที่คล้ายกันและไม่สามารถรับdata=writebackข้อเสนอแนะของ ring0 ในการทำงาน (อาจเป็นเพราะความจริงที่ว่าไฟล์อยู่ในพาร์ทิชันหลักของฉัน) ขณะทำการค้นคว้าวิธีแก้ปัญหาฉันพบสิ่งนี้:

tune2fs -O ^has_journal <device>

นี้จะปิด journaling สมบูรณ์โดยไม่คำนึงถึงตัวเลือกให้กับdata mountฉันรวมสิ่งนี้กับnoatimeและปริมาณที่dir_indexตั้งไว้และดูเหมือนว่าจะทำงานได้ดี การลบเสร็จจริงโดยไม่ต้องฆ่าระบบของฉันยังคงตอบสนองและตอนนี้ก็สำรองและทำงาน (ด้วย journaling back on) โดยไม่มีปัญหา


ฉันจะแนะนำให้ติดตั้งมันเป็น ext2 แทน ext3 เพื่อหลีกเลี่ยงการทำเจอร์นัล ops ข้อมูลเมตา สิ่งนี้ควรทำเช่นเดียวกัน
Peter Cordes

3

ให้แน่ใจว่าคุณทำ:

mount -o remount,rw,noatime,nodiratime /mountpoint

ซึ่งควรเร่งความเร็วให้เร็วขึ้นเช่นกัน


4
โทรดี แต่มันติดตั้งตอนเที่ยงแล้วตามที่ฉันพูดถึงในส่วนหัวของคำถาม และ nodiratime ซ้ำซ้อน; ดูlwn.net/Articles/245002
BMDan

1
ppl ทำซ้ำมนต์นี้ "noatime, nodiratime, nodevatime, noreadingdocsatime"
บทกวี

2

คำสั่ง ls ช้ามาก ลอง:

find /dir_to_delete ! -iname "*.png" -type f -delete

rm -rf วิ่งมาหนึ่งวันครึ่งและในที่สุดฉันก็ฆ่ามันโดยที่ไม่รู้เลยว่ามันทำอะไรได้จริงหรือไม่ ฉันต้องการแถบความคืบหน้า
BMDan

4
สำหรับ rm นั้นช้ามาก "time find. -delete" บนไฟล์ 30k: 0m0.357s / 0m0.019s / 0m0.337s จริง / user / sys "time (ls -1U | xargs rm -f)" ในไฟล์เดียวกัน: 0m0.366s / 0m0.025s / 0m0.340s ซึ่งเป็นขอบเขตอาณาเขตของข้อผิดพลาดโดยทั่วไป
BMDan

1
คุณสามารถเรียกใช้strace -r -p <pid of rm>เพื่อแนบกับกระบวนการ rm ที่รันอยู่แล้ว จากนั้นคุณจะเห็นว่าการunlinkเลื่อนของระบบผ่านไปเร็วแค่ไหน ( -rกำหนดเวลาตั้งแต่การเรียกระบบก่อนหน้านี้ที่จุดเริ่มต้นของทุกบรรทัด)
Peter Cordes

2

มีการdir_indexตั้งค่าสำหรับระบบไฟล์หรือไม่? ( tune2fs -l | grep dir_index) ถ้าไม่เปิดใช้งาน โดยปกติแล้วจะใช้สำหรับ RHEL ใหม่


1
ใช่มันเปิดใช้งาน แต่ข้อเสนอแนะที่ยอดเยี่ยม!
BMDan

2

สองสามปีหลังฉันพบไดเรกทอรีที่มีไฟล์XML 16 ล้านไฟล์ใน /ระบบไฟล์ เนื่องจากการวิพากษ์วิจารณ์ของเซิร์ฟเวอร์เราใช้คำสั่งต่อไปนี้ซึ่งใช้เวลาประมาณ30 ชั่วโมงจึงจะเสร็จสิ้น:

perl -e 'for(<*>){((stat)[9]<(unlink))}'

มันเป็นhdd เก่า7200 รอบต่อนาทีและแม้จะมีคอขวด IO และ CPU spikes เว็บเซิร์ฟเวอร์เก่ายังคงให้บริการ


1

ตัวเลือกที่ฉันชอบคือแนวทาง newfs แนะนำแล้ว ปัญหาพื้นฐานคืออีกครั้งตามที่ระบุไว้แล้วการสแกนเชิงเส้นเพื่อจัดการการลบเป็นปัญหา

rm -rfควรใกล้เหมาะสมที่สุดสำหรับระบบไฟล์โลคัล (NFS จะแตกต่างกัน) แต่ในล้านไฟล์มี 36 ไบต์ต่อชื่อไฟล์และ 4 ต่อ inode (เดาไม่ตรวจสอบค่าสำหรับ ext3) นั่นคือ 40 * ล้านเพื่อเก็บไว้ใน RAM สำหรับไดเรกทอรี

โดยการเดาว่าคุณกำลังหน่วยความจำแคชเมทาดาทาของระบบแฟ้มใน Linux ดังนั้นบล็อกสำหรับหน้าหนึ่งของไฟล์ไดเรกทอรีจะถูกลบออกในขณะที่คุณยังคงใช้อีกส่วนหนึ่งเพียงกดหน้าแคชอีกครั้งเมื่อหน้าถัดไป ไฟล์ถูกลบ การปรับประสิทธิภาพของ Linux ไม่ใช่พื้นที่ของฉัน แต่ / proc / sys / {vm, fs} / อาจมีบางสิ่งที่เกี่ยวข้อง

หากคุณสามารถหยุดทำงานได้คุณอาจลองเปิดใช้คุณลักษณะ dir_index มันสลับดัชนีไดเรกทอรีจากเชิงเส้นเป็นสิ่งที่ดีที่สุดสำหรับการลบในไดเรกทอรีขนาดใหญ่ (hashed b-trees) tune2fs -O dir_index ...ตามด้วยการe2fsck -Dทำงาน อย่างไรก็ตามในขณะที่ฉันมั่นใจว่าสิ่งนี้จะช่วยให้ก่อนมีปัญหาฉันไม่ทราบว่าการแปลง (e2fsck กับ-D) ทำงานอย่างไรเมื่อจัดการกับไดเรกทอรี v.large ที่มีอยู่ สำรองข้อมูล + suck-it-and-see


1
pubbs.net/201008/squid/ ......แนะนำว่า/proc/sys/fs/vfs_cache_pressureอาจเป็นค่าที่ใช้ แต่ฉันไม่ทราบว่าไดเรกทอรีนั้นนับรวมในแคชของหน้าเว็บ (เพราะนั่นคือสิ่งที่มันเป็น) หรือแคช inode (เพราะแม้จะไม่ใช่ inode เป็นข้อมูลเมตา FS และรวมเข้าด้วยกันด้วยเหตุผลนั้น) อย่างที่ฉันพูดการปรับแต่ง Linux VM ไม่ใช่พื้นที่ของฉัน เล่นและดูว่ามีอะไรช่วย
Phil P

1

เห็นได้ชัดว่าไม่ใช่แอปเปิ้ลแอปเปิ้ลที่นี่ แต่ฉันตั้งค่าการทดสอบเล็กน้อยและทำต่อไปนี้:

สร้าง 100,000 ไฟล์ขนาด 512 ไบต์ในไดเรกทอรี ( ddและ/dev/urandomในลูป); ลืมเวลา แต่ใช้เวลาประมาณ 15 นาทีในการสร้างไฟล์เหล่านั้น

เรียกใช้ข้อมูลต่อไปนี้เพื่อลบไฟล์ที่กล่าวว่า:

ls -1 | wc -l && time find . -type f -delete

100000

real    0m4.208s
user    0m0.270s
sys     0m3.930s 

นี่คือกล่อง Pentium 4 2.8GHz (สองร้อย GB IDE 7200 RPM ฉันคิดว่า; EXT3) เคอร์เนล 2.6.27


น่าสนใจดังนั้นความจริงที่ว่าไฟล์ถูกสร้างขึ้นมาเป็นระยะเวลานานมีความเกี่ยวข้องกันหรือไม่? แต่นั่นไม่สำคัญ บล็อกแคชควรมีบล็อกเมตาดาต้าที่เกี่ยวข้องทั้งหมดใน RAM อาจเป็นเพราะการยกเลิกการเชื่อมโยง (2) เป็นธุรกรรม? ในการประมาณค่าของคุณการปิดการทำเจอร์นัลในช่วงเวลาของ rm เป็นวิธีแก้ปัญหาที่มีศักยภาพ ดูเหมือนว่าคุณสามารถปิดการทำเจอร์นัลทั้งหมดบนระบบไฟล์ที่เมาท์ได้โดยไม่ต้องใช้ tune2fs / fsck / reboot ซึ่งค่อนข้างเอาชนะวัตถุประสงค์ได้
BMDan

ฉันไม่สามารถแสดงความคิดเห็นในนั้น แต่ anecdotally (NIX ในการอภิปรายต่าง ๆ ในช่วงปีที่ผ่านมา) ผมเคยได้ยินเสมอว่าrmช้าอย่างน่ากลัวในจำนวนมากของไฟล์ดังนั้นfind -deleteตัวเลือก ด้วย wildcard บนเชลล์มันจะขยายชื่อไฟล์แต่ละรายการที่จับคู่กันและฉันสมมติว่ามีบัฟเฟอร์หน่วยความจำที่ จำกัด สำหรับสิ่งนั้นดังนั้นคุณสามารถดูว่ามันจะไม่มีประสิทธิภาพอย่างไร
gravyface

1
rm จะช้าเพราะค้นหาไฟล์ตามชื่อซึ่งหมายความว่าวนซ้ำรายการไดเรกทอรีทีละรายการจนกว่าจะพบ ในกรณีนี้เนื่องจากแต่ละรายการจะถูกส่งเป็น (ณ จุดนั้น) รายการแรกในรายการ (ls -U / ls -f) รายการควรจะเกือบเร็ว ที่กล่าวว่า rm -rf <dir> ซึ่งควรทำงานเหมือนแชมป์ได้ช้าเท่าที่ควร บางทีอาจถึงเวลาที่จะเขียน patch เพื่อ coreutils เพื่อเพิ่มความเร็วในการลบขนาดใหญ่? อาจเป็นการแอบซ่อน / เรียงลำดับในแบบวนซ้ำเพื่อใช้ rm -rf หรือไม่? ความไม่แน่นอนเช่นนี้คือเหตุผลที่ฉันถามคำถาม ;)
BMDan

1
รีบูตเครื่องหลังจากที่คุณเรียกใช้ขั้นตอนการสร้าง คุณควรลบให้ช้าลงอย่างเห็นได้ชัด
แมตต์

1

บางครั้ง Perl สามารถทำงานสิ่งมหัศจรรย์ในกรณีเช่นนี้ คุณเคยลองแล้วหรือไม่ถ้าสคริปต์ขนาดเล็กเช่นนี้สามารถเอาชนะ bash และคำสั่งเชลล์พื้นฐานได้

#!/usr/bin/perl 
open(ANNOYINGDIR,"/path/to/your/directory");
@files = grep("/*\.png/", readdir(ANNOYINGDIR));
close(ANNOYINGDIR);

for (@files) {
    printf "Deleting %s\n",$_;
    unlink $_;
}

หรืออีกวิธีหนึ่งอาจเร็วกว่าคือ Perl

#!/usr/bin/perl
unlink(glob("/path/to/your/directory/*.png")) or die("Could not delete files, this happened: $!");

แก้ไข:ฉันเพิ่งลองสคริปต์ Perl ของฉัน verbose ยิ่งทำสิ่งที่ถูกต้อง ในกรณีของฉันฉันลองกับเซิร์ฟเวอร์เสมือนที่มี RAM 256 MB และไฟล์ครึ่งล้าน

time find /test/directory | xargs rm ผล:

real    2m27.631s
user    0m1.088s
sys     0m13.229s

เปรียบเทียบกับ

time perl -e 'opendir(FOO,"./"); @files = readdir(FOO); closedir(FOO); for (@files) { unlink $_; }'

real    0m59.042s
user    0m0.888s
sys     0m18.737s

ฉันลังเลที่จะจินตนาการว่าการเรียก glob () จะทำอะไร; ฉันคิดว่ามันเป็นเรื่องอื้อฉาว () ถ้าเป็นเช่นนั้นจะต้องใช้เวลาตลอดไปเพื่อกลับ การดัดแปลงคำแนะนำแรกที่ไม่ได้อ่านรายการ dir ล่วงหน้าทั้งหมดอาจมีบางขา อย่างไรก็ตามในรูปแบบปัจจุบันมันก็จะใช้ซีพียูในปริมาณที่ไม่บริสุทธิ์เพียงแค่อ่านรายการไดเรกทอรีทั้งหมดในครั้งเดียว ส่วนหนึ่งของเป้าหมายที่นี่คือการแบ่งและพิชิต; รหัสนี้ไม่แตกต่างจาก 'rm -f * .png' โดยพื้นฐานแม้ว่าจะมีปัญหาเกี่ยวกับการขยายเชลล์ ถ้ามันช่วยได้ฉันไม่มีอะไรในไดเรกทอรีที่ฉันไม่ต้องการลบ
BMDan

ฉันต้องลองอีกครั้งเมื่อทำงาน ฉันพยายามสร้างไฟล์ 100,000 ไฟล์ในไดเรกทอรีเดียวและค้นหาการรวมกันของ + xargs + rm ใช้เวลา 7.3 วินาที, Perl + unlink (glob) ... การรวมกันเสร็จใน 2.7 วินาที พยายามสองสามครั้งผลลัพธ์ก็เหมือนกันเสมอ ที่ทำงานฉันจะลองด้วยไฟล์เพิ่มเติม
Janne Pikkarainen

ฉันเรียนรู้สิ่งใหม่ขณะทดสอบสิ่งนี้ อย่างน้อยด้วย ext3 และ ext4 รายการไดเรกทอรีนั้นยังคงมีขนาดใหญ่แม้หลังจากลบไฟล์ทั้งหมดจากที่นั่น หลังจากการทดสอบสองสามไดเรกทอรีของฉัน / tmp / test ใช้พื้นที่ว่างบนดิสก์ 15 MB มีวิธีอื่นในการทำความสะอาดที่นอกเหนือจากการลบไดเรกทอรีและสร้างมันใหม่?
Janne Pikkarainen

2
ไม่คุณต้องสร้างใหม่ ฉันได้สิ่งนี้เมื่อต้องรับมือกับระบบอีเมลและโฟลเดอร์ต่อผู้รับและการล้างข้อมูลหลังจากปัญหาสำคัญ: ไม่มีทางอื่นนอกจากสร้างไดเรกทอรีใหม่และสับไดเรกทอรีเกี่ยวกับ ดังนั้นคุณสามารถลดระยะเวลาเมื่อไม่มีไดเรกทอรี แต่ไม่ต้องกำจัดมัน
Phil P

โปรดทราบว่า glob () จะเรียงลำดับผลลัพธ์ให้มากที่สุดเท่าที่เชลล์ globbing ทำตามปกติดังนั้นเนื่องจากคุณมีไฟล์ 100k เท่านั้นทุกอย่างลงตัวและเรียงได้อย่างรวดเร็ว ด้วยไดเรกทอรีที่ใหญ่กว่าคุณจะต้องการ opendir () / readdir () / closedir () เพียงเพื่อหลีกเลี่ยงการเรียงลำดับ [ฉันพูดตามปกติสำหรับเชลล์เนื่องจาก zsh มีตัวปรับแบบกลมเพื่อให้เรียงลำดับไม่เรียงลำดับซึ่งมีประโยชน์เมื่อจัดการกับไฟล์จำนวนมาก *(oN)]
Phil P

1

จากสิ่งที่ฉันจำได้ว่าการลบ inode ใน ext filesystems คือ O (n ^ 2) ดังนั้นยิ่งคุณลบไฟล์มากเท่าไหร่ก็จะยิ่งเหลือน้อยเท่านั้น

มีครั้งหนึ่งผมต้องเจอกับปัญหาที่คล้ายกัน (แม้ว่าประมาณการของฉันมองไปที่ ~ 7h เวลาลบ) คือในท้ายที่สุดไป jftuga แนะนำเส้นทางในการแสดงความคิดเห็นก่อน


0

นี่ไม่ใช่คำตอบที่แท้จริง แต่ ...

เป็นไปได้ไหมที่จะแปลงระบบไฟล์เป็น ext4 และดูว่ามีอะไรเปลี่ยนแปลงหรือไม่?


ดูเหมือนว่าการทำสิ่งนี้ "สด" ต้องใช้ fsck บนระบบไฟล์ที่เมาท์ซึ่งก็คือ ... น่ากลัว มีวิธีที่ดีกว่านี้ไหม?
BMDan

ระบบไฟล์จะต้องถูก unmount ก่อนการแปลงเช่นก่อนคำสั่ง tunefs ที่จำเป็น
marcoc

0

เอาล่ะสิ่งนี้ได้รับการคุ้มครองในรูปแบบต่างๆในส่วนที่เหลือของเธรด แต่ฉันคิดว่าฉันจะโยนในสองเซ็นต์ของฉัน ผู้ร้ายประสิทธิภาพในกรณีของคุณอาจอ่าน คุณกำลังเรียกคืนรายการไฟล์ที่ไม่จำเป็นต้องเรียงตามลำดับบนดิสก์ซึ่งเป็นสาเหตุที่ทำให้เข้าถึงดิสก์ได้ทุกที่เมื่อคุณยกเลิกการเชื่อมโยง ไฟล์มีขนาดเล็กพอที่การดำเนินการยกเลิกการเชื่อมโยงอาจไม่ได้กระโดดไปรอบ ๆ โดยไม่มีการเว้นวรรค หากคุณอ่านแล้วเรียงลำดับตามไอโหนดจากน้อยไปมากคุณอาจได้รับประสิทธิภาพที่ดีขึ้น ดังนั้น readdir เป็น ram (เรียงตาม inode) -> unlink -> profit

Inode เป็นการประมาณคร่าวๆที่นี่ฉันคิดว่า .. แต่จากการใช้งานของคุณมันอาจจะแม่นยำ ...


1
แก้ไขให้ถูกต้องหากฉันผิด แต่การยกเลิกการเชื่อมโยง (2) ไม่ได้เป็นศูนย์ inode มันจะลบการอ้างอิงไปจากไดเรกทอรี ฉันชอบ chutzpah ของวิธีการนี้ แต่ สนใจที่จะใช้เวลาทดลองและดูว่ามันถือจริงหรือไม่?
BMDan

0

ฉันอาจจะแปลคอมไพเลอร์ C และทำเทียบเท่าคุณธรรมของสคริปต์ของคุณ นั่นคือใช้opendir(3)ในการรับการจัดการไดเรกทอรีจากนั้นใช้readdir(3)เพื่อรับชื่อของไฟล์จากนั้นนับขึ้นไฟล์ที่ฉันยกเลิกการเชื่อมโยงพวกเขาและอีกครั้งในขณะที่พิมพ์ "% d ไฟล์ที่ถูกลบ" (และอาจเป็นเวลาที่ผ่านไปหรือประทับเวลาปัจจุบัน)

ฉันไม่คาดหวังว่ามันจะเร็วกว่ารุ่นเชลล์สคริปต์อย่างเห็นได้ชัดเพียงว่าฉันเคยต้องคอมไพล์คอมไพเลอร์ครั้งแล้วครั้งเล่าเพราะไม่มีวิธีที่ดีในการทำสิ่งที่ฉันต้องการจากเชลล์หรือเพราะ ในขณะที่สามารถใช้งานได้ในเชลล์มันก็ช้าลงอย่างไม่มีประสิทธิภาพ


อย่างน้อยที่สุดเขาสามารถเริ่มต้นได้โดยการปรับเปลี่ยนรหัสที่มาของ RM จากcoreutils
Cristian Ciupitu

0

คุณอาจพบปัญหาการเขียนซ้ำกับไดเรกทอรี ลองลบไฟล์ใหม่ล่าสุดก่อน ดูตัวเลือกการเชื่อมต่อที่จะเลื่อนการเขียนกลับไปที่ดิสก์

สำหรับแถบความคืบหน้าให้ลองใช้สิ่งที่ต้องการ rm -rv /mystuff 2>&1 | pv -brtl > /dev/null


ในแง่ของการลบไฟล์ใหม่ล่าสุดก่อน: ls -Ur? ฉันค่อนข้างแน่ใจว่าจะโหลดรายการ dir จากนั้นกลับรายการพวกเขา; ฉันไม่เชื่อว่า ls ฉลาดพอที่จะเริ่มในตอนท้ายของรายการ dir และย้อนกลับไปสู่จุดเริ่มต้น "ls -1" อาจไม่ใช่ความคิดที่ดีเนื่องจากอาจใช้เวลาแกนมากกว่า 50 MB และใช้เวลาหลายนาที คุณต้องการ "ls -U" หรือ "ls -f"
BMDan

เป็นไปได้ว่าจะใช้งานได้จริงหากชื่อไฟล์เพิ่มขึ้นในรูปแบบที่คาดการณ์ได้ อย่างไรก็ตามคุณลอง ls -1 ของฉันเพื่อย้อนกลับและไปที่ xargs ใช้ไฟล์แทนไพพ์หากคุณต้องการดูผลลัพธ์ระดับกลางของคุณ คุณยังไม่ได้ให้ข้อมูลใด ๆ เกี่ยวกับการตั้งชื่อไฟล์ คุณจะสร้างลายในสิ่งที่ตรงกันข้ามและลบไฟล์โดยใช้รูปแบบ คุณอาจต้องจัดการกับรายการไฟล์ที่หายไป ได้รับความคิดเห็นของคุณในหน่วยความจำที่จำเป็นคุณมีความคิดของ I / O ต้องเขียนไดเรกทอรี
BillThor

0

นี่คือวิธีที่ฉันลบไฟล์การติดตามนับล้านที่บางครั้งสามารถรวบรวมบนเซิร์ฟเวอร์ฐานข้อมูล Oracle ขนาดใหญ่:

for i in /u*/app/*/diag/*/*/*/trace/*.tr? ; do rm $i; echo -n . ;  done

ฉันพบว่าสิ่งนี้ส่งผลให้มีการลบอย่างช้าๆพอสมควรซึ่งมีผลกระทบต่อประสิทธิภาพการทำงานของเซิร์ฟเวอร์ต่ำซึ่งโดยปกติจะมีบางสิ่งบางอย่างตามชั่วโมงต่อล้านไฟล์ในการตั้งค่า "ปกติ" 10,000 IOPS

มักจะใช้เวลาหลายนาทีก่อนที่ไดเรกทอรีจะถูกสแกนรายการไฟล์เริ่มต้นที่สร้างขึ้นและไฟล์แรกจะถูกลบ จากที่นั่นและต่อไป ถูกสะท้อนสำหรับทุกไฟล์ที่ถูกลบ

การหน่วงเวลาที่เกิดจากการสะท้อนไปยังเครื่องเทอร์มินัลได้พิสูจน์แล้วว่ามีความล่าช้าเพียงพอที่จะป้องกันการโหลดที่สำคัญในขณะที่การลบกำลังดำเนินอยู่


คุณกำลังถูกกินโดยมีชีวิตกลม แล้วจะมีอะไรที่มากกว่านี้อีกfind /u* -maxdepth 3 -mindepth 3 -type d -path '*/app/*' -name diag -print0 | xargs -0I = find = -mindepth 4 -maxdepth 4 -type d -name 'trace' -print0 | xargs -0I = find = -mindepth 1 -maxdepth 1 -name '*.tr'ไหม: เพิ่ม-deleteไปที่รายการสุดท้ายเพื่อลบสิ่งต่าง ๆ จริง ๆ ; ตามที่เขียนไว้เพียงแค่แสดงสิ่งที่จะลบ โปรดทราบว่าสิ่งนี้เหมาะสำหรับสถานการณ์ที่คุณมีสิ่งที่น่าสนใจมากมายในไดเรกทอรีใกล้เคียง หากไม่ใช่ในกรณีนี้คุณสามารถทำให้ตรรกะเป็นเรื่องง่ายขึ้นมาก
BMDan

find -delete มีแนวโน้มที่จะทำให้ I / O มากเกินไปและส่งผลกระทบต่อประสิทธิภาพการผลิตได้ง่าย บางทีด้วยอิออน
Roy

มันทำให้ทุกอย่างที่ I / O เพียงแค่มีประสิทธิภาพมากขึ้น! globbing คือทั้งหมดที่ด้านหน้าโหลดสำหรับตัวอย่างของคุณ (นั่นคือรายการเต็มรูปแบบของไฟล์ที่ถูกสร้างขึ้นก่อนที่จะเป็นครั้งแรกที่rmเกิดขึ้น) เพื่อให้คุณมีประสิทธิภาพค่อนข้าง I / O ที่เริ่มต้นจากที่ตามมาด้วยความเจ็บปวดออกจากการสั่งซื้อrmของ ที่อาจไม่ก่อให้เกิด I ​​/ O มากนัก แต่เกี่ยวข้องกับการscandirเดินไดเรกทอรีซ้ำ ๆ (ไม่ก่อให้เกิด I ​​/ O เพราะมันถูกโหลดไปยังแคชบล็อกแล้วดูเพิ่มเติมvfs_cache_pressure) หากคุณต้องการที่จะชะลอตัวลงสิ่งioniceที่เป็นตัวเลือก แต่ผมอาจจะใช้เศษส่วนสองsleeps
BMDan

find /u*/app/*/diag -path '*/trace/*.tr' -execdir rm {} +จะเรียกใช้หนึ่งrmไดเรกทอรีต่อหนึ่งดังนั้นคุณจะมีค่าใช้จ่าย CPU น้อยลง ตราบใดที่คุณมีเวลาซีพียูจำนวนมากในการสำรองดิสก์ throttling IO โดยการrmผ่านกระบวนการทั้งหมดสำหรับทุกunlinkงานฉันเดา แต่มันก็น่าเกลียด Perl ด้วยการนอนหลับต่อการยกเลิกการเชื่อมโยงจะดีกว่าหากการนอนระหว่างrmไดเรกทอรีทั้งหมดในเวลานั้นเกินไป ( -execdir sh -c ...อาจจะ)
Peter Cordes

-1

คุณสามารถใช้คุณสมบัติการขนานของ 'xargs':

ls -1|xargs -P nb_concurrent_jobs -n nb_files_by_job rm -rf

1
สิ่งนี้จะไม่ช่วย คอขวดคือ I / O แบบสุ่มที่ไม่ดีในไดรฟ์ การลบแบบขนานอาจทำให้แย่ลงและเพิ่มภาระของ CPU
Wim Kerkhoff

-2
ls|cut -c -4|sort|uniq|awk '{ print "rm -rf " $1 }' | sh -x

1
ว้าว. ฉันเดาว่ามันค่อนข้างแน่นหนาในค่าย "มากกว่าหนึ่งวิธีในการสกินแมว" อย่างจริงจังแม้ว่ามีการเรียงลำดับและ uniq? "ls" เรียงลำดับตามค่าเริ่มต้นแล้วและฉันมั่นใจว่าหวังว่าชื่อไฟล์จะไม่ซ้ำกัน : /
BMDan

-2

อันที่จริงอันนี้ดีกว่านิดหน่อยถ้าเชลล์ที่คุณใช้ทำการขยายบรรทัดคำสั่ง:

ls|cut -c -4|sort|uniq|awk '{ print "echo " $1 ";rm -rf " $1 "*"}' |sh
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.