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

รายงานปัญหา ดูแหล่งที่มา รุ่น Nightly · 7.4

หน้านี้จะอธิบายวิธีตรวจสอบอัตรา 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 ของแคชตามที่คาดไว้ ให้ทําดังนี้

ตรวจสอบว่าการเรียกใช้คําสั่งบิลด์/ทดสอบเดิมอีกครั้งทําให้พบรายการในแคช

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

  2. เรียกใช้ bazel clean คำสั่งนี้จะล้างแคชในเครื่อง ซึ่งจะช่วยให้คุณตรวจสอบ Hit ของแคชระยะไกลได้โดยไม่ต้องปิดบังผลลัพธ์ด้วย 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 รันไทม์ หากบันทึกไม่เหมือนกัน ให้ตรวจสอบการกําหนดค่าบิลด์เพื่อหาความคลาดเคลื่อน รวมถึงพร็อพเพอร์ตี้จากสภาพแวดล้อมโฮสต์ที่รั่วไหลไปยังบิลด์ใดบิลด์หนึ่ง

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

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

บันทึกการดำเนินการสร้างได้ 1 ใน 3 รูปแบบ ได้แก่ กะทัดรัด (--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 ให้ตรงกับลําดับในบันทึกที่ 1 เพื่อให้เปรียบเทียบได้ง่ายขึ้น

    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