วิธีการลบไฟล์นับล้านไฟล์โดยไม่รบกวนเซิร์ฟเวอร์


11

ฉันต้องการลบไดเรกทอรีแคช nginx ซึ่งฉันลบออกอย่างรวดเร็วโดย:

mv cache cache.bak
mkdir cache
service nginx restart

ตอนนี้ฉันมีcache.bakโฟลเดอร์ที่มี 2 ล้านไฟล์ ฉันต้องการลบโดยไม่รบกวนเซิร์ฟเวอร์

ง่าย ๆrm -rf cache.bakในการทำให้เซิร์ฟเวอร์เสียหายแม้แต่การตอบสนอง HTTP ที่ง่ายที่สุดใช้เวลา 16 วินาทีในขณะที่ rm กำลังทำงานดังนั้นฉันจึงไม่สามารถทำได้

ฉันพยายามionice -c3 rm -rf cache.bakแล้ว แต่ก็ไม่ได้ช่วยอะไร เซิร์ฟเวอร์มี HDD ไม่ใช่ SSD อาจอยู่บน SSD สิ่งเหล่านี้อาจไม่มีปัญหา

ฉันเชื่อว่าทางออกที่ดีที่สุดคือการควบคุมปริมาณบางอย่างเช่นวิธีที่ตัวจัดการแคชของ nginx ทำ

คุณจะแก้ปัญหานี้อย่างไร มีเครื่องมือใดที่สามารถทำสิ่งนี้ได้อย่างแน่นอน?

ext4 บน Ubuntu 16.04


1
คุณกู้คืนจาก "rm -rf cache.bak" ได้อย่างไร ดูเหมือนว่า nginx กำลังทำงานอยู่เมื่อคุณทำการเปลี่ยนชื่อดังนั้นอาจมีการรักษาตัวอธิบายไฟล์ไว้และแม้กระทั่งเปลี่ยนเป็นไดเรกทอรีใหม่ ฉันคิดว่าคุณต้องปิด nginx ลงอย่างสมบูรณ์ลบแคชแล้วเริ่มใหม่
Jan Steinman

6
ในอนาคตโปรดติดแคชของคุณในระบบไฟล์แยกต่างหาก ด้วยวิธีนี้คุณสามารถทำนุกระบบไฟล์นั้นซึ่งเร็วกว่าการพยายามลบไฟล์นับล้าน เรียนรู้สิ่งนี้อย่างยากลำบากเมื่อไม่กี่ปีที่ผ่านมาด้วยไดเรกทอรี spool hylafax ที่มี zillions ของไฟล์
Dennis Kaarsemaker

คุณเคยลองrmใช้ดีไหม?
Vladislav Rastrusny

ลอง rsync เพื่อลบอย่างรวดเร็ว - ตอบคำถามที่คล้ายกัน - unix.stackexchange.com/questions/37329/…
kawu

ขอบคุณสำหรับความคิดเห็นทั้งหมดฉันได้สรุปข้อค้นพบของฉันเพื่อเขียนคำตอบ
hyperknot

คำตอบ:


9

สร้างสคริปต์ทุบตีเช่นนี้:

#!/bin/bash
rm -- "$*"
sleep 0.5

บันทึกด้วยชื่อdeleter.shตัวอย่าง เรียกใช้chmod u+x deleter.shเพื่อให้สามารถเรียกใช้งานได้

สคริปต์นี้จะลบไฟล์ทั้งหมดที่ส่งไปเป็นอาร์กิวเมนต์แล้วสลีป 0.5 วินาที

จากนั้นคุณสามารถเรียกใช้

find cache.bak -print0 | xargs -0 -n 5 deleter.sh

คำสั่งนี้จะเรียกรายการไฟล์ทั้งหมดใน cache.bak และส่งต่อห้าชื่อไฟล์พร้อมกันไปยังสคริปต์ลบ

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


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

xargsเข้าใจขนาดสูงสุดของบรรทัดคำสั่งและพยายามไม่ให้เกินขนาดโดยปริยาย อันนี้มีข้อ จำกัด เพิ่มเติมไม่เกิน 5 เส้นทางในเวลา
BowlOfRed

1
เพิ่งทราบว่าในอัตรา 10 ไฟล์ต่อวินาทีมันจะใช้เวลา 55 ชั่วโมงในการลบ 2 ล้านไฟล์
Andrew Henle

4

