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

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

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

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

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

Google Cloud Storage

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

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

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

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

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

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

    • ส่ง URL ต่อไปนี้ไปยัง Bazel โดยใช้ Flag --remote_cache=https://storage.googleapis.com/bucket-name โดยที่ bucket-name คือชื่อที่เก็บข้อมูล
    • ส่งคีย์การตรวจสอบสิทธิ์โดยใช้แฟล็ก: --google_credentials=/path/to/your/secret-key.json หรือ --google_default_credentials เพื่อใช้ Application Authentication
  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 เพื่อใช้แคชระยะไกล ดูรายการการกําหนดค่าและ Flag ได้ที่ด้านล่าง

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

คุณอาจต้องเพิ่ม Flag เหล่านี้ในไฟล์ .bazelrc เพื่อไม่ต้องระบุทุกครั้งที่เรียกใช้ Bazel คุณจะเพิ่มแฟล็กไปยังไฟล์ .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

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

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

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

แคชของดิสก์

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

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

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

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

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

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

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

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

Bazel จะไม่ติดตามเครื่องมือที่อยู่นอกเวิร์กスペース

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

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