14 điểm bởi GN⁺ 2025-09-02 | 5 bình luận | Chia sẻ qua WhatsApp
  • Gần đây, cách tiếp cận hybrid tích hợp GoRust như các ngôn ngữ mở rộng bên trong kiến trúc monolithic PHP đang thu hút sự chú ý
  • Trước đây, sự kết hợp giữa microservice Gomonolith PHP 8.3 giúp đạt được sự cân bằng giữa năng suấthiệu năng cao
  • Theo nguyên lý Pareto (80% lưu lượng tập trung vào 20% API), việc tối ưu các endpoint hotspot là điều bắt buộc; trước đây người ta xử lý bằng cache·tách dịch vụ Go, nhưng độ phức tạp lại tăng lên
  • Gần đây, cùng với sự phát triển của hệ sinh thái PHP, các kỹ thuật như FFI, extension Rust, extension Go (FrankenPHP) đã xuất hiện, cho phép tăng mạnh hiệu năng ngay bên trong monolith
  • Extension Rust đồng thời mang lại an toàn bộ nhớ và tốc độ, còn FrankenPHP cho thấy mức cải thiện hiệu năng hơn 4 lần với worker mode và extension dựa trên Go
  • Có thể đảm bảo cả năng suất lẫn tốc độ bằng cách tiếp cận PHP hybrid, đồng thời tránh được chi phí·rủi ro khi viết lại toàn bộ bằng Go/Rust

Bối cảnh và kiến trúc hiện có

  • Trước đây, xoay quanh ứng dụng monolithic DDD (mother), các microservice dựa trên Go (children) được phát triển riêng để tối ưu những chức năng cụ thể
  • Microservice Go đảm nhiệm xử lý lưu lượng hiệu năng cao, còn monolith PHP 8.3 mang lại phát triển tính năng nhanh và độ tin cậy khi triển khai trong bối cảnh đội backend nhỏ
  • Cấu trúc này mang đến một điểm cân bằng giúp đảm bảo cả tốc độ, độ ổn định và năng suất

Điểm nghẽn hiệu năng và cách ứng phó trước đây

  • Thường quan sát thấy nguyên lý Pareto trong đó 80% lưu lượng tập trung vào 20% endpoint API
  • Đối với 20% khu vực quan trọng nhất về hiệu năng này, nhiều cách đã được áp dụng như viết mã tối ưu, thêm lớp cache, tách microservice Go
  • Tuy nhiên vẫn tồn tại giới hạn về độ phức tạp và gánh nặng vận hành

Các lựa chọn hybrid trong hệ sinh thái PHP hiện đại

  • Gần đây ngày càng có nhiều công nghệ cho phép cải thiện hiệu năng trực tiếp bên trong monolith PHP
  • 1. FFI (Foreign Function Interface)

    • Với tính năng FFI của PHP, có thể gọi trực tiếp mã C từ PHP
    • Ngay cả logic ở cấp hệ thống hoặc performance-critical cũng có thể được triển khai trong dự án PHP
    • Tuy vậy, nên chỉ dùng trong trường hợp phù hợp do cần cân nhắc chi phí context switching
  • 2. Extension dựa trên Rust

    • Có thể phát triển extension PHP bằng Rust (hoặc Zig)
    • Bằng cách offload các khu vực chịu tải cao sang extension Rust có an toàn bộ nhớhiệu năng biên dịch, có thể đảm bảo cả độ tin cậy lẫn tốc độ cao
  • 3. Extension dựa trên Go: FrankenPHP

    • Gần đây sau khi chuyển sang FrankenPHP và chạy ở worker mode, đã xác nhận hiệu năng nhanh hơn hơn 4 lần so với trước đây
    • Các bản phát hành gần đây cũng cho phép viết extension PHP bằng Go
    • Nhờ đó có thể tận dụng trực tiếp hiệu năng API của Go ngay trong monolith PHP, kết hợp năng suất và tốc độ mà không cần tách ngôn ngữ

