1 điểm bởi GN⁺ 5 giờ trước | 1 bình luận | Chia sẻ qua WhatsApp
  • zeroserve là một máy chủ HTTPS nhỏ gọn và nhanh, nhận tarball của website rồi phục vụ qua HTTP/2 và TLS 1.3, đồng thời chạy chương trình eBPF bên trong tarball như middleware sandbox không gian người dùng cho từng request
  • Không cần tệp cấu hình; chương trình eBPF quyết định định tuyến theo từng request, header, xác thực, giới hạn tốc độ và proxy, hợp nhất cấu hình khai báo kiểu nginx·Caddy với một tầng script riêng thành một thể thống nhất
  • Website được lập chỉ mục thành một tệp tar duy nhất và không giải nén ra đĩa; thay tarball và gửi SIGHUP sẽ hoán đổi website, script và dữ liệu TLS một cách nguyên tử mà không làm rớt kết nối
  • Trong benchmark HTTPS đơn nhân, zeroserve đạt 36,681 req/s với tệp tĩnh nhỏ, 46,945 req/s với JSON động eBPF 10ms, và 26,486 req/s với proxy nhỏ; tuy nhiên với proxy 100KB thì nginx dẫn trước ở mức 5,882 req/s
  • zeroserve nhắm tới việc trở thành lựa chọn thay thế cho nginx và Caddy bằng cách kết hợp triển khai bằng một tarball duy nhất, cấu hình kiểu lập trình, eBPF không gian người dùng và TLS hiện đại, nhưng với phản hồi proxy lớn thì nginx vẫn phù hợp hơn

Tổng quan

  • zeroserve là một máy chủ HTTPS nhỏ gọn, nhanh và không cần cấu hình, phục vụ một tarball website duy nhất qua HTTP/2 và TLS 1.3
  • Các chương trình eBPF đặt trong tarball sẽ chạy như middleware sandbox không gian người dùng cho mọi request, có thể xử lý rewrite request, xác thực, giới hạn tốc độ và reverse proxy backend
  • Đây là máy chủ hướng tới hiệu năng cao hơn nginx trên hầu hết các workload theo đơn nhân như tệp tĩnh nhỏ·lớn, middleware script và proxy phản hồi nhỏ
  • Script eBPF được JIT compile thành mã native và sandbox trong không gian người dùng, với mục tiêu chi phí đủ thấp để chạy trên từng request
  • Tác vụ mạng và đĩa được gửi qua io_uring thông qua runtime monoio
  • Hỗ trợ TLS 1.3, HTTP/2, Encrypted Client Hello, chọn chứng chỉ theo SNI, và fingerprinting JA4
  • Toàn bộ website và dữ liệu TLS được phục vụ từ một tarball duy nhất, có thể hot reload bằng SIGHUP

Mô hình cấu hình: chương trình chính là cấu hình

  • zeroserve nhắm tới việc trở thành lựa chọn thay thế cho nginx và Caddy, và lựa chọn thiết kế cốt lõi nằm ở cách cấu hình
  • nginx và Caddy cung cấp ngôn ngữ cấu hình khai báo như khối location, quy tắc rewrite, chỉ thị map, try_files, rồi khi chạm giới hạn thì gắn thêm runtime script tùy chọn như Lua hoặc plugin Caddy
  • Trong cấu trúc đó, hành vi bị chia thành một tầng chỉ thị có luồng điều khiển riêng và một tầng script chạy tại các điểm cụ thể trong vòng đời request
  • zeroserve không có tệp cấu hình; một chương trình eBPF duy nhất nhìn thấy mọi request và quyết định routing, header, xác thực, giới hạn tốc độ và proxy

Phục vụ nguyên trạng một tarball duy nhất

  • Toàn bộ website là một tệp tar, và khi tải vào, zeroserve tạo map path -> byte-range rồi đọc theo phạm vi byte ngay trên chính tarball đó để phục vụ tệp
  • Không có tệp nào được giải nén ra đĩa, nên website chỉ tồn tại trong một tệp duy nhất và không có document root nào có thể bị lộ do quy tắc location sai
  • Triển khai là thay thế nguyên tử một tệp duy nhất; để phát hành phiên bản mới, thay tarball rồi gửi SIGHUP
  • Lệnh đóng gói thư mục và chạy có dạng như sau
