java - ejemplo - jlabel netbeans
Hilo de Java por modelo de conexión vs NIO (6)
Como la mayoría de ustedes está diciendo que el servidor está bloqueado en el uso de la CPU antes de que se llegue a 10k usuarios concurrentes, supongo que es mejor para mí usar un enfoque de bloqueo roscado (N) IO considerando el hecho de que para este particular MMORPG, obtener varios paquetes por segundo para cada jugador no es infrecuente y puede empantanar un selector si uno fuera a ser utilizado.
Peter planteó un punto interesante que el bloqueo de NIO es más rápido que las bibliotecas antiguas, mientras que irrecusable mencionó que para un servidor MMORPG ocupado, sería mejor utilizar subprocesos debido a la cantidad de instrucciones que se reciben por jugador. No contaría con demasiados jugadores que están inactivos en este juego, por lo que no debería ser un problema para mí tener un montón de subprocesos que no se ejecutan. Me he dado cuenta de que la sincronización aún es necesaria incluso cuando se utiliza un marco basado en NIO porque utilizan varios subprocesos de trabajo que se ejecutan al mismo tiempo para procesar los paquetes recibidos de los clientes. El cambio de contexto puede resultar costoso, pero intentaré con esta solución. Es relativamente fácil refactorizar mi código para poder usar un marco de NIO si encuentro que hay un cuello de botella.
Creo que mi pregunta ha sido respondida. Esperaré un poco más para recibir aún más información de más personas. ¡Gracias por todas tus respuestas!
EDIT: finalmente he elegido mi curso de acción. En realidad estaba indeciso y decidí usar JBoss Netty y permitirle al usuario cambiar entre oio o nio usando las clases
org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
org.jboss.netty.channel.socket.oio.OioServerSocketChannelFactory;
¡Qué bueno que Netty admite ambos!
¿El Java NIO no bloqueante es aún más lento que el hilo estándar por socket asíncrono de conexión?
Además, si usara hilos por conexión, ¿crearía hilos nuevos o utilizaría un grupo de hilos muy grande?
Estoy escribiendo un servidor MMORPG en Java que debería poder escalar 10000 clientes fácilmente con hardware suficientemente potente, aunque la cantidad máxima de clientes es 24000 (que creo que es imposible de alcanzar para el hilo por modelo de conexión debido a un hilo de 15000 límite en Java). De un artículo de hace tres años, he escuchado que bloquear IO con un hilo por modelo de conexión era todavía un 25% más rápido que NIO (es decir, este documento http://www.mailinator.com/tymaPaulMultithreaded.pdf ), pero puede lo mismo se puede lograr en este día? Java ha cambiado mucho desde entonces, y he escuchado que los resultados eran cuestionables cuando se comparan escenarios de la vida real porque la VM utilizada no era Sun Java. Además, dado que es un servidor MMORPG con muchos usuarios simultáneos que interactúan entre sí, ¿el uso de las prácticas de sincronización y seguridad de subprocesos disminuirá el rendimiento hasta el punto de que un selector de NIO con un único subproceso que atienda 10000 clientes sea más rápido? (No es necesario procesar todo el trabajo en el hilo con el selector, se puede procesar en hilos de trabajo como funciona MINA / Netty).
¡Gracias!
En realidad hay 3 soluciones:
- Múltiples hilos
- Un hilo y NIO
- Ambas soluciones 1 y 2 al mismo tiempo
Lo mejor que se puede hacer por el rendimiento es tener un número pequeño y limitado de subprocesos y eventos de red múltiplex en estos subprocesos con NIO a medida que ingresan nuevos mensajes a través de la red.
Usar NIO con un hilo es una mala idea por algunas razones:
- Si tiene varias CPU o núcleos, estará inactivo de recursos ya que solo puede usar un núcleo a la vez si solo tiene un hilo.
- Si tiene que bloquear por alguna razón (tal vez para hacer un acceso al disco), su CPU está inactiva cuando podría manejar otra conexión mientras espera el disco.
Un hilo por conexión es una mala idea porque no escala. Digamos que tiene:
- 10 000 conexiones
- 2 CPU con 2 núcleos cada uno
- solo 100 hilos serán bloqueados en un momento dado
Entonces puedes descubrir que solo necesitas 104 hilos. Más y estás desperdiciando recursos administrando hilos adicionales que no necesitas. Hay una gran cantidad de contabilidad bajo el capó necesaria para gestionar 10 000 hilos. Esto lo retrasará.
Es por eso que combina las dos soluciones. Además, asegúrese de que su VM esté usando las llamadas al sistema más rápidas. Cada sistema operativo tiene sus propias llamadas al sistema únicas para IO de red de alto rendimiento. Asegúrese de que su máquina virtual esté usando lo último y lo mejor. Creo que esto es epoll () en Linux.
Además, si usara hilos por conexión, ¿crearía hilos nuevos o utilizaría un grupo de hilos muy grande?
Depende de cuánto tiempo desee optimizar. La solución más rápida es crear recursos como hilos y cadenas cuando sea necesario. Luego deje que la recolección de basura los reclame cuando haya terminado con ellos. Puede obtener un aumento de rendimiento al tener un grupo de recursos. En lugar de crear un objeto nuevo, le pide al grupo uno y lo devuelve al grupo cuando haya terminado. Esto agrega la complejidad del control de concurrencia. Esto se puede optimizar aún más con algoritmos de concurrencia avanzada como algoritmos sin bloqueo . Las nuevas versiones de la API de Java tienen algunos de estos para usted. Puede pasar el resto de su vida haciendo estas optimizaciones en un solo programa. Cuál es la mejor solución para su aplicación específica es probablemente una pregunta que merece su propia publicación.
Los beneficios de NIO deben tomarse con un grano de sal.
En un servidor HTTP, la mayoría de las conexiones son conexiones keep-alive, están inactivas la mayoría de las veces. Sería un desperdicio de recursos preasignar un hilo para cada uno.
Para el MMORPG las cosas son muy diferentes. Supongo que las conexiones están constantemente ocupadas recibiendo instrucciones de los usuarios y enviando el último estado del sistema a los usuarios. Se necesita un hilo la mayor parte del tiempo para una conexión.
Si usa NIO, tendrá que volver a asignar constantemente un hilo para una conexión. Puede ser una solución inferior a la solución simple de hilo fijo por conexión.
El tamaño predeterminado de la pila de subprocesos es bastante grande (1/4 MB). Es la principal razón por la que solo puede haber subprocesos limitados. Intenta reducirlo y ver si tu sistema puede soportar más.
Sin embargo, si tu juego está realmente "ocupado", es tu CPU la que debes preocuparte más. NIO o no, es realmente difícil manejar miles de jugadores hiper activos en una máquina.
Puede obtener algo de inspiración del antiguo proyecto patrocinado por Sun, ahora llamado Red Dwarf. El viejo sitio web en http://www.reddwarfserver.org/ está fuera de servicio.
Github al rescate: https://github.com/reddwarf-nextgen/reddwarf
Si está dispuesto a gastar cualquier cantidad de dinero en hardware lo suficientemente potente, ¿por qué limitarse a un servidor? google no usa un servidor, ni siquiera usan un centro de datos de servidores.
Una idea errónea común es que NIO permite IO no bloqueante, por lo que es el único modelo que vale la evaluación comparativa. Si compara el bloqueo de NIO, puede obtenerlo un 30% más rápido que el IO antiguo. es decir, si usa el mismo modelo de subprocesamiento y compara solo los modelos de E / S.
Para un juego sofisticado, es mucho más probable que se quede sin CPU antes de llegar a las conexiones de 10K. De nuevo, es más simple tener una solución que se escale horizontalmente. Entonces no necesita preocuparse por la cantidad de conexiones que puede obtener.
¿Cuántos usuarios pueden interactuar razonablemente? 24? en cuyo caso tiene 1000 grupos independientes interactuando. No tendrás tantos núcleos en un solo servidor.
¿Cuánto dinero por usuario piensa gastar en servidor (es)? Puede comprar un servidor de 12 núcleos con 64 GB de memoria por menos de £ 5000. Si coloca 2500 usuarios en este servidor, habrá gastado £ 2 por usuario.
EDITAR: Tengo una referencia http://vanillajava.blogspot.com/2010/07/java-nio-is-faster-than-java-io-for.html que es mía. ;) Hice una revisión por alguien que es un GURU de Java Networking y estuvo de acuerdo con lo que había encontrado.
Si tiene conexiones ocupadas, lo que significa que constantemente le envían datos y los envía de vuelta, puede usar non-Blocking IO
junto con Akka
.
Akka es un kit de herramientas de código abierto y tiempo de ejecución que simplifica la construcción de aplicaciones concurrentes y distribuidas en la JVM. Akka admite múltiples modelos de programación para concurrencia, pero enfatiza la concurrencia basada en actores, con inspiración extraída de Erlang. Existen enlaces de lenguaje para Java y Scala.
La lógica de Akka no bloquea, por lo que es perfecta para la programación asincrónica. Usando Akka Actors
puedes eliminar el Thread overhead
.
Pero si su socket se bloquea con mayor frecuencia, le sugiero que use Blocking IO
junto con Quasar
Quasar es una biblioteca de código abierto para la concurrencia de JVM simple y liviana, que implementa hilos ligeros verdaderos (fibras AKA) en la JVM. Las fibras Quasar se comportan como los hilos simples de Java, excepto que prácticamente no tienen memoria y tareas de cambio de tareas, por lo que puede generar fácilmente cientos de miles de fibras, o incluso millones, en una sola JVM. Quasar también proporciona canales para comunicaciones interfibras modeladas a partir de las que ofrece el lenguaje Go, completadas con selectores de canales. También contiene una implementación completa del modelo de actor, muy similar a Erlang.
La lógica de Quasar es bloqueante, por lo que puedes generar, digamos 24000 fibras esperando conexiones diferentes. Uno de los puntos positivos sobre Quasar es que las fibras pueden interactuar fácilmente con los hilos lisos. También Quasar tiene integraciones con bibliotecas populares, como Apache HTTP client
o JDBC
o Jersey
y así sucesivamente, por lo que puede utilizar los beneficios del uso de Fibras en muchos aspectos de su proyecto.
Puede ver una buena comparación entre estos dos marcos here .