2011-01-20 23 views
34

Trình điều khiển Java NIO không chặn vẫn chậm hơn luồng chuẩn không đồng bộ cho mỗi ổ cắm không đồng bộ kết nối không?Chủ đề Java cho mỗi mô hình kết nối vs NIO

Ngoài ra, nếu bạn sử dụng các chuỗi cho mỗi kết nối, bạn chỉ cần tạo chủ đề mới hoặc bạn có sử dụng một hồ bơi chủ đề rất lớn không?

Tôi đang viết một máy chủ MMORPG bằng Java có thể mở rộng 10000 khách hàng một cách dễ dàng với phần cứng đủ mạnh, mặc dù số lượng khách hàng tối đa là 24000 (mà tôi tin là không thể giới hạn chuỗi 15000 trong Java). Từ bài viết ba năm tuổi, tôi nghe nói rằng việc chặn IO với mô hình kết nối cho mỗi mô hình kết nối vẫn nhanh hơn 25% so với NIO (cụ thể là tài liệu này http://www.mailinator.com/tymaPaulMultithreaded.pdf), nhưng vẫn có thể đạt được như vậy vào ngày này? Java đã thay đổi rất nhiều kể từ đó, và tôi đã nghe nói rằng các kết quả có vấn đề khi so sánh các kịch bản thực tế đời sống vì VM được sử dụng không phải là Sun Java. Ngoài ra, bởi vì nó là một máy chủ MMORPG với nhiều người dùng đồng thời tương tác với nhau, việc sử dụng đồng bộ hóa và thực hành an toàn luồng có làm giảm hiệu suất đến điểm mà bộ chọn NIO luồng duy nhất phục vụ 10000 máy khách sẽ nhanh hơn không? (tất cả công việc không cần thiết phải được xử lý trên luồng với bộ chọn, nó có thể được xử lý trên các chuỗi công nhân như cách hoạt động của MINA/Netty).

Cảm ơn!

+7

10k chủ đề không phải là một chiến thắng cho bất kỳ (* hàng hóa *) máy chủ :-) Ngoài ra, 10k khách hàng hoạt động trên một hộp duy nhất là rất ... không. –

+1

@pst: nếu theo hàng hóa bạn có ý nghĩa; không lượng tử, chưa được phát hiện ra loại công nghệ, tôi hoàn toàn đồng ý. Tôi nghĩ rằng ít nhất của vấn đề của Kevin là số lượng chủ đề. Tôi xin lỗi vì không có bất kỳ thông tin hữu ích nào về vấn đề này. Cũng nhớ QOTD: Kiểm tra. –

+0

@pst Oh JRE ngọt ngào đàn hồi của nó! Bạn chỉ cần làm cho ngày của tôi đáng giá. –

Trả lời

19

Lợi ích NIO nên được thực hiện với một hạt muối.

Trong máy chủ HTTP, hầu hết các kết nối là các kết nối liên tục, chúng hầu như không hoạt động. Nó sẽ là một sự lãng phí tài nguyên để phân bổ trước một luồng cho mỗi luồng.

Đối với những điều MMORPG thì rất khác nhau. Tôi đoán các kết nối liên tục bận nhận hướng dẫn từ người dùng và gửi trạng thái hệ thống mới nhất cho người dùng. Một chủ đề là cần thiết hầu hết thời gian cho một kết nối.

Nếu bạn sử dụng NIO, bạn sẽ phải liên tục phân bổ lại chuỗi cho kết nối. Nó có thể là một giải pháp kém hơn, với giải pháp cố định-mỗi-kết nối đơn giản.

Kích thước ngăn xếp luồng mặc định là khá lớn, (1/4 MB?) Đó là lý do chính tại sao chỉ có thể có chuỗi giới hạn. Hãy thử giảm nó và xem liệu hệ thống của bạn có thể hỗ trợ nhiều hơn không.

Tuy nhiên nếu trò chơi của bạn thực sự rất "bận", đó là CPU của bạn mà bạn cần phải lo lắng nhiều nhất. NIO hay không, nó thực sự khó khăn để xử lý hàng ngàn game thủ hoạt động siêu trên một máy tính.

+1