zeroserve --pack ./public > site.tar  
zeroserve --addr 0.0.0.0:8080 site.tar  
Quảng cáo
  • Lệnh hot reload có dạng như sau
killall -SIGHUP zeroserve  
  • Việc reload sẽ hoán đổi website, script và dữ liệu TLS một cách nguyên tử trong cùng tiến trình, hoạt động mà không làm mất kết nối
  • Mỗi instance là một event loop đơn luồng; đây là giới hạn nếu xét theo một tiến trình, nhưng phù hợp khi đơn vị mở rộng là “nhiều tiến trình hơn”

Script eBPF không gian người dùng

  • Mọi tệp .c đặt dưới .zeroserve/scripts/ sẽ được compile thành object eBPF bằng clangllc tại thời điểm đóng gói, rồi chạy trên mọi request
  • eBPF chạy trong không gian người dùng trong runtime async-ebpf bên trong một tiến trình thường không đặc quyền, không cần kernel BPF subsystem hay CAP_BPF
  • async-ebpf tích hợp uBPF để JIT compile bytecode thành mã máy x86-64 native
  • Pointer cage sẽ mask mọi truy cập bộ nhớ của mã JIT vào một arena dành riêng cho chương trình, nhốt các truy cập sai phạm bên trong bộ nhớ của script
  • Script chạy trực tiếp trên event loop đơn của zeroserve; để script chậm không chặn các kết nối khác, timer có thể ngắt mã native JIT đang chạy giữa chừng và trả quyền điều khiển về event loop
  • Mô hình lập trình là một chuỗi script chạy theo thứ tự sắp xếp tên tệp, và các script chia sẻ một map metadata theo từng request
  • Nếu script gọi zs_respond hoặc zs_reverse_proxy thì chuỗi sẽ kết thúc sớm
  • Các khóa dưới zs.response.header.* sẽ trở thành header của mọi response; các khóa khác được dùng trong một bước template nhỏ để thay thế placeholder như <zs-meta>visitor</zs-meta> trong tệp HTML tại thời điểm xuất
  • Bề mặt helper hỗ trợ đọc method·path·query·header·địa chỉ peer của request, rewrite URI, đặt·xóa header
  • Các helper mã hóa và encoding cung cấp SHA-256, HMAC-SHA256, base64, hex, getrandom
  • Helper JSON hỗ trợ parse body request, tạo·sửa cây tài liệu, và phản hồi bằng zs_json_respond
  • Giới hạn tốc độ hỗ trợ token bucket dựa trên khóa tùy ý như IP của peer hoặc API key, và trạng thái vẫn được giữ sau hot reload
  • Helper AWS SigV4 hỗ trợ header Authorization có chữ ký và presigned URL để giao tiếp với S3 và các dịch vụ AWS khác
  • Đăng nhập OIDC cung cấp luồng relying-party dựa trên Authorization Code + PKCE; toàn bộ session đăng nhập được đặt trong cookie XChaCha20-Poly1305 sealed để máy chủ vẫn stateless, cho phép đặt website tĩnh phía sau “Đăng nhập bằng Google”
  • Endpoint động hoạt động theo cách script tự phản hồi trực tiếp tại một đường dẫn cụ thể; ví dụ trả về header application/json và body {"status":"ok"} cho request /health
  • Mỗi script chạy dưới giới hạn bộ nhớ mặc định 256KB; runtime sẽ chia thời gian thực thi cho các script chạy lâu và throttle các script mất kiểm soát
  • Các script có thể gọi lẫn nhau bằng zs_call, với độ sâu gọi bị giới hạn
  • Script rơi vào vòng lặp vô hạn chỉ làm chậm request của chính nó; timer tiền nhiệm sẽ ngắt nó để máy chủ tiếp tục xử lý các request khác
  • Tầng TLS chỉ hỗ trợ TLS 1.3 và được terminate bằng BoringSSL
  • Encrypted Client Hello giúp SNI thực không xuất hiện dưới dạng plaintext, đồng thời cung cấp chọn chứng chỉ SNI theo thư mục và fingerprinting client JA4 được lộ cho script
  • Chế độ transparent ECH relay chuyển nguyên trạng từng byte các handshake không thể giải mã tới upstream thực, cho phép tên được bảo vệ trộn phía sau tên công khai

