การแก้ไขข้อบกพร่องของ Hit แคชระยะไกลสำหรับการดำเนินการระยะไกล

หน้านี้อธิบายวิธีตรวจสอบอัตรา Hit ของแคชและวิธีตรวจสอบการไม่พบแคชในบริบทของการดำเนินการระยะไกล

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

การตรวจสอบอัตรา Hit ของแคช

ในเอาต์พุตมาตรฐานของการเรียกใช้ Bazel ให้ดูบรรทัด INFO ที่แสดงรายการกระบวนการ ซึ่งสอดคล้องกับการดำเนินการของ Bazel โดยคร่าวๆ บรรทัดดังกล่าวจะมีรายละเอียด ที่มีการเรียกใช้การดำเนินการ มองหาป้ายกำกับ remote ซึ่งระบุการดำเนินการที่ทำจากระยะไกล linux-sandbox สำหรับการดำเนินการที่ดำเนินการในแซนด์บ็อกซ์ในเครื่อง และค่าอื่นๆ สำหรับกลยุทธ์การดำเนินการอื่นๆ การดำเนินการที่มีผลลัพธ์มาจากแคชระยะไกลจะแสดงเป็น remote cache hit

เช่น

INFO: 11 processes: 6 remote cache hit, 3 internal, 2 remote.

ในตัวอย่างนี้มี Hit แคชระยะไกล 6 ครั้ง และการดำเนินการ 2 รายการไม่มี Hit แคชและมีการดำเนินการจากระยะไกล คุณสามารถละเว้นส่วนภายใน 3 ส่วนได้ โดยปกติจะเป็นการดำเนินการภายในเพียงเล็กน้อย เช่น การสร้างลิงก์สัญลักษณ์ Hit แคชในเครื่องจะไม่รวมอยู่ในสรุปนี้ หากมีกระบวนการ 0 รายการ (หรือน้อยกว่าที่คาดไว้) ให้เรียกใช้ bazel clean ตามด้วยคำสั่ง build/test

การแก้ปัญหาการตีข้อมูลแคช

หากคุณไม่ได้รับอัตรา Hit ของแคชตามที่คาดไว้ ให้ทำดังนี้

ตรวจสอบว่าการเรียกใช้คำสั่งบิลด์/ทดสอบเดียวกันอีกครั้งจะสร้าง Hit ของแคช

  1. เรียกใช้บิลด์และ/หรือการทดสอบที่คุณต้องการป้อนข้อมูลในแคช เมื่อเรียกใช้บิลด์ใหม่บนสแต็กหนึ่งๆ เป็นครั้งแรก คุณจะไม่พบ Hit แคชระยะไกล ระบบจะจัดเก็บผลลัพธ์การดำเนินการไว้ในแคชและการเรียกใช้ครั้งต่อๆ ไปควรจะได้รับผลลัพธ์ดังกล่าวซึ่งเป็นส่วนหนึ่งของการดำเนินการจากระยะไกล

  2. เรียกใช้ bazel clean คำสั่งนี้จะล้างแคชในเครื่องซึ่งช่วยให้คุณตรวจสอบ Hit ของแคชระยะไกลได้โดยไม่ต้องมาสก์ผลลัพธ์ด้วยการพบแคชในเครื่อง

  3. เรียกใช้บิลด์และทดสอบที่คุณกำลังตรวจสอบอีกครั้ง (บนเครื่องเดียวกัน)

  4. ตรวจสอบบรรทัด INFO เพื่อดูอัตรา Hit ของแคช หากไม่เห็นกระบวนการใดๆ ยกเว้น remote cache hit และ internal แสดงว่าระบบกําลังสร้างและเข้าถึงแคชอย่างถูกต้อง ในกรณีนี้ ให้ข้ามไปยังส่วนถัดไป

  5. แหล่งที่มาของความคลาดเคลื่อนที่น่าจะเกิดขึ้นคือสิ่งที่ไม่สมบูรณ์ในบิลด์ ซึ่งทําให้การดำเนินการได้รับคีย์การดําเนินการที่แตกต่างกันในการเรียกใช้ 2 ครั้ง หากต้องการค้นหาการดำเนินการเหล่านั้น ให้ทำดังนี้

    ก. เรียกใช้บิลด์หรือการทดสอบที่เป็นปัญหาอีกครั้งเพื่อรับบันทึกการดำเนินการ

      bazel clean
      bazel --optional-flags build //your:target --execution_log_compact_file=/tmp/exec1.log

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

    หากแก้ปัญหาการแคชได้และตอนนี้การเรียกใช้ซ้ำทำให้เกิด Hit แคชทั้งหมด ให้ข้ามไปยังส่วนถัดไป

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

  6. ตรวจสอบว่าการดำเนินการทั้งหมดในบันทึกการดำเนินการตั้งค่า cacheable เป็น "จริง" หาก cacheable ไม่ปรากฏในบันทึกการดำเนินการสำหรับการดำเนินการที่ให้ แสดงว่ากฎที่เกี่ยวข้องอาจมีแท็ก no-cache ในคำจำกัดความในไฟล์ BUILD ดูช่อง mnemonic และ target_label ในบันทึกการดำเนินการเพื่อช่วยระบุที่มาของการดำเนินการ

  7. หากการดำเนินการเหมือนกันและ cacheable แต่ไม่มี Hit ของแคช อาจเป็นเพราะบรรทัดคำสั่งมี --noremote_accept_cached ซึ่งจะปิดใช้การค้นหาแคชสำหรับบิลด์

    หากหาบรรทัดคำสั่งจริงได้ยาก ให้ใช้บรรทัดคำสั่งตามมาตรฐานจากโปรโตคอลเหตุการณ์การสร้าง ดังนี้

    ก. เพิ่ม --build_event_text_file=/tmp/bep.txt ลงในคำสั่ง Bazel เพื่อรับบันทึกในรูปแบบข้อความ

    ข. เปิดบันทึกเวอร์ชันข้อความของบันทึกและค้นหาข้อความ structured_command_line ด้วย command_line_label: "canonical" ซึ่งจะแสดงรายการตัวเลือกทั้งหมดหลังจากขยาย

    ค. ค้นหา remote_accept_cached และตรวจสอบว่ามีการตั้งค่าเป็น false หรือไม่

    ง. หาก remote_accept_cached เป็น false ให้ตรวจสอบว่ามีการกําหนดค่าเป็น false ที่ใด นั่นคือที่บรรทัดคําสั่งหรือในไฟล์ bazelrc