Vì sao không chuyển hoàn toàn sang Go hoặc Rust

  • Chi phí viết lại toàn bộ và rủi ro đều cao
    • Việc thay thế hoàn toàn một ứng dụng đã lớn và ổn định bằng Go hay Rust đòi hỏi nhiều tài nguyên và mang rủi ro lớn
  • Bản thân PHP vẫn có những thế mạnh riêng
    • Trong phần lớn công việc, tốc độ phát triển nhanh, hệ sinh thái thân thiện và hiệu năng đủ nhanh của PHP vẫn rất cạnh tranh
    • Chỉ cần cấu hình hybrid với Go, Rust cho một số khu vực thực sự cần giới hạn hiệu năng cao nhất là có thể loại bỏ sự cần thiết phải chuyển toàn bộ

Kết luận: giá trị của PHP hybrid

  • Hệ sinh thái PHP hiện đại cung cấp cả năng suất phát triển nhanh lẫn các lựa chọn tích hợp extension hiệu năng cao (C, Rust, Go)
  • Với cấu trúc hybrid này, có thể đảm bảo cả tốc độ lẫn năng suất
  • Vẫn duy trì phát triển lấy PHP làm trung tâm, đồng thời mở ra một mô hình kiến trúc mới cho phép mở rộng chọn lọc theo ngôn ngữ khi cần

5 bình luận

 
naearu 2025-09-02

Có cảm giác như JavaScript cũng đang dần thay đổi theo kiểu này.

 
skageektp 2025-09-02

Rust đi với Node.js thì còn được chứ;; cá nhân tôi thấy PHP cứ phải dùng mấy ký hiệu như $ liên tục nên gõ code có vẻ khá bất tiện, nhưng những người dùng thành thạo thì thường không cảm thấy quá bất tiện phải không?

 
proinworks 2025-09-03

Dù thấy bất tiện, nhưng dùng một thời gian thì chẳng phải sẽ nhanh quen thôi sao?
Con người là loài động vật có khả năng thích nghi.

 
nemorize 2025-09-02

Tôi có thể thấy không thoải mái với chính khái niệm biến/hàm của PHP, chứ chưa từng một lần cảm thấy khó chịu với cách biểu diễn bằng $.

