2013-07-11 19 views
26

Sau khi đọc nổi tiếng C10k article và tìm kiếm trên web về cách mọi thứ đã phát triển kể từ khi nó được viết, tôi muốn biết liệu nó có thể đạt được tiêu chuẩn ngày nay không máy chủ để xử lý > 10000 đồng thời kết nối sử dụng một luồng cho mỗi kết nối (có thể với sự trợ giúp của một nhóm luồng để tránh quá trình tạo/giết).TCP/IP - Giải quyết C10K bằng cách tiếp cận từng khách hàng


Một số chi tiết có thể ảnh hưởng cách tiếp cận với các vấn đề:

  1. Input, chế biến trung gian và đầu ra.
  2. Độ dài của mỗi kết nối.
  3. Thông số kỹ thuật của máy chủ (lõi, vi xử lý, RAM, vv ...)
  4. Kết hợp hệ thống này với các kỹ thuật thay thế như AIO, bỏ phiếu, chủ đề màu xanh lá cây, vv ...

Rõ ràng tôi không phải là chuyên gia về vấn đề này, vì vậy bất kỳ nhận xét hoặc lời khuyên nào sẽ được đánh giá cao :)

Trả lời

3

Các cách tiếp cận thông thường cho máy chủ là: (a) luồng cho mỗi kết nối (thường là với một hồ bơi) hoặc (b) đơn luồng với IO không đồng bộ (thường với epoll hoặc kqueue). Suy nghĩ của tôi là một số yếu tố của các phương pháp này có thể, và thường nên, được kết hợp để sử dụng IO không đồng bộ (với epoll hoặc kqueue) và sau đó đưa ra yêu cầu kết nối đến một hồ bơi thread để xử lý. Cách tiếp cận này sẽ kết hợp công việc hiệu quả của IO không đồng bộ với sự song song được cung cấp bởi nhóm luồng.

Tôi đã viết một máy chủ thú vị như vậy (bằng C++) sử dụng epoll trên Linux và kqueue trên FreeBSD và OSX cùng với một nhóm luồng. Tôi chỉ cần chạy nó thông qua các bước của nó cho thử nghiệm nặng, làm một số mã dọn dẹp, và sau đó quăng nó ra trên github (hy vọng sớm).

+2

Có thể là tôi hơi bối rối, nhưng tôi nghĩ rằng 'epoll' không chính xác là không đồng bộ. Sau một số nghiên cứu, tôi đã tìm thấy một số văn bản nói rằng 'AIO' sẽ hoạt động tốt hơn khi kết hợp với một nhóm luồng và 'epoll' với một chuỗi duy nhất: [So sánh aio và epoll] (http://lkml.indiana.edu/hypermail /linux/kernel/0305.2/0697.html). – Str1101

+1

... Tôi cũng đã đọc rằng có một số khó khăn liên quan đến việc thực hiện 'AIO', vì vậy có lẽ nó vẫn còn nhiều lợi nhuận hơn để sử dụng cách tiếp cận hồ bơi 'epoll' + thread. [whats-the-different-between ...] (http://stackoverflow.com/questions/5844955/whats-the-difference-between-event-driven-and-asynchronous-between-epoll-and-a). Ý tưởng riêng của tôi về nó là có thể sử dụng trực tiếp một luồng của hồ bơi để tắt mọi kết nối cho đến khi số lượng kết nối đồng thời đến gần số chuỗi tối đa mà hệ thống có thể duy trì và sau đó chúng tôi có thể sử dụng ... – Str1101

+1

epoll/kqueue/AIO hệ thống để xử lý các kết nối mới đến trong khi tất cả các chủ đề đang bận. (p.s .: Tôi thực sự rất thích xem máy chủ của bạn sớm, đặc biệt nếu nó được viết bằng C++ :) – Str1101

51

Tuyệt đối. Máy chủ chuẩn có thể xử lý nhiều hơn 10K kết nối đồng thời sử dụng mô hình với một sợi cho mỗi kết nối. Tôi đã xây dựng một ứng dụng như vậy, và năm năm trước, nó đã chạy với hơn 50K kết nối đồng thời trên mỗi tiến trình trên một máy chủ Linux chuẩn. Ngày nay, có thể chạy cùng một ứng dụng với hơn 250K kết nối đồng thời trên phần cứng hiện tại.

Chỉ có một vài điều cần lưu ý:

  • đề tái sử dụng bằng cách sử dụng một hồ bơi thread. Không cần phải giết các chủ đề nếu chúng không được sử dụng, vì việc sử dụng tài nguyên nên được tối ưu hóa cho các tải cao điểm.
  • Kích thước ngăn xếp: Theo mặc định, mỗi luồng Linux dự trữ 8 MB cho ngăn xếp của nó. Điều đó lên đến 80 GB cho các chủ đề 10K. Bạn nên đặt kích thước ngăn xếp mặc định thành một số giá trị từ 64k đến 512k, đây không phải là vấn đề, bởi vì hầu hết các ứng dụng không yêu cầu ngăn xếp cuộc gọi sâu hơn.
  • Nếu các kết nối ngắn ngủi, hãy tối ưu hóa cho các kết nối mới bằng cách tạo một số ổ cắm trên cùng điểm cuối với tùy chọn SO_REUSEPORT.
  • Tăng giới hạn người dùng: open files (mặc định 1.024), max user processes
  • Tăng giới hạn hệ thống, ví dụ: /proc/sys/kernel/pid_max (mặc định 32K), /proc/sys/kernel/threads-max/proc/sys/vm/max_map_count (mặc định là 65K).

Ứng dụng được đề cập ở trên ban đầu được thiết kế để chỉ xử lý các kết nối đồng thời 2K. Tuy nhiên, với sự tăng trưởng sử dụng, chúng tôi không phải thực hiện những thay đổi đáng kể cho mã để mở rộng lên tới 50K kết nối.

+2

Điều này cũng có thể hữu ích: https://gcc.gnu.org/wiki/SplitStacks – chbaker0

+0

Điều này chủ yếu là sử dụng hệ thống lập lịch trình chuỗi làm hệ thống lập lịch biểu gói: trình lập lịch trình chuỗi xác định 'read()' nào sẽ gọi tiếp theo tùy thuộc vào dữ liệu đến. Nó hoạt động, rõ ràng, nhưng có nhiều thiết kế có thể mở rộng hơn. –

Các vấn đề liên quan