Hiệu năng

  • Điều kiện benchmark

    • So sánh zeroserve, nginx 1.26 và Caddy 2.11 khi phục vụ HTTPS với cùng nội dung và cùng chứng chỉ tự ký trên Ryzen 7 3700X 8 nhân
    • Vì instance zeroserve về thiết kế là đơn luồng, tiêu chí so sánh là hiệu năng trên mỗi lõi
    • Tất cả máy chủ đều bị ghim vào một CPU bằng taskset; nginx dùng worker_processes 1, Caddy dùng GOMAXPROCS=1, còn zeroserve dùng cấu trúc đơn luồng sẵn có
    • Tải được tạo từ lõi khác bằng wrk -t4 -c100, lấy trung vị của 3 lần chạy, mỗi lần 10 giây
    • wrk dùng HTTP/1.1, nên các con số là HTTP/1.1 trên TLS 1.3, tức chi phí trạng thái ổn định của các kết nối HTTPS đã mở sẵn với keep-alive dài để phân bổ chi phí handshake
  • Tệp tĩnh nhỏ 174B

    Máy chủ req/s p99
    zeroserve 36,681 5.4 ms
    nginx 31,226 7.8 ms
    Caddy 12,830 22 ms
    • zeroserve phục vụ tệp nhỏ trên một lõi nhanh hơn nginx khoảng 17%, đồng thời có độ trễ đuôi thấp hơn
    • Các trường hợp cơ bản của website tĩnh như trang HTML, JSON nhỏ, CSS là mục tiêu tối ưu của zeroserve
    Quảng cáo
  • Tệp tĩnh lớn 100KB

    Máy chủ req/s Thông lượng p99
    zeroserve 8,000 782 MB/s 22 ms
    nginx 7,600 773 MB/s 28 ms
    Caddy 6,084 590 MB/s 44 ms
    • Kết quả của ba máy chủ khá sát nhau, với zeroserve nhỉnh hơn một chút ở khoảng 780 MB/s trên một lõi
    • sendfile() vốn là thế mạnh của nginx với tệp lớn không được dùng dưới TLS, vì byte phải được mã hóa trong không gian người dùng, nên cả ba máy chủ đều bị ràng buộc bởi vòng lặp mã hóa và ghi
    • Khi kernel TLS đều bị tắt trên cả ba, đường đọc·ghi io_uring của zeroserve cho kết quả nhanh hơn đôi chút

eBPF vs Lua

  • Đối tượng so sánh cho phần script là nginx + LuaJIT ngx_http_lua_module, cách phổ biến để chạy mã nhanh bên trong máy chủ web
  • Theo mặc định, zeroserve đặt timer tiền nhiệm script mỗi 2ms; khoảng thời gian càng mịn giúp throttle script có vấn đề nhanh hơn nhưng cũng tạo thêm chi phí cho script bình thường
  • Ở mặc định 2ms, với phản hồi động hoàn toàn, eBPF đạt khoảng 32k req/s, thấp hơn 41k req/s của nginx Lua
  • Khi tăng --preempt-timer-interval-ms lên 10, thông lượng xử lý script phục hồi khoảng 40% và kết quả đảo chiều
  • Middleware chèn header theo từng request

    Engine req/s p99
    zeroserve eBPF 10ms 43,709 5.1 ms
    zeroserve eBPF 2ms mặc định 31,334 6.7 ms
    nginx Lua header_filter 28,653 8.4 ms
    • Trong trường hợp middleware nơi script chạy nhưng tệp tĩnh vẫn tiếp tục được phục vụ, eBPF 10ms cao hơn nginx Lua khoảng 50% và cũng có độ trễ đuôi thấp hơn
  • Phản hồi JSON động hoàn toàn

    Engine req/s p99
    zeroserve eBPF 10ms 46,945 4.5 ms
    nginx Lua content_by_lua 41,231 6.4 ms
    zeroserve eBPF 2ms mặc định 32,393 6.7 ms
    • eBPF được tinh chỉnh với khoảng 10ms đạt thông lượng cao hơn content_by_lua của nginx ngay cả với phản hồi tổng hợp hoàn toàn
    • Cả hai engine đều compile thành mã native; LuaJIT là tracing JIT, còn async-ebpf JIT compile eBPF thông qua uBPF
    • Trong điều kiện mà mã hóa TLS là chi phí request chung, đường eBPF đã tinh chỉnh dẫn trước về thông lượng
    • Với mặc định 2ms, eBPF vẫn giữ lợi thế ở middleware nhưng mất vị trí dẫn đầu ở phản hồi tổng hợp, nên khuyến nghị dùng 10ms cho script vận hành