'Đối với những điều MMORPG thì rất khác nhau. Tôi đoán các kết nối liên tục bận nhận hướng dẫn từ người dùng và gửi trạng thái hệ thống mới nhất cho người dùng.' Tôi cho rằng người dùng sẽ đi ngủ, đôi khi, ít nhất là hầu hết trong số họ. Vì vậy, tôi mong đợi hàng ngàn kết nối bận rộn và thậm chí nhiều người nhàn rỗi hơn. Tôi tự hỏi làm thế nào để tách chúng, có thể sử dụng các chủ đề và để cho chúng chết trên Socket timeout? – maaartinus

+0

Tôi đã làm một khách hàng chủ đề duy nhất, máy chủ thread đơn trong io cũ và một trong nio ở đây (nio đánh bại các io cũ hoặc gắn nó ... khó nói ... cổ và cổ.) Https://github.com/deanhiller/webpieces/cây/master/core/core-asyncserver/src/kiểm tra/java/org/webpieces/nio/api/thông lượng Nio có vẻ như một lựa chọn tốt hơn để sau đó có một Threadpool có kích thước để 10k tỷ lệ ổ cắm. –

9

Nếu bạn muốn chi tiêu bất kỳ số tiền nào trên phần cứng đủ mạnh tại sao lại giới hạn bản thân bạn cho một máy chủ. google không sử dụng một máy chủ, họ thậm chí không sử dụng một trung tâm dữ liệu của máy chủ.

Một quan niệm sai lầm phổ biến là NIO cho phép IO không chặn cho mô hình duy nhất có giá trị điểm chuẩn. Nếu bạn điểm chuẩn chặn NIO bạn có thể nhận được nó nhanh hơn 30% so với IO cũ. tức là nếu bạn sử dụng cùng một mô hình luồng và chỉ so sánh các mô hình IO.

Đối với một trò chơi tinh vi, bạn có nhiều khả năng hết CPU trước khi bạn đạt kết nối 10K. Một lần nữa nó là đơn giản hơn để có một giải pháp mà quy mô theo chiều ngang. Sau đó, bạn không cần phải lo lắng về việc có bao nhiêu kết nối bạn có thể nhận được.

Có bao nhiêu người dùng có thể tương tác hợp lý? 24? trong trường hợp này bạn có 1000 nhóm độc lập tương tác. Bạn sẽ không có nhiều lõi này trong một máy chủ.

Bạn muốn chi tiêu bao nhiêu tiền cho mỗi người dùng trên (các) máy chủ? Bạn có thể mua một máy chủ 12 lõi với 64 GB bộ nhớ với giá dưới 5000 bảng. Nếu bạn đặt 2500 người dùng trên máy chủ này, bạn đã chi tiêu 2 đô la cho mỗi người dùng.

EDIT: Tôi có một tham chiếu http://vanillajava.blogspot.com/2010/07/java-nio-is-faster-than-java-io-for.html là của tôi. ;) Tôi đã được xem xét bởi một người là một GURU của Java Mạng và nó rộng rãi đồng ý với những gì ông đã tìm thấy.

+0

Chà, tôi không biết rằng NIO cũng hỗ trợ chặn IO! Dường như nó không thu hút nhiều sự chú ý đến chính nó và kết quả là, rất khó để tìm điểm chuẩn so sánh việc chặn IO cũ và ngăn chặn NIO, đó là một sự xấu hổ. Tôi sẽ xem xét điều này mặc dù. –

+1

Tôi nghi ngờ số hiệu suất của bạn, bạn có tham chiếu không? Đã có báo cáo rằng NIO không chặn chậm hơn 30% so với IO truyền thống. Tuy nhiên, thử nghiệm không thực tế bởi vì nó không làm bất cứ điều gì với dữ liệu. Ngay sau khi mỗi byte trong luồng ít nhất được đọc một lần, chi phí của NIO/IO trở nên không đáng kể. – irreputable

+0

Khi bạn làm điều gì đó thực tế với dữ liệu mạng và việc xử lý trở nên quan trọng hơn và lợi thế của NIO hoặc IO phần lớn bị mất. Tôi sử dụng NIO vì nó xuất hiện với cùng tôi khoảng 6 độ trễ của chúng tôi cho lần đọc. Điều đó không đặc biệt quan trọng đối với hầu hết các nhà phát triển. –

12

Thực tế, có 3 giải pháp:

  1. Nhiều chủ đề
  2. Một chủ đề và nio
  3. Cả hai giải pháp 1 và 2 đồng thời gian

Điều tốt nhất để làm cho hiệu suất là để có một số lượng nhỏ, giới hạn các chủ đề và các sự kiện mạng multiplex vào các chủ đề này với NIO khi các tin nhắn mới đến qua mạng.


