การแคชจากระยะไกล

หน้านี้ครอบคลุมการแคชระยะไกล การตั้งค่าเซิร์ฟเวอร์เพื่อโฮสต์แคช และการเรียกใช้บิลด์โดยใช้แคชระยะไกล

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

ภาพรวม

Bazel จะแบ่งบิลด์ออกเป็นขั้นตอนที่แยกกัน ซึ่งเรียกว่าการดำเนินการ การดำเนินการแต่ละรายการมีอินพุต ชื่อเอาต์พุต บรรทัดคำสั่ง และตัวแปรสภาพแวดล้อม ระบบจะประกาศอินพุตที่จำเป็นและเอาต์พุตที่คาดหวังอย่างชัดเจนสำหรับการดำเนินการแต่ละรายการ

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

วิธีใช้การแคชระยะไกล

  • ตั้งค่าเซิร์ฟเวอร์เป็นแบ็กเอนด์ของแคช
  • กำหนดค่าบิลด์ Bazel ให้ใช้แคชระยะไกล
  • ใช้ Bazel เวอร์ชัน 0.10.0 ขึ้นไป

แคชระยะไกลจะจัดเก็บข้อมูล 2 ประเภท ได้แก่

  • แคชการดำเนินการ ซึ่งเป็นการแมปแฮชการดำเนินการกับข้อมูลเมตาของผลการดำเนินการ
  • ที่เก็บข้อมูลที่ระบุตำแหน่งตามเนื้อหา (CAS) ของไฟล์เอาต์พุต

โปรดทราบว่าแคชระยะไกลจะจัดเก็บ stdout และ stderr สำหรับการดำเนินการทุกรายการด้วย ดังนั้น การตรวจสอบ stdout/stderr ของ Bazel จึงไม่ใช่สัญญาณที่ดีในการ ประมาณการฮิตของแคช

วิธีที่บิลด์ใช้การแคชระยะไกล

เมื่อตั้งค่าเซิร์ฟเวอร์เป็นแคชระยะไกลแล้ว คุณจะใช้แคชได้หลายวิธี ดังนี้

  • อ่านและเขียนไปยังแคชระยะไกล
  • อ่านและ/หรือเขียนไปยังแคชระยะไกล ยกเว้นเป้าหมายที่เฉพาะเจาะจง
  • อ่านจากแคชระยะไกลเท่านั้น
  • ไม่ใช้แคชระยะไกลเลย

เมื่อเรียกใช้บิลด์ Bazel ที่อ่านและเขียนไปยังแคชระยะไกลได้ บิลด์จะทำตามขั้นตอนต่อไปนี้

  1. Bazel สร้างกราฟของเป้าหมายที่ต้องสร้าง แล้วสร้างรายการการดำเนินการที่จำเป็น การดำเนินการแต่ละรายการมีอินพุตและชื่อไฟล์เอาต์พุตที่ประกาศไว้
  2. Bazel ตรวจสอบเอาต์พุตของบิลด์ที่มีอยู่ในเครื่องภายในและนำเอาต์พุตที่พบไปใช้ซ้ำ
  3. Bazel ตรวจสอบเอาต์พุตของบิลด์ที่มีอยู่ในแคช หากพบเอาต์พุต Bazel จะดึงเอาต์พุต ซึ่งเรียกว่าพบแคช
  4. สำหรับการดำเนินการที่จำเป็นซึ่งไม่พบเอาต์พุต Bazel จะดำเนินการในเครื่องและสร้างเอาต์พุตของบิลด์ที่จำเป็น
  5. ระบบจะอัปโหลดเอาต์พุตของบิลด์ใหม่ไปยังแคชระยะไกล

การตั้งค่าเซิร์ฟเวอร์เป็นแบ็กเอนด์ของแคช

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

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

  • ความเร็วเครือข่าย เช่น หากทีมของคุณอยู่ในออฟฟิศเดียวกัน คุณอาจต้องการเรียกใช้เซิร์ฟเวอร์ภายในของคุณเอง
  • ความปลอดภัย แคชระยะไกลจะมีไบนารีของคุณ ดังนั้นจึงต้องมีความปลอดภัย
  • ความสะดวกในการจัดการ เช่น Google Cloud Storage เป็นบริการที่มีการจัดการครบวงจร

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

nginx

nginx เป็นเว็บเซิร์ฟเวอร์แบบโอเพนซอร์ส โดยสามารถใช้เป็นแคชระยะไกลสำหรับ Bazel ได้ด้วย [โมดูล WebDAV] ใน Debian และ Ubuntu คุณสามารถติดตั้งแพ็กเกจ nginx-extras ได้ ใน macOS nginx จะพร้อมใช้งานผ่าน Homebrew ดังนี้

brew tap denji/nginx
brew install nginx-full --with-webdav