Quảng cáo

Dùng làm reverse proxy

  • zeroserve proxy tới backend bằng cách gọi zs_reverse_proxy("http://127.0.0.1:9000";) trong script
  • Pool kết nối upstream hỗ trợ tối đa 128 kết nối cho mỗi backend và tái sử dụng kết nối rỗi trong 30 giây
  • Để so sánh công bằng, do nginx mặc định đóng kết nối upstream sau mỗi request, nó được cấu hình rõ ràng với keepalive 128, proxy_http_version 1.1, và header Connection để trống
  • Caddy tái sử dụng kết nối theo hành vi mặc định
  • Mỗi proxy terminate TLS trên một lõi rồi chuyển tiếp tới backend plaintext dùng chung; backend chạy trên máy chủ 2 lõi riêng và tự giữ được 100k req/s, nên chỉ đo overhead của proxy
  • Proxy phản hồi nhỏ 174B

    Proxy req/s p50 p99
    zeroserve 26,486 3.3 ms 8 ms
    nginx 21,761 4.2 ms 10.5 ms
    Caddy 7,683 10.3 ms 33 ms
    • Proxy io_uring có pooling của zeroserve vượt nginx khoảng 22% và đạt thông lượng gấp khoảng 3.4 lần so với Caddy
    • Với các workload proxy phổ biến như API call, JSON nhỏ, HTML từ app server, zeroserve thực hiện terminate TLS và chuyển tiếp backend nhanh hơn
  • Proxy phản hồi 100KB

    Proxy req/s Thông lượng
    nginx 5,882 585 MB/s
    Caddy 4,285 406 MB/s
    zeroserve 3,631 359 MB/s
    • Khi body phản hồi proxy lớn hơn, cơ chế buffering của nginx di chuyển byte hiệu quả hơn nên dẫn đầu, Caddy ở giữa, còn zeroserve tụt lại
    • Khi phản hồi proxy lớn, nginx là công cụ tốt hơn; còn với phản hồi nhỏ nhưng số lượng nhiều, zeroserve nhanh hơn

Bộ nhớ

  • Một instance zeroserve đơn ở trạng thái nhàn rỗi dùng khoảng 15MB PSS, cao hơn khoảng 6MB của nginx nhưng thấp hơn khoảng 60MB của Caddy
  • Điều quan trọng là đơn vị thực thi là toàn bộ tiến trình; khi chạy một bản sao cho mỗi lõi, chúng ánh xạ cùng một binary và chia sẻ các trang mã
  • Các tiến trình bổ sung chỉ thêm ít bộ nhớ ngoài working set riêng của chúng

Công bố

  • zeroserve là một dự án mã nguồn mở được công bố trên GitHub