Sử dụng nio với một thread là một ý tưởng tồi cho một vài lý do:

  • Nếu bạn có nhiều CPU hoặc lõi, bạn sẽ được chạy không tải nguồn lực vì bạn chỉ có thể sử dụng một lõi tại một thời điểm nếu bạn chỉ có một chủ đề.
  • Nếu bạn phải chặn vì một số lý do (có thể truy cập đĩa), CPU của bạn không hoạt động khi bạn có thể xử lý kết nối khác trong khi chờ đĩa.

Một chuỗi cho mỗi kết nối là một ý tưởng tồi bởi vì nó không mở rộng quy mô. Hãy nói rằng có:

  • 10 000 kết nối
  • 2 CPU với 2 lõi mỗi
  • chỉ 100 chủ đề sẽ được ngăn chặn bất cứ lúc nào

Sau đó, bạn có thể làm việc ra rằng bạn chỉ cần 104 chủ đề. Bất kỳ chi tiết nào và bạn đang lãng phí tài nguyên quản lý các chuỗi phụ mà bạn không cần. Có rất nhiều sổ sách kế toán dưới mui xe cần thiết để quản lý 10 000 chủ đề. Điều này sẽ làm chậm bạn xuống.


Đây là lý do tại sao bạn kết hợp hai giải pháp. Ngoài ra, hãy đảm bảo máy ảo của bạn đang sử dụng các cuộc gọi hệ thống nhanh nhất. Mỗi hệ điều hành đều có các cuộc gọi hệ thống độc đáo riêng cho mạng IO hiệu suất cao. Đảm bảo máy ảo của bạn đang sử dụng mới nhất và tuyệt vời nhất. Tôi tin rằng đây là epoll() trong Linux.

Bên cạnh đó, nếu bạn đã sử dụng chủ đề cho mỗi kết nối, bạn sẽ chỉ tạo chủ đề mới hoặc bạn sẽ sử dụng một hồ bơi thread rất lớn?

Tùy thuộc vào thời gian bạn muốn tối ưu hóa. Giải pháp nhanh nhất là tạo tài nguyên như chuỗi và chuỗi khi cần. Sau đó, để cho bộ sưu tập rác yêu cầu họ khi bạn đang thực hiện với họ. Bạn có thể tăng hiệu suất bằng cách có một nhóm tài nguyên.Thay vì tạo một đối tượng mới, bạn yêu cầu hồ bơi cho một đối tượng và trả lại cho hồ bơi khi bạn hoàn tất. Điều này cho biết thêm sự phức tạp của kiểm soát đồng thời. Điều này có thể được tối ưu hóa thêm với các thuật toán đồng thời trước như non-blocking algorithms. Các phiên bản Java API mới có một vài phiên bản này cho bạn. Bạn có thể dành phần còn lại của cuộc sống của bạn làm những tối ưu hóa trên chỉ một chương trình. Giải pháp tốt nhất cho ứng dụng cụ thể của bạn có lẽ là một câu hỏi xứng đáng với bài đăng của riêng mình.

+0

Bạn đã quyết định 104 chủ đề như thế nào? Tôi thấy 10000/100 + 4. Nhưng tại sao không chỉ có 100 chủ đề, 4 khác là gì? 4 chủ đề đọc và 100 công nhân? Sẽ có nhiều chủ đề gọi selector.select()? Tôi hiện đang khám phá ý tưởng có nhiều luồng với các bộ chọn riêng lẻ. Tôi đã thực hiện nó trong C, nhưng cú pháp NIO là một chút khác nhau với tôi. đăng ký phím để chọn trong một vòng robin thời trang là những gì tôi đang suy nghĩ. Mỗi chuỗi cuộc gọi chọn và sau đó sinh ra một chuỗi để làm việc, hoặc sử dụng một số chủ đề phân vùng hộp đen ma thuật. – JustinDanielson

+0

@JustinDanielson, Nếu có 100 chủ đề bị chặn, bạn có thể có thêm 4 luồng trên CPU vì có 4 lõi. Bất kỳ ít hơn và sẽ có lõi nhàn rỗi khi có việc phải làm. – Jay

1

Như hầu hết các bạn đang nói rằng các máy chủ đang bị ràng buộc để được nhốt trong sử dụng CPU trước 10k người dùng đồng thời đạt được, tôi cho rằng nó là tốt hơn cho tôi sử dụng một chặn ren (N) phương pháp tiếp cận IO xem xét thực tế là cho MMORPG đặc biệt này, nhận được một vài gói mỗi giây cho mỗi người chơi không phải là hiếm và có thể bog xuống một bộ chọn nếu một trong những được sử dụng.