ด้านล่างนี้คือตัวอย่างการกำหนดค่าสำหรับ nginx โปรดทราบว่าคุณจะต้องเปลี่ยน /path/to/cache/dir เป็นไดเรกทอรีที่ถูกต้องซึ่ง nginx มีสิทธิ์เขียนและอ่าน คุณอาจต้องเปลี่ยนตัวเลือก client_max_body_size เป็นค่าที่มากขึ้นหากมีไฟล์เอาต์พุตขนาดใหญ่ เซิร์ฟเวอร์จะต้องมีการกำหนดค่าอื่นๆ เช่น การตรวจสอบสิทธิ์

ตัวอย่างการกำหนดค่าสำหรับส่วน server ใน nginx.conf

location /cache/ {
  # The path to the directory where nginx should store the cache contents.
  root /path/to/cache/dir;
  # Allow PUT
  dav_methods PUT;
  # Allow nginx to create the /ac and /cas subdirectories.
  create_full_put_path on;
  # The maximum size of a single file.
  client_max_body_size 1G;
  allow all;
}

bazel-remote

bazel-remote เป็นแคชบิลด์ระยะไกลแบบโอเพนซอร์สที่คุณใช้ในโครงสร้างพื้นฐานได้ โดยมีการใช้งานจริงในหลายบริษัทอย่างประสบความสำเร็จตั้งแต่ต้นปี 2018 โปรดทราบว่าโปรเจ็กต์ Bazel ไม่มีการสนับสนุนด้านเทคนิคสำหรับ bazel-remote

แคชนี้จะจัดเก็บเนื้อหาไว้ในดิสก์และมีระบบจัดการหน่วยความจำที่ไม่ใช้แล้วเพื่อบังคับใช้ขีดจำกัดพื้นที่เก็บข้อมูลสูงสุดและล้างอาร์ติแฟกต์ที่ไม่ได้ใช้ แคชพร้อมใช้งานเป็น [อิมเมจ Docker] และโค้ดพร้อมใช้งานใน GitHub ระบบรองรับทั้ง API แคชระยะไกล REST และ gRPC

โปรดดูวิธีการใช้งานในหน้า GitHub

Google Cloud Storage

[Google Cloud Storage] เป็นที่เก็บข้อมูลออบเจ็กต์ที่มีการจัดการครบวงจรซึ่งมี HTTP API ที่เข้ากันได้กับโปรโตคอลการแคชระยะไกลของ Bazel คุณต้องมีบัญชี Google Cloud ที่เปิดใช้การเรียกเก็บเงิน

วิธีใช้ Cloud Storage เป็นแคช

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

  2. สร้างบัญชีบริการเพื่อให้ Bazel ตรวจสอบสิทธิ์กับ Cloud Storage ดู การสร้างบัญชีบริการ

  3. สร้างคีย์ลับ JSON แล้วส่งคีย์ดังกล่าวไปยัง Bazel เพื่อตรวจสอบสิทธิ์ จัดเก็บคีย์อย่างปลอดภัย เนื่องจากทุกคนที่มีคีย์จะอ่านและเขียนข้อมูลที่กำหนดเองไปยัง/จาก Bucket ของ GCS ได้

  4. เชื่อมต่อกับ Cloud Storage โดยเพิ่มแฟล็กต่อไปนี้ลงในคำสั่ง Bazel

    • ส่ง URL ต่อไปนี้ไปยัง Bazel โดยใช้แฟล็ก: --remote_cache=https://storage.googleapis.com/bucket-name โดยที่ bucket-name คือชื่อ Bucket พื้นที่เก็บข้อมูล
    • ส่งคีย์การตรวจสอบสิทธิ์โดยใช้แฟล็ก --google_credentials=/path/to/your/secret-key.json หรือ --google_default_credentials เพื่อใช้ การตรวจสอบสิทธิ์แอปพลิเคชัน
  5. คุณสามารถกำหนดค่า Cloud Storage ให้ลบไฟล์เก่าโดยอัตโนมัติได้ หากต้องการทำเช่นนั้น โปรดดู การจัดการวงจรออบเจ็กต์

เซิร์ฟเวอร์อื่น

คุณสามารถตั้งค่าเซิร์ฟเวอร์ HTTP/1.1 ที่รองรับ PUT และ GET ให้เป็นแบ็กเอนด์ของแคชได้ ผู้ใช้รายงานว่าแคชแบ็กเอนด์ เช่น Hazelcast, Apache httpd และ AWS S3 ทำงานได้ดี

การตรวจสอบสิทธิ์

