WebSockets và Long Polling – phương thức nào ưu việt hơn?

Diễn đàn - Ngày đăng : 16:21, 20/06/2019

Đôi khi, chúng ta cần thông tin từ các máy chủ của mình ngay khi nó có sẵn. Tất cả các yêu cầu/phản hồi AJAX thông thường mà con người đã sử dụng để không giữ kết nối mở cho loại trường hợp sử dụng này. Thay vào đó, chúng ta cần một phương thức như WebSockets, Long Polling, Server-sent events (SSE - các sự kiện do máy chủ gửi), hoặc HTTP2 push được tạo ra gần đây. Trong bài viết này, các chuyên gia sẽ so sánh hai phương pháp: WebSockets và Long Polling.

Tổng quan về Long Polling

Năm 1995, Netscape Communications đã thuê Brendan Eich để thực hiện các khả năng viết kịch bản trong Netscape Navigator, và trong khoảng thời gian mười ngày, ngôn ngữ JavaScript đã ra đời. Khả năng ngôn ngữ của nó ban đầu rất hạn chế so với JavaScript hiện đại, và khả năng tương tác với mô hình đối tượng tài liệu trên trình duyệt (DOM - document object model) thậm chí còn hạn chế hơn. JavaScript chủ yếu hữu ích trong việc cung cấp các cải tiến hạn chế để làm phong phú khả năng tiêu thụ tài liệu. Ví dụ: xác thực mẫu trong trình duyệt và chèn HTML động vào tài liệu hiện có.

Khi cuộc chiến giữa các trình duyệt ngày càng sôi động, và Internet Explorer của Microsoft đạt đến phiên bản 4 và hơn thế nữa, cuộc cạnh tranh cho bộ tính năng mạnh mẽ nhất đã dẫn đến việc Microsoft giới thiệu XMLHttpRequest. Tất cả các trình duyệt đã hỗ trợ tính năng trong hơn một thập kỷ.

Long Polling về cơ bản là một hình thức hiệu quả hơn của kỹ thuật Polling ban đầu. Việc thực hiện các yêu cầu lặp lại cho máy chủ làm lãng phí tài nguyên, vì mỗi kết nối mới phải được thiết lập, các tiêu đề HTTP phải được phân tích cú pháp, phải thực hiện truy vấn cho dữ liệu mới và phải tạo phản hồi (thường không có dữ liệu mới để cung cấp) để đưa lại kết quả. Kết nối phải được đóng lại và mọi tài nguyên cần được dọn sạch. Thay vì phải lặp lại quy trình này nhiều lần cho mỗi khách hàng cho đến khi có dữ liệu mới cho một khách hàng cụ thể, Long Polling là một kỹ thuật trong đó máy chủ chọn giữ kết nối của khách hàng mở càng lâu càng tốt, chỉ cung cấp phản hồi sau khi dữ liệu trở thành có sẵn hoặc sau khi vượt qua một ngưỡng thời gian chờ.

Tổng quan về WebSockets

Khoảng giữa năm 2008, những khó khăn và hạn chế của việc sử dụng Comet khi thực hiện bất cứ điều gì mạnh mẽ đã được các nhà phát triển Michael Carter và Ian Hickson cảm nhận đặc biệt sâu sắc. Thông qua sự hợp tác trên các danh sách gửi thư của IRC và W3C, họ đã ấp ủ kế hoạch giới thiệu một tiêu chuẩn mới cho giao tiếp hai chiều, thời gian thực hiện đại trên web và do đó, cái tên “WebSocket” đã được đặt ra.

WebSockets

Ý tưởng đã đi vào tiêu chuẩn dự thảo HTML của W3C và ngay sau đó, Michael Carter đã viết một bài viết giới thiệu cộng đồng Comet cho WebSockets. Vào năm 2010, Google Chrome 4 là trình duyệt đầu tiên cung cấp hỗ trợ đầy đủ cho WebSockets, và các nhà cung cấp trình duyệt khác đã tiếp bước trong vài năm sau đó. Năm 2011, RFC 6455 - Giao thức WebSocket - đã được xuất bản lên trang web của IETF (Lực lượng Chuyên trách về Kỹ thuật Liên mạng).

Tóm lại, WebSockets là một lớp vận chuyển mỏng được xây dựng trên đỉnh của ngăn xếp TCP/IP của thiết bị. Mục đích là để cung cấp lớp giao tiếp TCP cho các nhà phát triển ứng dụng web, trong khi thêm một vài khái niệm trừu tượng để loại bỏ rào cản tồn tại liên quan đến cách thức hoạt động của web. Chúng cũng phục vụ cho thực tế rằng các web có các cân nhắc bảo mật bổ sung phải được tính đến, để bảo vệ cả người tiêu dùng và nhà cung cấp dịch vụ.

Ưu và nhược điểm củaLong Polling

Ưu điểm