ตรวจสอบการแคชในเครื่องต่างๆ

หลังจากที่การพบแคชเกิดขึ้นตามที่คาดไว้ในเครื่องเดียวกัน ให้เรียกใช้บิลด์/การทดสอบเดียวกันในเครื่องอื่น หากคุณสงสัยว่าการแคช ไม่เกิดขึ้นในอุปกรณ์ต่างๆ ให้ทำดังต่อไปนี้

  1. ทำการแก้ไขเล็กน้อยในบิลด์เพื่อหลีกเลี่ยงการใช้แคชที่มีอยู่

  2. เรียกใช้บิลด์ในเครื่องแรกด้วยคำสั่งต่อไปนี้

     bazel clean
     bazel ... build ... --execution_log_compact_file=/tmp/exec1.log
  3. เรียกใช้บิลด์บนเครื่องที่ 2 เพื่อให้แน่ใจว่ารวมการแก้ไขจากขั้นตอนที่ 1 ไว้ด้วยแล้ว

     bazel clean
     bazel ... build ... --execution_log_compact_file=/tmp/exec2.log
  4. เปรียบเทียบบันทึกการดำเนินการของ 2 รันไทม์ หากบันทึกไม่เหมือนกัน ให้ตรวจสอบการกําหนดค่าบิลด์เพื่อหาความคลาดเคลื่อน รวมถึงพร็อพเพอร์ตี้จากสภาพแวดล้อมโฮสต์ที่รั่วไหลไปยังบิลด์ใดบิลด์หนึ่ง

การเปรียบเทียบบันทึกการดำเนินการ

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

บันทึกการดําเนินการจะสร้างได้ในรูปแบบใดรูปแบบหนึ่งต่อไปนี้ แบบกะทัดรัด (--execution_log_compact_file), ไบนารี (--execution_log_binary_file) หรือ JSON (--execution_log_json_file) เราขอแนะนําให้ใช้รูปแบบกะทัดรัด เนื่องจากจะสร้างไฟล์ที่เล็กกว่ามากและมีค่าใช้จ่ายเพิ่มเติมในรันไทม์เพียงเล็กน้อย วิธีการต่อไปนี้ใช้ได้กับทุกรูปแบบ และยังแปลงค่าเหล่านี้โดยใช้เครื่องมือ //src/tools/execlog:converter ได้ด้วย

หากต้องการเปรียบเทียบบันทึกของบิลด์ 2 รายการที่ไม่ได้แชร์ Hit ของแคชตามที่คาดไว้ ให้ทําดังนี้

  1. รับบันทึกการดำเนินการจากบิลด์แต่ละรายการ แล้วจัดเก็บเป็น /tmp/exec1.log และ /tmp/exec2.log

  2. ดาวน์โหลดซอร์สโค้ด Bazel และสร้างเครื่องมือ //src/tools/execlog:parser:

    git clone https://github.com/bazelbuild/bazel.git cd bazel bazel build //src/tools/execlog:parser

  3. ใช้เครื่องมือ //src/tools/execlog:parser เพื่อแปลงบันทึกเป็นรูปแบบข้อความที่มนุษย์อ่านได้ ในรูปแบบนี้ การดำเนินการในบันทึกที่ 2 จะจัดเรียงให้ตรงกับลำดับในบันทึกแรก ซึ่งทำให้เปรียบเทียบได้ง่ายขึ้น

    bazel-bin/src/tools/execlog/parser \
      --log_path=/tmp/exec1.log \
      --log_path=/tmp/exec2.log \
      --output_path=/tmp/exec1.log.txt \
      --output_path=/tmp/exec2.log.txt
    
  4. ใช้ข้อความที่คุณต้องการแทนที่ diff /tmp/exec1.log.txt และ /tmp/exec2.log.txt