Peter nêu ra một điểm thú vị ngăn chặn NIO nhanh hơn các thư viện cũ trong khi không thể chối cãi được đề cập cho một máy chủ MMORPG bận rộn, sẽ tốt hơn nếu sử dụng các chuỗi. Tôi sẽ không tính đến quá nhiều người chơi không sử dụng trong trò chơi này, vì vậy nó không phải là một vấn đề đối với tôi để có một loạt các chủ đề không chạy. Tôi đã nhận ra rằng việc đồng bộ hóa vẫn được yêu cầu ngay cả khi sử dụng một khung công tác dựa trên NIO vì chúng sử dụng một số luồng công nhân chạy cùng một lúc để xử lý các gói nhận được từ các máy khách. Chuyển ngữ cảnh có thể tỏ ra đắt tiền, nhưng tôi sẽ thử giải pháp này. Nó tương đối dễ dàng để tái cấu trúc mã của tôi để tôi có thể sử dụng một khung NIO nếu tôi thấy có một nút cổ chai.

Tôi tin rằng câu hỏi của tôi đã được trả lời. Tôi sẽ chờ thêm một chút nữa để có được cái nhìn sâu sắc hơn nữa từ nhiều người hơn. Cảm ơn tất cả các câu trả lời của bạn!

EDIT: Cuối cùng tôi đã chọn khóa học hành động của mình. Tôi thực sự đã không quyết định và quyết định sử dụng JBoss Netty và cho phép người dùng chuyển đổi giữa một trong hai oio hoặc nio bằng cách sử dụng các lớp

org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; 
org.jboss.netty.channel.socket.oio.OioServerSocketChannelFactory; 

Khá tốt mà Netty hỗ trợ cả hai!

3

Nếu bạn có kết nối bận, có nghĩa là họ liên tục gửi cho bạn dữ liệu và bạn gửi lại, bạn có thể sử dụng non-Blocking IO kết hợp với Akka.

Akka là một bộ công cụ mã nguồn mở và thời gian chạy đơn giản hóa việc xây dựng các ứng dụng đồng thời và phân phối trên JVM. Akka hỗ trợ nhiều mô hình lập trình để đồng thời, nhưng nó nhấn mạnh đến sự đồng thời dựa trên diễn viên, với cảm hứng được rút ra từ Erlang. Các ràng buộc ngôn ngữ tồn tại cho cả Java và Scala.

Logic của Akka không bị chặn nên hoàn hảo cho lập trình không đồng bộ. Sử dụng Akka Actors bạn có thể xóa Thread overhead.

Nhưng nếu dòng ổ cắm của bạn chặn thường xuyên hơn, tôi đề nghị sử dụng Blocking IO kết hợp với Quasar

Quasar là một thư viện mã nguồn mở cho đơn giản, đồng thời JVM nhẹ, mà thực hiện đề nhẹ đúng (sợi AKA) trên JVM.Các chuỗi quasar hoạt động giống như các luồng Java đơn giản, ngoại trừ chúng hầu như không có bộ nhớ và chuyển đổi nhiệm vụ, do đó bạn có thể dễ dàng sinh ra hàng trăm nghìn sợi - hoặc thậm chí hàng triệu - trong một JVM duy nhất. Quasar cũng cung cấp các kênh truyền thông liên sợi được mô hình hóa sau các kênh được cung cấp bởi ngôn ngữ Go, hoàn chỉnh với các bộ chọn kênh. Nó cũng chứa đầy đủ việc thực hiện mô hình diễn viên, được mô hình hóa chặt chẽ sau Erlang.

Logic của Quasar đang chặn, vì vậy bạn có thể sinh ra, cho biết 24000 sợi đang chờ kết nối khác nhau. Một trong những điểm tích cực về Quasar là, các sợi có thể tương tác với các Threads đơn giản rất dễ dàng. Ngoài ra Quasar có tích hợp với các thư viện phổ biến, chẳng hạn như Apache HTTP client hoặc JDBC hoặc Jersey, v.v., vì vậy bạn có thể sử dụng lợi ích của việc sử dụng Sợi ở nhiều khía cạnh của dự án của bạn.
Bạn có thể thấy sự so sánh tốt giữa hai khung này here.

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