Long Polling được triển khai ở mặt sau của XMLHttpRequest, được các thiết bị hỗ trợ gần như toàn cầu, do đó, thường không cần phải hỗ trợ các lớp dự phòng tiếp theo. Tuy nhiên, trong trường hợp phải xử lý các trường hợp ngoại lệ, hoặc khi máy chủ có thể truy vấn dữ liệu mới nhưng không hỗ trợ long pulling, pulling cơ bản đôi khi vẫn có thể được sử dụng hạn chế, và có thể được triển khai bằng XMLHttpRequest hoặc thông qua JSONP thông qua các thẻ script HTML đơn giản.

Nhược điểm

  • Long Polling chuyên sâu hơn rất nhiều trên máy chủ.
  • Đặt hàng thông qua tin nhắn đáng tin cậy có thể là một vấn đề với việc Long Polling, vì có thể nhiều yêu cầu HTTP từ cùng một khách hàng sẽ được thực hiện cùng một lúc. Ví dụ: nếu một máy khách có hai tab trình duyệt mở, sử dụng cùng một tài nguyên máy chủ và ứng dụng phía máy khách đang lưu dữ liệu vào một cửa hàng địa phương như localStorage hoặc IndexedDb, thì không có gì đảm bảo rằng dữ liệu trùng lặp sẽ không bị viết nhiều hơn một lần.
  • Phụ thuộc vào việc triển khai của máy chủ. Xác nhận nhận tin nhắn của một cá thể khách hàng cũng có thể khiến một cá thể khách khác không bao giờ nhận được tin nhắn mong đợi, vì máy chủ có thể nghĩ rằng khách hàng đã nhận được dữ liệu mà họ mong đợi.

Ưu và nhược điểm củaWebSockets

Ưu điểm

  • WebSockets giữ một kết nối duy nhất mở trong khi loại bỏ các vấn đề về độ trễ phát sinh với Long Polling.
  • WebSockets thường không sử dụng XMLHttpRequest, và do đó, các tiêu đề không được gửi mỗi lần người dùng cần để có thêm thông tin từ máy chủ. Điều này đã làm giảm tải dữ liệu đắt tiền được gửi đến máy chủ.

Nhược điểm

  • WebSockets không tự động khôi phục khi kết nối bị chấm dứt - đây là điều bạn cần tự thực hiện và là một phần lý do tại sao có nhiều thư viện phía máy khách tồn tại.
  • Các trình duyệt cũ hơn 2011 không thể hỗ trợ các kết nối WebSocket - nhưng điều này ngày càng trở nên không còn quan trọng.

Tại sao giao thức WebSocket là lựa chọn tốt hơn

Nhìn chung, WebSockets sẽ là lựa chọn tốt hơn.

Long Polling đòi hỏi nhiều tài nguyên hơn trên các máy chủ trong khi WebSockets có dấu chân cực kỳ nhẹ trên máy chủ. Long Polling cũng đòi hỏi nhiều bước nhảy giữa máy chủ và thiết bị. Và các cổng này thường có các ý tưởng khác nhau về thời gian kết nối điển hình được phép duy trì mở. Nếu nó mở quá lâu, một điều gì đó có thể giết chết nó, có thể ngay cả khi nó đang thực hiện một việc quan trọng.

Tại sao bạn nên xây dựng với WebSockets

  • Tin nhắn không đồng bộ song công hoàn toàn. Nói cách khác, cả máy khách và máy chủ đều có thể truyền tin nhắn cho nhau một cách độc lập.
  • WebSockets đi qua hầu hết các tường lửa mà không cần cấu hình lại.
  • Mô hình bảo mật tốt (mô hình bảo mật dựa trên nguồn gốc).

Giải pháp mã nguồn mở WebSockets

Có hai lớp thư viện WebSocket chính: những lớp triển khai giao thức và giao phần còn lại cho nhà phát triển, và những lớp xây dựng trên giao thức với các tính năng bổ sung khác thường yêu cầu các ứng dụng nhắn tin thời gian thực, như khôi phục các kết nối bị mất, phụ đề và kênh, xác thực, ủy quyền, v.v…

Sự đa dạng thứ hai thường yêu cầu các thư viện riêng của họ được sử dụng ở phía máy khách, thay vì chỉ sử dụng API (Giao diện lập trình ứng dụng) WebSocket thô do trình duyệt cung cấp. Do đó, điều quan trọng là đảm bảo rằng bạn sẽ hài lòng với cách họ làm việc và những gì họ cung cấp. Bạn có thể thấy mình bị ràng buộc trong giải pháp đã chọn khi nó được tích hợp vào kiến ​​trúc của bạn, và mọi vấn đề về độ tin cậy, hiệu suất và khả năng mở rộng có thể quay lại cản trở bạn.

Hãy bắt đầu với một danh sách những người đối tượng rơi vào trường hợp đầu tiên trong hai loại.

Lưu ý: Tất cả những điều sau đây là các thư viện nguồn mở.

ws

ws là một ứng dụng đơn giản dễ sử dụng, nhanh chóng và được thử nghiệm kỹ lưỡng trên máy khách và máy chủ WebSocket cho Node.js.

Máy khách (Trình duyệt, trước khi đóng gói):

1 const WebSocket = require('ws');

2 const ws = new WebSocket('ws://www.host.com/path');

3 ws.on('open', function open() {

4    ws.send('something');

5 });