1 bình luận

 
Ý kiến trên Hacker News
  • Khi benchmark máy chủ web của TechEmpower biến mất, có vẻ như các dự án mới kiểu này có ít cơ hội hơn để tự chứng minh mình
    Sửa: có lẽ tôi bị chậm thông tin, và thứ đang nổi lên gần đây hình như là https://www.http-arena.com/leaderboard/. Chúc may mắn

    • Tôi không hiểu “chết” ở đây nghĩa là gì. Nó vẫn còn ở https://www.techempower.com/benchmarks/#section=data-r23, và benchmark gần nhất cũng là tháng 2 năm 2025
      Chỉ là vốn dĩ họ cũng không chạy thường xuyên, nhìn lịch sử các vòng thì chưa đến một lần mỗi năm
    • UI/UX của LLM quá tệ. Chỉ cần bỏ ra một hai ngày cuối tuần cho mấy thứ này cũng có thể cải thiện trải nghiệm người dùng khá nhiều, không hiểu sao họ không làm
  • Tôi thích việc thấy những thử nghiệm như thế này xuất hiện vì LLM đã giúp việc khám phá trở nên tương đối rẻ và nhanh
    Tuy vậy, điều tôi rút ra ở đây là bản thân nginx khá ấn tượng. Điểm khác cũng đáng chú ý là dự án này tự mô tả là một lựa chọn thay thế cho nginx và Caddy, và đặt cược vào cách cấu hình
    nginx và Caddy cung cấp ngôn ngữ cấu hình khai báo, và khi chạm tới giới hạn của chúng thì lại gắn thêm một runtime script như Lua hoặc plugin Caddy ở bên cạnh, nên hành vi bị chia thành hai tầng
    Nhưng tôi nghĩ cách đặt cược đó là sai. Từ rất lâu rồi, mọi người đã thích cấu hình hơn là mã, và trong nhiều trường hợp chỉ cần tính năng tích hợp sẵn là đủ, không cần phải viết mã C

    • Tôi không chắc có thể khẳng định như vậy
      Mọi định dạng tệp cấu hình dường như ban đầu đều khá đơn giản. Ngay cả YAML lúc đầu cũng khá hợp lý, rồi mọi người bắt đầu muốn những thứ phức tạp hơn với anchor và alias
      Ngay cả GitLab cũng có định dạng riêng kiểu như điều kiện và biến, và nó gần như là một mớ hack chỉ hoạt động ở những chỗ cụ thể. Apache cũng đi theo con đường tương tự với định dạng cấu hình dựa trên XML
      Cuối cùng thì xuất hiện vô số ngôn ngữ lập trình tùy biến để quản lý cấu hình. Trong môi trường doanh nghiệp, người ta thậm chí không chỉnh trực tiếp mà viết script cho quy trình Ansible để thao tác từ xa
      Nếu ngay từ đầu máy chủ được nhúng sẵn một trình thông dịch như Lua hay Python để quản lý cấu hình thì có lẽ đã bỏ qua được cả quá trình đó, và sẽ đơn giản hơn việc chỉnh các tệp cấu hình tùy biến bằng chương trình
      Tất nhiên có thể nói những nỗ lực tùy biến đó được tối ưu cho mục đích cụ thể hơn ngôn ngữ phổ thông, nhưng lập luận đó ngay từ đầu chỉ đúng trong phạm vi hẹp của các ví dụ đồ chơi vốn chẳng cần đến cơ chế ấy
      Còn nhớ file INI của Windows không. Đó là thời đẹp đẽ khi mã là mã và dữ liệu là dữ liệu
    • Tôi cá là trong vòng 96 giờ tới sẽ có người dùng LLM để tạo ra một công cụ chuyển đổi và đóng gói file cấu hình nginx hay Caddy thành mã mà zeroserve có thể dùng
      Hoặc đơn giản hơn, đọc toàn bộ manifest Ingress của một cụm Kubernetes rồi dựng lại pack từ đó
      Ý chính là giao diện giữa công cụ và cấu hình cũng chỉ là một API nữa mà thôi, và quản trị viên hệ thống từ lâu đã mô tả trạng thái hệ thống bằng những cấu trúc ở cấp cao hơn, còn những byte cấu thành cấu hình chỉ là đầu ra của quá trình đó
    • Tôi tự hỏi liệu có thể trừu tượng hóa độ phức tạp và dùng macro để đạt được kiểu cấu hình dạng “tệp cấu hình” hay không
    • Cũng đáng để xem liệu sở thích này có thay đổi khi AI ngày càng cho phép lời nói của con người → hiệu ứng trên máy hay không
      Từ góc nhìn của AI thì cách đó có thể dễ xử lý hơn. AI làm được cả hai phía, nên có thể sẽ còn lâu trước khi một sự chuyển dịch như vậy thực sự được xem là ý tưởng rõ ràng tốt hơn
    • Tôi không hiểu vì sao cứ muốn gán công lao cho LLM đến vậy. Chỉ vì bài viết có dùng LLM hỗ trợ không có nghĩa là chính các thử nghiệm cũng do LLM làm thay
  • Tôi thích ý tưởng này
    Chỉ là tôi sẽ yên tâm hơn nếu trong thư mục eBPF có thể đặt tệp .rs thay vì .c. Đằng nào đây cũng đã là một dự án Rust
    Và tôi cũng đã phần nào kỳ vọng vào một máy chủ web tăng tốc bằng kernel. Nếu có thể làm điều đó một cách an toàn bằng eBPF thì sẽ thực sự rất ấn tượng
    Ngoài ra, chỉ một luồng thôi sao? Trên Linux, fork và chia sẻ hàng đợi kết nối đến là chuyện gần như tầm thường, và với Rust cũng chỉ mất vài dòng. Dùng SO_REUSEPORT thì phần còn lại kernel sẽ lo
    Tiện nói luôn, nếu định theo đuổi io_uring thì tôi nghĩ cũng nên theo luôn kTLS. Nếu tránh được xử lý SSL trong không gian người dùng sau bắt tay thì thiết kế sẽ đơn giản hơn rất nhiều

    • Cảm ơn. Tôi dự định sẽ triển khai fork + SO_REUSEPORT
      Từ trước đến giờ tôi vẫn dùng nftables cho kiểu mục đích này nên chưa trực tiếp cần đến
  • Rất ngầu. Tôi tò mò liệu có thể kết hợp thứ này với chương trình XDP hay các loại chương trình BPF khác như chương trình gắn vào socket map, để tích hợp các tính năng HTTP lớp 7 xuống tầng thấp hơn không

  • Ý tưởng thì hay, nhưng tôi không chắc có nên tập trung vào tệp tĩnh hay không. Dạo này hiếm khi người ta dựng hẳn một máy chủ mới chỉ cho mục đích đó

    • Tuần trước tôi vừa chuyển Ghost sang dạng tĩnh và đã làm đúng như vậy, thậm chí còn lờ mờ nghĩ một binary tự chứa duy nhất có thể nhanh hơn
      Vì thế cái này có cảm giác như được làm riêng cho tôi, dù tôi cũng thừa nhận mình không phải người dùng điển hình
    • Còn tùy lĩnh vực. Trong nhiều ngành khoa học, người ta phân phối hiệu quả các bộ dữ liệu lớn dưới định dạng tệp tĩnh. Ví dụ như https://zarr.dev/ hay https://parquet.apache.org/
  • Trông khá ổn và tính năng cũng được. Nhưng có gì đó quá nhân tạo nên không khiến tôi thực sự bị thuyết phục
    Không rõ các chỉ số có giả hay không, các hàm tiện ích có thực sự hoạt động hay không, hay đã có quá trình hardening tử tế chưa
    Việc làm bằng vibe coding và cả README được tự động tạo ra thì tôi còn chấp nhận được. Nhưng đến cả bài blog công bố cũng do AI tạo, và hoàn toàn không có cơ sở nào để đánh giá liệu mức hiểu biết về chất lượng phần mềm của họ có giống tôi hay không
    Đúng là một thế giới kỳ lạ. Nếu vài năm trước bài công bố được đăng mà không nói gì về AI thì có lẽ tôi đã chấp nhận không chút nghi ngờ, còn bây giờ cứ thấy một README bóng bẩy với các tham số dòng lệnh có vẻ hợp lý là tôi lập tức nghi README đang hallucinate, và thực ra có thể chẳng hề có các tùy chọn đó

    • Tôi là tác giả. Một vài phần cốt lõi của dự án này, chẳng hạn async-ebpf, đã được viết từ rất lâu trước khi mấy coding agent kiểu đó xuất hiện
      Khi làm zeroserve thì tôi có dùng AI hỗ trợ khá nhiều, nhưng tôi tự kiểm tra đầu ra của AI và cũng chính tôi chịu trách nhiệm
    • Nhìn benchmark thì, với tệp tĩnh nhỏ 174B, zeroserve đạt 36,681 req/s và p99 5.4ms, nginx là 31,226 req/s và p99 7.8ms, còn Caddy là 12,830 req/s và p99 22ms
      zeroserve phục vụ tệp nhỏ trên một lõi đơn nhanh hơn nginx khoảng 17% và độ trễ đuôi cũng hẹp hơn. Đây là trường hợp zeroserve phát huy tốt với trang HTML, JSON nhỏ và CSS
      Với tệp tĩnh lớn 100KB, zeroserve đạt 8,000 req/s, 782 MB/s, p99 22ms; nginx là 7,600 req/s, 773 MB/s, p99 28ms; còn Caddy là 6,084 req/s, 590 MB/s, p99 44ms
      Dù vậy, tôi vẫn sẽ chọn một dự án lâu đời đã được audit, chứng minh trong thực tế và hardening kỹ lưỡng hơn là một dự án mới như thế này. Mức cải thiện không đủ lớn để đáng chấp nhận rủi ro
    • Đây thực sự là một tình huống đáng buồn. Gần đây có dự án ffmpeg-wasm, tôi thử rồi và nó đúng là chạy được. Nhưng đó là vibe coding bằng AI, mà tôi không chịu nổi AI. Dù có chạy được thì cũng vậy
      Tôi quyết định ở lại với thời đại cũ càng lâu càng tốt. Những người thông minh phát hành phần mềm, và những người thông minh bảo trì nó. Họ không cần AI. Đó là ngách của tôi
      Có thể chúng tôi sẽ biến mất, nhưng tôi vẫn thấy như vậy tốt hơn. Chỉ là điều đó đi kèm giả định rằng những người thông minh đó có viết tài liệu. Cũng có nhiều người giỏi nhưng ghét viết tài liệu
      Từ lâu tôi đã quyết rằng phần mềm không có tài liệu thì dù xuất sắc đến đâu cũng không đáng để tôi bỏ thời gian. Chủ yếu tôi nói về ứng dụng; tôi gần như không đọc tài liệu Linux, dù người khác bảo nó cũng không tệ lắm, nên tôi cũng không rõ
  • Đây là một khái niệm mới thú vị và tôi thích nó
    Câu hỏi thực sự là mức độ cam kết của nhà phát triển và cộng đồng. Những người đứng sau Caddy và Nginx đã hỗ trợ sản phẩm một cách bền bỉ, và dự án này cũng sẽ cần rất nhiều sự tập trung và quan tâm

  • Tại sao lại là tarball?

    • Đây là một định dạng đơn giản giúp truy cập tài nguyên theo byte range dễ dàng, ai cũng có công cụ để làm việc với nó, và quan trọng nhất là nó không nén
    • Theo đoạn đầu của mục “One tarball, served in place”, toàn bộ site là một tệp tar duy nhất, và zeroserve khi nạp sẽ lập chỉ mục nó để tạo bản đồ byte range từ các đường dẫn, rồi thực hiện đọc theo byte range trực tiếp trên chính tarball đó để phục vụ tệp
      Nó không giải nén gì ra đĩa. Vì toàn bộ site nằm trọn trong một tệp đó, nên sẽ không có document root nào để các quy tắc location sai lộ ra, và việc triển khai cũng trở thành một lần thay thế tệp duy nhất theo kiểu atomic
      Tuy vậy, ngay cả lời giải thích đó cũng có thể là kiểu hợp thức hóa của LLM. Rải rác khắp bài có những cách diễn đạt như “the right shape” hay “the surface is broad”