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

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

แคชระยะไกลใช้โดยทีมนักพัฒนาซอฟต์แวร์และ/หรือระบบการรวมอย่างต่อเนื่อง (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 เป็นเว็บเซิร์ฟเวอร์โอเพนซอร์ส [โมดูล WebDAV] ช่วยให้ใช้เป็นแคชระยะไกลสำหรับ Bazel ได้ ใน 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 รองรับทั้ง REST และ gRPC Remote Cache API

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

Google Cloud Storage

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

หากต้องการใช้ Cloud Storage เป็นแคช ให้ทำดังนี้

  1. สร้างที่เก็บข้อมูล ตรวจสอบว่าคุณเลือกตำแหน่ง 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 คือชื่อของที่เก็บข้อมูล
    • ส่งคีย์การตรวจสอบสิทธิ์โดยใช้แฟล็ก --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 เป็นต้นไป Bazel จะรองรับการตรวจสอบสิทธิ์พื้นฐานของ HTTP คุณส่งชื่อผู้ใช้และรหัสผ่านไปยัง 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 คุณเพิ่ม Flag ลงในไฟล์ .bazelrc ได้ โดยขึ้นอยู่กับโปรเจ็กต์และ การทำงานร่วมกันของทีม

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

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

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

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

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

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

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

build --remote_upload_local_results=false

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

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

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

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

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

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

คุณอาจต้องการลบเนื้อหาออกจากแคชเพื่อดำเนินการต่อไปนี้

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

Unix Sockets

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

   build --remote_cache=http://your.host:port
   build --remote_cache_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 ต้องสร้างใหม่ก่อนใช้แคชระยะไกล