6

7 ws.on('message', function incoming(data) {

8    console.log(data);

9 });

Máy chủ (Node.js):

1 const WebSocket = require('ws');

2 const wss = new WebSocket.Server({ port: 8080 });

3 wss.on('connection', function connection(ws) {

4    ws.on('message', function incoming(message) {

5    console.log('received: %s', message);

6    });

7    ws.send('something');

8 });

μWebSockets

μWebSockets là sự thay thế cho ws, được thực hiện với trọng tâm đặc biệt là hiệu suất và tính ổn định. Theo hiểu biết tốt nhất của chuyên gia, μWS triển khai máy chủ WebSocket có sẵn nhanh nhất trong vòng một dặm.

Gần đây đã có một cuộc tranh cãi xung quanh μWS do tác giả đã cố gắng kéo nó từ npm vì lý do triết học, nhưng phiên bản làm việc mới nhất vẫn còn trên npm và có thể được cài đặt chỉ định rõ ràng phiên bản đó khi cài đặt từ npm. Điều đó nói rằng, tác giả đang làm việc trên một phiên bản mới, với các ràng buộc Node.js đi kèm cũng đang được phát triển.


1 var WebSocketServer = require('uws').Server;

2 var wss = new WebSocketServer({ port: 3000 });

3 function onMessage(message) {

4    console.log('received: ' message);

5 }

6 wss.on('connection', function(ws) {

7    ws.on('message', onMessage);

8    ws.send('something');

9 });

Phía khách hàng: Sử dụng WebSockets trong Trình duyệt

API WebSocket được định nghĩa trong Tiêu chuẩn sống WHATWG HTML và thực sự khá đơn giản để sử dụng. Xây dựng một WebSocket chỉ mất một dòng mã:

JS

1 const ws = new WebSocket('ws://example.org');

Lưu ý việc sử dụng ws nơi bạn thường có sơ đồ HTTP. Ngoài ra còn có tùy chọn sử dụng wss khi bạn thường sử dụng HTTPS. Các giao thức này được giới thiệu song song với đặc tả WebSocket và được thiết kế để thể hiện kết nối HTTP, bao gồm yêu cầu nâng cấp kết nối để sử dụng WebSockets.

Việc tạo đối tượng WebSocket không mất quá nhiều công sức. Kết nối được thiết lập không đồng bộ, do đó, bạn phải lưu ý trước khi gửi bất kỳ tin nhắn nào, và cũng bao gồm một người lắng nghe các tin nhắn nhận được từ máy chủ:


1 ws.addEventListener('open', () => {

2    // Send a message to the WebSocket server

3    ws.send('Hello!');

4 });

5

6.ws.addEventListener('message', event => {

7 // The `event` object is a typical DOM event object, and the message data sent

8 // by the server is stored in the `data` property

9    console.log('Received:', event.data);

10 });

Ngoài ra còn có lỗi và các sự kiện gần đây. WebSockets không tự động khôi phục khi các kết nối bị chấm dứt - đây là điều bạn cần tự thực hiện và là một phần lý do tại sao có nhiều thư viện phía máy khách tồn tại. Mặc dù lớp WebSocket đơn giản và dễ sử dụng, nó thực sự chỉ là một khối xây dựng cơ bản. Hỗ trợ cho các giao thức con khác nhau hoặc các tính năng bổ sung như các kênh nhắn tin phải được triển khai riêng.

Long polling: Giải pháp nguồn mở

Hầu hết các thư viện không thực hiện Long polling cách ly với các phương tiện vận chuyển khác. Bởi vì nhìn chung, Long polling thường đi kèm với các chiến lược vận chuyển khác, như là một phương thức dự phòng. Trong năm 2018 và hơn thế nữa, các thư viện Long polling độc lập đặc biệt không phổ biến, vì nó là một kỹ thuật nhanh chóng mất đi sự liên quan khi đối mặt với sự hỗ trợ rộng rãi cho các lựa chọn thay thế hiện đại hơn. Tuy nhiên, dưới đây là một số tùy chọn cho một vài ngôn ngữ khác nhau mà bạn có thể triển khai cho vận chuyển dự phòng:

Go: golongpoll

PHP: php-long-polling

Node.js: Pollymer

Python: Một máy chủ COMET đơn giản

Có rất nhiều vấn đề liên quan khi triển khai hỗ trợ cho WebSockets với Long Polling như một phương án dự phòng - không chỉ về chi tiết triển khai máy khách và máy chủ, mà còn liên quan đến hỗ trợ cho các phương tiện vận chuyển khác, để đảm bảo hỗ trợ mạnh mẽ cho các môi trường máy khách khác nhau. Cũng như mối quan tâm rộng hơn, chẳng hạn như xác thực và ủy quyền, gửi tin nhắn được đảm bảo, đặt hàng tin nhắn đáng tin cậy, lưu giữ tin nhắn lịch sử, v.v. Tại Ably, SDK thư viện khách sử dụng WebSockets làm kết nối thời gian thực chính, với việc sử dụng Long polling như một phương án dự phòng.

Ngọc Huyền