Những câu kiểu vì dấu đô la nên khó chịu không dùng được, ~~bọn dùng ký hiệu đô la thì kiếm được nhiều tiền, không phải đô la Mỹ mà là đô la Zimbabwe nên cũng chẳng kiếm được bao nhiêu~~ chẳng phải vốn chỉ là mấy câu nói đùa thôi sao...

 
GN⁺ 2025-09-02
Ý kiến Hacker News
  • Tôi ngày càng có cảm giác không thiện cảm với các framework đa dụng (Spring, Laravel, Phoenix, v.v.); lúc đầu chúng thực sự rất hiệu quả, nhưng trong các dự án legacy thì những vấn đề quen thuộc luôn lặp lại. Mỗi dự án lại có môi trường hạ tầng và điều kiện kinh doanh khác nhau, nên không thể chỉ làm theo đúng cách mà framework khuyến nghị; kết quả là đủ loại bản vá bổ sung và mẹo phụ thuộc bắt đầu mọc ra khắp nơi. Khi muốn nâng cấp lên ngôn ngữ hay phiên bản mới, tất cả những phần tùy biến này đều vỡ tung, nên rốt cuộc chẳng ai cập nhật cho đến khi hạ tầng không còn chạy nổi nữa, rồi mới bước vào cuộc di cư đầy nước mắt. Cách kết hợp nhiều thư viện và tự xây lớp trừu tượng riêng có thể tốn thời gian hơn, nhưng đổi lại có thể nâng cấp linh hoạt từng phần và xoay hướng rất nhanh. Tôi dần thấy hệ sinh thái Go là lý tưởng ở điểm này; ban đầu hơi lạ lẫm, nhưng giờ thì tôi lại thích cách đó hơn.

    • Với web framework, tôi luôn có cảm giác kiểu “lúc đầu thì rất tuyệt, rồi đến một thời điểm nào đó bắt đầu thấy vướng víu”. Khi làm ứng dụng đơn giản, kiểu như Rails với “làm blog trong 15 phút” thật sự giống phép màu, nhưng khi hệ thống phức tạp lên thì chính framework lại trở thành vật cản. Cá nhân tôi thấy các thiết lập HTTP “mức trung gian” như Express + Node.js hay Vert.x + Java dễ chịu hơn.

    • Trong Python có thể chia ra microframework (kiểu Flask) và macroframework (Django). Tôi lúc nào cũng chọn Django; Flask gần như không gợi ý gì cả, nên mỗi dự án lại thành một bông tuyết được trang trí mới hoàn toàn. Bạn sẽ mệt mỏi vì phải quyết định giữa N lựa chọn cho xác thực, template, cookie, email, v.v. Đặc biệt là phần lớn các thư viện kiểu này lại do một người duy trì, nên chất lượng bảo trì/bảo mật rất thất thường. Ngược lại, Django khiến hầu hết dự án trông khá giống nhau và gần như cung cấp ngay mọi tính năng cơ bản. Tôi chỉ có lý do dùng thư viện mở rộng khi có yêu cầu đặc thù; vì nhiều phần đã được quản lý và kiểm chứng trực tiếp, tôi thấy độ tin cậy mã nguồn và bảo mật cũng cao hơn.

    • Lý do Go không có các framework khổng lồ là vì hệ thống kiểu của ngôn ngữ này vẫn còn khá chưa hoàn thiện. Việc tạo ra các thư viện phức tạp nhưng phối hợp tốt với nhau là rất khó. Tôi đã phải đợi đến 9 năm mới có thể dùng generics để làm bộ công cụ cơ sở dữ liệu đầu tiên cho Go. Nó thành công, nhưng vẫn khiến tôi cảm thấy hồi trước làm kiểu này bằng Java còn tốt hơn. Nếu có thể map/filter/reduce một kiểu kết quả sang kiểu generic khác thì sẽ là một thế giới hoàn toàn khác. Chỉ cần có khả năng khai báo union type thì cũng chẳng cần dùng kiểu any nữa. Ngay cả hỗ trợ overloading thôi cũng sẽ làm mã gọn gàng hơn rất nhiều; hệ thống kiểu của Go vẫn cần phát triển thêm.

    • Trong lĩnh vực của tôi thì chỉ Go và Rust là hữu ích. Văn hóa framework quá nhiều tính áp đặt không hợp với tôi. Tôi nghĩ Rails, Laravel, Django rất tuyệt trong những tình huống có thao tác CRUD với CSDL quan hệ rõ ràng.

    • Trong 5 năm gần đây tôi chỉ dùng các component tương thích PSR (Php Standards Recommendation), hoàn toàn không dùng framework. Lý do là các framework lớn về lâu dài cuối cùng đều không còn phù hợp. Chúng có quá nhiều ràng buộc, và việc quản lý cũng như cập nhật trở nên quá khó khăn. Dù là dự án lớn cho công ty hay dịch vụ cá nhân, tôi đều thấy kiến trúc xoay quanh các component PSR tốt hơn.

  • Tôi hiểu rằng khi codebase quá lớn và không thể viết lại toàn bộ, thì cách tiếp cận hybrid (kết hợp PHP với các ngôn ngữ hiệu năng như C, Rust, Go, v.v.) có thể có ý nghĩa. Nhưng nếu không thật sự cần đến mức đó, thì theo kinh nghiệm của tôi, API viết bằng C# vừa đảm bảo tốc độ phát triển vừa đảm bảo hiệu năng chạy. Hầu như tôi chưa bao giờ phải đi xa đến mức C++ hay Rust. PHP cũng tốt, nhưng vẫn chưa làm được những thứ như mảng có kiểu. Ví dụ, đây là ngôn ngữ mà ngay cả chuỗi cũng không bị từ chối khi lọt vào một mảng ngày tháng.

    • Tôi đã dùng C# lâu năm và có kinh nghiệm với nhiều framework web/API. Nếu đào sâu một chút thì PHP rất hay ở chỗ có cực nhiều hàm tích hợp sẵn cho phát triển web. Nó có nhược điểm, nhưng nếu cần làm gì đó thật nhanh thì theo tôi PHP là người thắng cuộc.

    • Đúng là PHP cho phép kiểu sai trong mảng (ví dụ: chuỗi trong mảng ngày tháng). Thỉnh thoảng sẽ bật ra những hành vi kỳ quặc hay bug lạ. Gần đây tôi từng gặp lỗi khi json_decode() giải mã thì key là số sẽ vào dưới dạng int, còn các key khác là string, khiến kiểu của key bị trộn lẫn. Những góc cạnh kiểu này đúng là hơi quái, nhưng dù vậy PHP vẫn là một ngôn ngữ Frankenstein cực kỳ cuốn hút.

    • Thực tế là nếu dùng static analyzer thì những lỗi kiểu đó thường sẽ bị chặn. Khả năng cao PHP cũng sắp có hỗ trợ generics. Có thể xem tin liên quan trên blog của thephp.foundation.

    • Tôi là tác giả bài viết, cảm ơn vì đã đọc. Thực ra không cần viết lại toàn bộ; nếu chạy PHP trên runtime dạng worker như swoole hay frankenphp thì có thể đạt hiệu năng cỡ Node. Các vấn đề về mảng có kiểu hay generics đều được static analyzer như phpstan hỗ trợ; nếu tận dụng type annotation thì độ an toàn kiểu cũng tăng lên rõ rệt.

    • Từ sau khi VB6 bị ngừng hỗ trợ, tôi quyết định không đụng đến ngôn ngữ nào của Microsoft nữa. Chỉ ngôn ngữ mã nguồn mở mới là lựa chọn tốt cho sức khỏe tinh thần.

  • Khi tôi vào làm ở {{company}}, toàn công ty vẫn đang ở môi trường PHP 5.4, và khi đó sự ác cảm với PHP là khắp nơi. Nhưng sau khi trải nghiệm PHP hiện đại, tôi lại có cảm giác rằng đúng vào thời điểm chúng tôi đang ở chặng cuối rời khỏi PHP, cuộc migration này hóa ra lại giống như một bước lùi ở thời điểm hiện tại. Mọi người vẫn đánh giá PHP bằng thời 5.x, nhưng bây giờ nó đã hoàn toàn khác.

    • Tôi nhìn hơi khác; nếu nhìn vào thị trường tuyển dụng thì vẫn còn định kiến với PHP (dù tốt hay xấu), nên có giới hạn trong việc tuyển được kỹ sư giỏi. Ngay cả khi về mặt kỹ thuật PHP không còn tệ như trước, thì xét về branding công ty, việc rời PHP vẫn có ý nghĩa.

    • Tôi không đồng ý với câu “PHP giờ đã awesome”; chắc chắn nó đã tốt hơn, nhưng gọi là awesome thì hơi quá.

    • PHP đang dần tốt lên, tôi nghĩ sắp tới mình nên tìm hiểu sâu hơn.

    • Bọn tôi cũng từng có đúng trăn trở đó 4 năm trước, và cuối cùng đã nâng cấp lên PHP 8 rồi tiếp tục dùng. Với đội của tôi, lựa chọn đó đã phát huy hiệu quả trong vài năm qua.

  • Pasir giống frankenphp nhưng được xây trên Rust; rất hứa hẹn nhưng vẫn còn ở giai đoạn phát triển sớm.

  • Pasir github Pasir dùng bản chuyển đổi Rust của Zend API binding.

  • Zend API Rust binding Cũng có những thử nghiệm thú vị như ngx-php, với cấu trúc nhúng PHP bằng Zend API ngay bên trong binary của nginx.

  • ngx-php github workerman triển khai runtime rất nhanh bằng cách dùng backend hybrid dựa trên asio.

  • workerman github

    • Tôi tò mò không biết Pasir, frankenphp, v.v. có hỗ trợ cả các module PHP hiện có hay không.

    • Cảm ơn vì gợi ý, trông thật sự rất ngầu. Nhưng đúng như bạn nói, tôi cũng đồng ý là nó vẫn còn khá xa mức production-ready. Bọn tôi cuối cùng chọn frankenphp, thứ đang được php foundation hỗ trợ.

  • Độ phức tạp trong việc debug và bảo trì thường bị xem nhẹ; nếu có quyền lựa chọn thì tôi nghĩ nên tránh kiểu kết hợp này.

    • Cảm ơn ý kiến, bọn tôi đã chọn frankenphp; nếu có lý do nào khiến việc debug khó hơn thì mong bạn giải thích cụ thể hơn.
  • Tôi cũng đã thay toàn bộ ứng dụng của mình từ PHP sang Go, và đó là một khoản đầu tư thành công cho công ty. Tôi giảm được 20 nghìn dòng PHP xuống còn 4 nghìn dòng Go, đồng thời tăng hiệu quả lên rất nhiều. Nếu là một công ty PHP thì tôi rất khuyến nghị lên kế hoạch viết lại quy mô lớn, kèm theo bổ sung test (việc này trong Go dễ hơn), thay vì tiếp tục chịu khổ vì phải bảo trì nhiều ngôn ngữ trộn lẫn như Rust/PHP hay Go/PHP.

    • Tôi tò mò không biết khi chuyển từ PHP sang Go mà số dòng code lại giảm được như thế bằng cách nào. Tôi vẫn nghĩ Go là ngôn ngữ khá dài dòng; theo trải nghiệm của tôi thì PHP ở mức trung bình, Haskell là cô đọng nhất, còn Java/Go lại thường dài hơn do xử lý lỗi các thứ.

    • Tôi thấy khó tin chuyện chuyển từ PHP sang Go mà số dòng giảm 5 lần. Tôi luôn thấy PHP có khá nhiều cú pháp rút gọn, còn Go thì không nhiều.

    • Tôi nghĩ điểm quan trọng luôn là hiệu năng và hiệu quả được cải thiện do “bản thân ngôn ngữ” hay do những cải tiến kiến trúc được đưa vào cùng lúc với việc rewrite.

    • Tôi cứ tưởng khi rewrite sang Go thì mẫu if err != nil sẽ làm code phình ra gấp 10 lần. Tôi từng trải qua một lần rewrite sang Python, và Python cũng hóa ra khá dài dòng, còn các pattern như dependency injection thì gây phiền toái trong testing.

    • Tôi không khuyến khích rewrite một cách vô điều kiện (dù bản thân đã hai lần hoàn tất rewrite thành công, nhưng có lẽ vẫn không tự chọn cách đó). Runtime PHP hiện nay thật sự đã nhanh hơn rất nhiều, nên rất đáng thử. Đặc biệt nếu tận dụng đầy đủ những thứ như task cache của swoole thì có lúc còn nhanh ngang Go (khuyên nên xem benchmark).

  • Đôi khi tôi nghĩ chúng ta thực sự phải quay về với những điều cơ bản: pixel, dữ liệu, độ trễ/băng thông. Xét cho cùng, web cũng chỉ là một bài toán tối ưu: vẽ đúng pixel, đủ nhanh để mắt người nhận ra, trong giới hạn tài nguyên mạng. Tôi thấy nên tiếp cận bằng kiểu suy nghĩ như “người dùng sắp nhìn thấy pixel nào?”, “cần dữ liệu gì để vẽ nó?”, “có nên prefetch trước dữ liệu có thể sắp dùng không?”.

    • Tôi đang làm alumina-ui bằng egui cho WASM, không cần đụng đến đống kiến thức web phức tạp như HTML, JavaScript, CSS; chỉ cần một canvas có kích thước phù hợp trong trình duyệt rồi render thẳng bằng WebGL là xong. Tôi có thể dùng ngôn ngữ mình thích để xuất đồ họa tăng tốc GL nhanh chóng, nên cực kỳ tiện. Tôi rất thích WASM/WebGL nhờ kiểu trừu tượng này.

    • Chỉ tập trung vào pixel mà người dùng thấy là quá phiến diện. Trong dự án phần mềm, không chỉ UX tức thời mà cả thời gian phát triển cũng phải được tối ưu. Độ trễ đến lúc màn hình đầu tiên hiện ra và thời gian phát triển thực tế hoàn toàn không tỉ lệ thuận.

  • FrankenPHP trông rất thú vị, nhưng ngoài đời lại hơi kỳ quặc. Chẳng ai dùng PHP mà không có module PHP cả, nhưng danh sách module PHP mà FrankenPHP hỗ trợ lại không rõ ràng, và tôi cũng không chắc có thể tự build rồi thêm module riêng mình muốn hay không. Nó gắn rất chặt với Caddy, mà tôi không quen web server này và thích nginx hơn. Không có hướng dẫn nên tôi cũng không biết có thể dùng nó thay cho php-fpm dưới nginx hay không. Thêm nữa, image Docker của Caddy hay FrankenPHP dường như chỉ nghĩ đến chứng chỉ Let's Encrypt, nên nếu muốn tự cấu hình SSL hoặc chỉ chạy HTTP thì mọi thứ thật sự rất khó hiểu.

    • Vấn đề module PHP thường được xử lý bằng cách tự build trong Dockerfile. Ví dụ muốn thêm module pgsql thì cài dependency bằng apt, cài module bằng docker-php-ext-install, xong thì gỡ dependency/dọn dẹp là được. Cấu hình HTTP thì chỉ cần mở thẳng cổng 80 trong Caddyfile.

    • Static build mặc định đã đi kèm hàng chục module PHP quan trọng. Danh sách module chi tiết và script build có thể xem ở frankenphp build-static.sh.

  • Tôi tò mò không biết ở loại workload nào thì thật sự cần đến các extension ngôn ngữ như C/Rust/Go. Tôi hiểu là có những trường hợp như vậy, nhưng cũng muốn biết rõ hơn tại sao phải đưa thêm độ phức tạp này vào stack và vì sao không thể giải quyết theo cách khác.

  • Điều tôi ghét nhất ở PHP là mỗi request HTTP lại bootstrap toàn bộ ứng dụng một lần, autoload và đánh giá lại cấu hình lại từ đầu. Tất nhiên có cache các kiểu, nhưng so với cách engine luôn chạy sẵn như Go thì vẫn rất khó chấp nhận.

    • Thực tế có khá nhiều thư viện được tài liệu hóa tốt, cho phép chạy server độc lập chỉ bằng PHP và hoàn toàn dùng được trong production. Hiệu năng JIT của PHP cũng khá ấn tượng.
  • reactphp.org

  • php.net ev module

  • pecl-event

  • workerman.net

    • Không nhất thiết cứ phải như vậy (chạy lại từ đầu cho mỗi request). Một số runtime PHP hỗ trợ một lần thực thi script có thể xử lý nhiều HTTP request.
  • tài liệu frankenphp worker

    • Tôi lại cho rằng đây là ưu điểm lớn nhất của PHP. Việc scale out trở nên cực kỳ dễ dàng.

    • Tôi cũng thích cấu trúc này. Nó vốn dĩ giảm trạng thái xuống mức tối thiểu (ít nhất là đến một mức độ nào đó).

    • Bạn nói đúng, cách này thật sự rất tệ. Đặc biệt còn tệ hơn khi PHP được dùng như một ngôn ngữ template riêng. Các template engine tự chế hay runtime chạy liên tục để sửa chuyện này rốt cuộc cũng chỉ là “trang điểm cho con heo”. Ngay từ đầu đáng lẽ nên chọn một ngôn ngữ không mang cái tên Personal HomePage.