คุณควรพิจารณาบันทึกแคชของคุณในระบบไฟล์แยกต่างหากที่คุณสามารถเมาน / unmount เป็นคนที่ระบุไว้ในความคิดเห็น จนกว่าคุณจะทำคุณสามารถใช้สายการบินเดียวนี้/usr/bin/find /path/to/files/ -type f -print0 -exec sleep 0.2 \; -exec echo \; -deleteโดยสมมติว่าไบนารีการค้นหาของคุณอยู่ภายใต้ / usr / bin และคุณต้องการดูความคืบหน้าบนหน้าจอ ปรับโหมดสลีปให้เหมาะสมดังนั้นคุณจะไม่เครียดกับ HDD


ไม่มีใครต้องการ-print0ที่นี่เนื่องจากคุณไม่ได้ส่งออกท่อของfindที่ใดก็ได้
Tero Kilkanen

คุณอาจสนใจสิ่งที่ rm-ing เรียกมันว่าความหวาดระแวง แต่ฉันต้องการแน่ใจเสมอว่าฉันกำลังลบไฟล์ที่ถูกต้อง
อเล็กซ์

อาจริงฉันไม่ได้ถอดรหัสคำสั่งอย่างถูกต้องไม่ดี
Tero Kilkanen

3

คุณอาจต้องการลองใช้ ionice ในสคริปต์ที่ใช้เอาต์พุตของคำสั่ง find สิ่งต่อไปนี้:

ionice -c3 $(
for file in find cache.bak -type f; do
    rm $file
done
for dir in find cache.bak -depthe -type d -empty; do
    rmdir $dir
done
)

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

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

คุณอาจต้องการใช้ระบบไฟล์โดยไม่มีวารสารสำหรับแคช

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


2

ฉันได้คำตอบ / ความคิดเห็นที่เป็นประโยชน์มากมายที่นี่ซึ่งฉันต้องการสรุปและแสดงวิธีแก้ปัญหาของฉันด้วย

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

  2. ionice/ niceการแก้ปัญหาไม่ได้ทำอะไรเพราะกระบวนการลบที่เกิดจริงเกือบจะไม่มี I / O สิ่งที่ทำให้ I / O เกิดขึ้นผมเชื่อว่าระบบคิว / บัฟเฟอร์ระดับเคอร์เนล / ระบบเติมเต็มเมื่อไฟล์ถูกลบเร็วเกินไปโดยกระบวนการลบ

  3. วิธีที่ฉันแก้ไขมันคล้ายกับโซลูชันของ Tero Kilkanen แต่ไม่ต้องการเรียกเชลล์สคริปต์ ฉันใช้--bwlimitสวิตช์ในตัวของ rsync เพื่อ จำกัด ความเร็วในการลบ

คำสั่งเต็มคือ:

mkdir empty_dir
rsync -v -a --delete --bwlimit=1 empty_dir/ cache.bak/

ตอนนี้ bwlimit ระบุแบนด์วิดท์เป็นกิโลไบต์ซึ่งในกรณีนี้ใช้กับชื่อไฟล์หรือพา ธ ของไฟล์ เมื่อตั้งค่าเป็น 1 KBps จะเป็นการลบไฟล์ประมาณ 100,000 ไฟล์ต่อชั่วโมงหรือ 27 ไฟล์ต่อวินาที ไฟล์มีเส้นทางสัมพัทธ์เช่นcache.bak/e/c1/db98339573acc5c76bdac4a601f9ec1eซึ่งมีความยาว 47 ตัวอักษรดังนั้นมันจะให้ 1,000/47 ~ = 21 ไฟล์ต่อวินาทีดังนั้นมันคล้ายกับที่ฉันคาดเดา 100,000 ไฟล์ต่อชั่วโมง

ตอนนี้ทำไม--bwlimit=1? ฉันลองค่าต่าง ๆ :

  • 10,000, 1,000, 100 -> ระบบช้าลงเหมือนเมื่อก่อน
  • 10 -> ระบบทำงานได้ค่อนข้างดีชั่วครู่ แต่สร้างการชะลอตัวบางส่วนหนึ่งครั้งต่อนาทีหรือมากกว่านั้น HTTP เวลาตอบสนองยัง <1 วินาที
  • 1 -> ไม่มีการชะลอตัวของระบบเลย ฉันไม่รีบร้อนและสามารถลบไฟล์ได้ 2 ล้านไฟล์ใน <1 วันด้วยวิธีนี้ฉันเลยเลือกมัน

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


และตอนนี้ฉันอยากรู้ว่าเอฟเฟกต์ดิสก์จะเป็นอย่างไรถ้าคุณทำอะไรเช่น "mv cache.dir-old / dev / null"
ivanivan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.