1 Project Architecture
Basic framework of 5 servers:
2 Game Dress Threads
Main-server and Logic Server configuration
Main-server
Executorservice Bossexecutor =Executors.newcachedthreadpool (); Executorservice Workerexecutor=Executors.newcachedthreadpool (); ChannelFactory ChannelFactory=Newnioserversocketchannelfactory (Bossexecutor, workerexecutor); Serverbootstrap Bootstrap=NewServerbootstrap (ChannelFactory); Executionhandler Executionhandler=NewExecutionhandler (NewOrderedmemoryawarethreadpoolexecutor (0, 0, Timeunit.minutes,Newthreadfactory () {PrivateAtomicinteger count =NewAtomicinteger (0); @Override Publicthread Newthread (Runnable r) {thread T=NewThread (R, "server-biz-pool-" + count.getandadd (1)); returnT; } }));//Define nameBootstrap.setpipelinefactory (NewGameserverpipelinefactory (Listenercon, Executionhandler));//gameserverpipelinefactory load the prescribed handler. and will add Executionhandler after Lengthfielddecoder//Disable the Nagle algorithm for highly interactive clientsBootstrap.setoption ("Child.tcpnodelay",true); //Set KeepAliveBootstrap.setoption ("Child.keepalive", Listenerconfiguration.iskeepalive ()); Bootstrap.bind (NewInetsocketaddress (Listenerconfiguration.getip (), Listenerconfiguration.getport ()));
Logic-server two types connection[for Mainserve], 8 for each type. 16 Connections in total
push[responsible for message push]
logic[responsible for business processing]
The pipelinefactory is configured with the appropriate filter and Handler:
The handler of the project have these several:
Lengthfielddecoder
executionhandler[executes channelhandler work
Therefore, in order to increase the number of concurrent, generally through the Executionhandler Line pool asynchronous processing Channelhandler chain (worker The thread ends after executionhandler , and it is ChannelFactory by the worker Collected by the thread pool). ]
Jsondecoder
requesthandler[Client passes the action is a string, back to Filter,like is login, through the specified bean name and method with invoke execution, request num use Atominteger Record.]
Lengthfieldprepender
Jsonencoder
For the thread pool model that Executionhandler needs,Netty provides two options:
1) memoryawarethreadpoolexecutor controls the use of thread pool memory to control Executor The upper limit of the task to be processed (when the upper limit is exceeded, subsequent tasks will be blocked), and can control the upper limit of the single Channel Backlog, and prevent memory overflow error;
2) orderedmemoryawarethreadpoolexecutor is memoryawarethreadpoolexecutor Sub-class. In addition to the functionality of Memoryawarethreadpoolexecutor , it also guarantees the sequence of event streams processed in the same Channel, This is primarily the sequence of events that control the errors that may occur in an event in asynchronous processing mode, but it does not guarantee that events in the same Channel are executed in one thread (often not necessary).
For example:
Thread X:---Channel A (Event A1)--. .--Channel B (event B2)---Channel B (event B3)--->
\ /
X
/ \
Thread Y:---channel B (event B1)--"channel A (event A2)---channel A (event A3)--->
There are several meanings to be expressed:
(1) for the entire thread pool, events that deal with the same Channel must be handled in order. For example, channel A (event A1) must be processed before channel a (event A2),Channel A (event A3) is processed .
(2) multiple events of the same Channel are distributed to multiple threads in the thread pool to be processed.
(3) different Channel events can be processed at the same time (sharing multiple threads) without affecting each other.
The Orderedmemoryawarethreadpoolexecutor of this sort of event handling is meaningful because, typically, the request sender expects the server to be able to process its own requests in order, especially the application layer protocol, which requires multiple handshakes. For example:XMPP protocol.
(Executionhandler reference: http://www.cnblogs.com/TeaMax/archive/2013/04/03/2997874.html)
// used in the project New Executionhandler (new memoryawarethreadpoolexecutor (8, 0, 0));
3 Project Message Queuing
Push queue
Principle: Put the required push information in the appropriate queue of Redis according to priority, and then take out the priority level.
//Asynchronous Message Processing//Main thread Private voidcommandprocess () {Try { while(true) { FinalCommand command = Commanddao.get (Priority.high, Priority.normal, Priority.lower, priority.message);//Blocking if(Command! =NULL) { FinalCommandHandler CommandHandler =commandhandlerfactory.getinstance (). GetHandler (Command.getcommand ()); Runnable Task=NewRunnable () {@Override Public voidrun () {commandhandler.handle (command);//transfer the processed messages through the push connection above } }; Gametaskprocessor.ins (). General (Task);//thread pool exec } Else { Break; } } } Catch(Exception e) {log.error (E.getmessage (), E); Try{Thread.Sleep (1000 * 5); } Catch(Interruptedexception ex) {Log.error (Ex.getmessage (), ex); } } }//Cache handler. You can also use Spring getbeanbyname instead. Public classCommandhandlerfactory {Private Static FinalLogger LOG = Loggerfactory.getlogger (commandhandlerfactory.class); PrivateMap<integer, commandhandler> commandhandlermap =NewHashmap<integer, commandhandler>(); Private StaticCommandhandlerfactory instance =NULL; Privatecommandhandlerfactory () {} Public Staticcommandhandlerfactory getinstance () {if(Instance = =NULL) {instance=Newcommandhandlerfactory (); } returninstance; } Public voidRegisterintcommand, CommandHandler handler) {//when spring instantiates the corresponding handler, the Init method invokes theLog.info ("command handler register.command[" + COMMAND + "]"); Commandhandlermap.put (command, handler); } PublicCommandHandler GetHandler (intcommand) { intKey = command/10000; if(Commandhandlermap.containskey (key)) {returnCommandhandlermap.get (key); } Else{Log.warn ("The command processor does not exist. command[" + Command + "], key[" + key + "]"); } return NULL; }}//put/get Command Public classCommanddaoredisimplImplementsCommanddao {Private Static Final intTime_out = 2; PrivateString GetKey (intPriority ) { returnRediskey.getcommandkey (priority); } @Override Public BooleanAdd (Command command) {String key=GetKey (Command.getpriority ()); Jedisutils.pushmsg (Key, Json.tojson (command)); return true; } @Override PublicCommand Get (Integer ... proritys) {string[] keys=NewString[proritys.length]; for(inti = 0; i < proritys.length; i++) {String key=GetKey (Proritys[i]); Keys[i]=key; } String JSON= Jedisutils.blockpopmsg (time_out, keys);//Blocking Methods if(JSON! =NULL) { returnJson.toobject (JSON, Command.)class); } return NULL; }}
Finally, using the push connection random a connection, handed to Netty processing.
Logic queue
Use Netty Channel Link+java reflection.
Summary of the first project