ตั้งแต่เวอร์ชัน 0.11.0 เป็นต้นมา ระบบได้เพิ่มการรองรับการตรวจสอบสิทธิ์พื้นฐาน HTTP ลงใน Bazel คุณสามารถส่งชื่อผู้ใช้และรหัสผ่านไปยัง Bazel ผ่าน URL แคชระยะไกลได้ ไวยากรณ์คือ https://username:password@hostname.com:port/path โปรดทราบว่าการตรวจสอบสิทธิ์พื้นฐาน HTTP จะส่งชื่อผู้ใช้และรหัสผ่านเป็นข้อความธรรมดาผ่านเครือข่าย ดังนั้นจึงจำเป็นอย่างยิ่งที่จะต้องใช้กับ HTTPS เสมอ

โปรโตคอลการแคช HTTP

Bazel รองรับการแคชระยะไกลผ่าน HTTP/1.1 โปรโตคอลนี้มีแนวคิดที่เรียบง่าย คือ ระบบจะอัปโหลดข้อมูลไบนารี (BLOB) ผ่านคำขอ PUT และดาวน์โหลดผ่านคำขอ GET ข้อมูลเมตาของผลการดำเนินการจะจัดเก็บไว้ในเส้นทาง /ac/ และไฟล์เอาต์พุตจะจัดเก็บไว้ในเส้นทาง /cas/

ตัวอย่างเช่น ลองพิจารณาแคชระยะไกลที่ทำงานภายใต้ http://localhost:8080/cache คำขอ Bazel เพื่อดาวน์โหลดข้อมูลเมตาของผลการดำเนินการสำหรับการดำเนินการที่มีแฮช SHA256 เป็น 01ba4719... จะมีลักษณะดังนี้

GET /cache/ac/01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b HTTP/1.1
Host: localhost:8080
Accept: */*
Connection: Keep-Alive

คำขอ Bazel เพื่ออัปโหลดไฟล์เอาต์พุตที่มีแฮช SHA256 เป็น 15e2b0d3... ไปยัง CAS จะมีลักษณะดังนี้

PUT /cache/cas/15e2b0d3c33891ebb0f1ef609ec419420c20e320ce94c65fbc8c3312448eb225 HTTP/1.1
Host: localhost:8080
Accept: */*
Content-Length: 9
Connection: Keep-Alive

0x310x320x330x340x350x360x370x380x39

เรียกใช้ Bazel โดยใช้แคชระยะไกล

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

นอกจากนี้ คุณอาจต้องกำหนดค่าการตรวจสอบสิทธิ์ ซึ่งจะขึ้นอยู่กับเซิร์ฟเวอร์ที่คุณเลือก

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

  • อยู่ในเครื่องภายใน
  • อยู่ในพื้นที่ทำงานของโปรเจ็กต์ ซึ่งแชร์กับทีม
  • อยู่ในระบบ CI

อ่านและเขียนไปยังแคชระยะไกล

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

ใช้แฟล็กต่อไปนี้เพื่ออ่านและเขียนไปยังแคชระยะไกล

build --remote_cache=http://your.host:port

นอกจาก HTTP แล้ว ระบบยังรองรับโปรโตคอลต่อไปนี้ด้วย ได้แก่ HTTPS, grpc, grpcs

ใช้แฟล็กต่อไปนี้เพิ่มเติมจากแฟล็กด้านบนเพื่ออ่านจากแคชระยะไกลเท่านั้น

build --remote_upload_local_results=false

ยกเว้นเป้าหมายที่เฉพาะเจาะจงจากการใช้แคชระยะไกล

หากต้องการยกเว้นเป้าหมายที่เฉพาะเจาะจงจากการใช้แคชระยะไกล ให้ติดแท็กเป้าหมายด้วย no-remote-cache เช่น

java_library(
    name = "target",
    tags = ["no-remote-cache"],
)

ลบเนื้อหาออกจากแคชระยะไกล

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

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

คุณอาจต้องการลบเนื้อหาออกจากแคชเพื่อวัตถุประสงค์ต่อไปนี้

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

ซ็อกเก็ต Unix

แคช HTTP ระยะไกลรองรับการเชื่อมต่อผ่านซ็อกเก็ตโดเมน Unix ลักษณะการทำงานจะคล้ายกับแฟล็ก --unix-socket ของ curl ใช้คำสั่งต่อไปนี้เพื่อกำหนดค่าซ็อกเก็ตโดเมน Unix

   build --remote_cache=http://your.host:port
   build --remote_proxy=unix:/path/to/socket

ระบบไม่รองรับฟีเจอร์นี้ใน Windows

แคชดิสก์

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

build --disk_cache=path/to/build/cache

คุณสามารถส่งเส้นทางที่เฉพาะเจาะจงของผู้ใช้ไปยังแฟล็ก --disk_cache โดยใช้นามแฝง ~ (Bazel จะแทนที่ด้วยไดเรกทอรีแรกของผู้ใช้ปัจจุบัน) ซึ่งจะมีประโยชน์เมื่อเปิดใช้แคชดิสก์สำหรับนักพัฒนาซอฟต์แวร์ทุกคนในโปรเจ็กต์ผ่านไฟล์ .bazelrc ที่เช็กอินของโปรเจ็กต์

ระบบจัดการหน่วยความจำที่ไม่ใช้แล้ว

ตั้งแต่ Bazel 7.4 เป็นต้นมา คุณสามารถใช้ --experimental_disk_cache_gc_max_size และ --experimental_disk_cache_gc_max_age เพื่อกำหนดขนาดสูงสุดสำหรับแคชดิสก์หรืออายุของรายการแคชแต่ละรายการ Bazel จะจัดการหน่วยความจำที่ไม่ใช้แล้วของแคชดิสก์โดยอัตโนมัติขณะที่ไม่มีการใช้งานระหว่างบิลด์ โดยคุณสามารถตั้งค่าตัวจับเวลาที่ไม่มีการใช้งานได้ด้วย --experimental_disk_cache_gc_idle_delay (ค่าเริ่มต้นคือ 5 นาที)

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

ปัญหาที่ทราบ

การแก้ไขไฟล์อินพุตระหว่างบิลด์

เมื่อมีการแก้ไขไฟล์อินพุตระหว่างบิลด์ Bazel อาจอัปโหลดผลลัพธ์ที่ไม่ถูกต้องไปยังแคชระยะไกล คุณสามารถเปิดใช้การตรวจหาการเปลี่ยนแปลงได้ด้วยแฟล็ก --experimental_guard_against_concurrent_changes ไม่มีปัญหาที่ทราบและระบบจะเปิดใช้แฟล็กนี้โดยค่าเริ่มต้นในรุ่นต่อๆ ไป ดูข้อมูลอัปเดตได้ที่ [ปัญหา #3360] โดยทั่วไปแล้ว ให้หลีกเลี่ยงการแก้ไขไฟล์ซอร์สระหว่างบิลด์

ตัวแปรสภาพแวดล้อมรั่วไหลไปยังการดำเนินการ

คำจำกัดความของการดำเนินการมีตัวแปรสภาพแวดล้อม ซึ่งอาจเป็นปัญหาสำหรับการแชร์ฮิตของแคชระยะไกลระหว่างเครื่อง ตัวอย่างเช่น สภาพแวดล้อมที่มีตัวแปร $PATH ต่างกันจะไม่แชร์ฮิตของแคช เฉพาะตัวแปรสภาพแวดล้อมที่อนุญาตพิเศษอย่างชัดเจนผ่าน --action_env เท่านั้นที่จะรวมอยู่ในคำจำกัดความของการดำเนินการ แพ็กเกจ Debian/Ubuntu ของ Bazel เคยติดตั้ง /etc/bazel.bazelrc พร้อมรายการตัวแปรสภาพแวดล้อมที่อนุญาตพิเศษ ซึ่งรวมถึง $PATH หากคุณได้รับฮิตของแคชน้อยกว่าที่คาดไว้ ให้ตรวจสอบว่าสภาพแวดล้อมของคุณไม่มีไฟล์ /etc/bazel.bazelrc เก่า

Bazel ไม่ติดตามเครื่องมือภายนอกพื้นที่ทำงาน

ปัจจุบัน Bazel ไม่ติดตามเครื่องมือภายนอกพื้นที่ทำงาน ซึ่งอาจเป็นปัญหาได้หากการดำเนินการใช้คอมไพเลอร์จาก /usr/bin/ จากนั้น ผู้ใช้ 2 รายที่ติดตั้งคอมไพเลอร์ต่างกันจะแชร์ฮิตของแคชอย่างไม่ถูกต้อง เนื่องจากเอาต์พุตต่างกันแต่มีแฮชการดำเนินการเดียวกัน ดูข้อมูลอัปเดตได้ที่ ปัญหา #4558

สถานะที่เพิ่มขึ้นในหน่วยความจำจะหายไปเมื่อเรียกใช้บิลด์ภายในคอนเทนเนอร์ Docker Bazel ใช้สถาปัตยกรรมเซิร์ฟเวอร์/ไคลเอ็นต์แม้ว่าจะเรียกใช้ในคอนเทนเนอร์ Docker เดียวก็ตาม ในฝั่งเซิร์ฟเวอร์ Bazel จะรักษาสถานะในหน่วยความจำซึ่งจะช่วยเร่งความเร็วของบิลด์ เมื่อเรียกใช้บิลด์ภายในคอนเทนเนอร์ Docker เช่น ใน CI สถานะในหน่วยความจำจะหายไปและ Bazel ต้องสร้างสถานะใหม่ก่อนที่จะใช้แคชระยะไกล