Original Post
This post is a bit of an extension of my previous two posts Trying to get my IOCP code on par with expected performance and [Article] Using UDP with IOCP. I've begun working on what I hope would be a scalable high performance server architecture useful in an online game with a large number of concurrent users. This is how I envision it would work:
The public interface to the network as a whole is handled on the first layer. There would be 1..n of these IOCP servers that handle the network traffic for the entire system. Packet security and physical validation would take place in this layer. When packets are deemed to be complete and physically valid, they would be passed to the second layer. I achieve scalability here by simply being able to add more servers and update the client with a list to connect to. The second layer is a collection of 1..m switch servers that route complete packets from the first layer to the desired destination in the third layer as well as packets from the third layer to other servers in the third layer. The database is used to store connection specific data sent from the first and third layers so that information can be kept to route the response packets back to where they need to go. That logic would be handled through a specific packet protocol not yet described. I achieve scalability here by simply being able to add more servers and update the 1st/3rd layer servers with a list of available switches to use. The third layer is composed of all of the "logical" servers for the system. If servers need to talk to each other, they will go through the second layer so the switch servers can router the packets to the other servers that need the information. Likewise when a server in layer 3 needs to return data to a client, it just sends the data to the second layer with a specific protocol so the switch server then sends it back to the correct layer 1 server that contains the client to send to. I don't have a blueprint on the exact packet protocol for the internal communication, but it would be really simple, it'd contain the local and remote addresses for the client and the original server, possibly some flags and then the data to be sent. There is no specific UDP or TCP protocol specified right now, but ideally that would be up to the user to choose which one would work best. I believe for now I'd just use TCP, but UDP could be used with a simple protocol like enet. Each "Server" listed on the image does not necessary mean a physical machine on the network, but the design should allow for that. It could just as well be another process! For starting out, I will have one physical server and have one IOCP process in layer one, one switch process in layer 2, the database in layer 2, and one server in layer 3 (world). My reasoning for this design has to do with some recent success with splitting up a networking task into two parts, a low level part that does all the performance critical work in C++ and a high level part that uses readily formatted data in C#. With this setup, I envision all of the performance critical networking traffic being processed by C++ IOCP processes and my actual "logical servers" can be done in a variety of languages as I need. The second layer routing servers is to easily allow all the servers to interact as needed. As of right now I am working on the protocol between the 2nd and 1st/3rd layers. The layer 1 server design is done, so that code can be used in the 2nd and 3rd layers for my servers there, even though I plan on making another server in C# for the 3rd layer. I already have an ambition to actually complete this design and see how it works in practice myself, but I'd like to know what everyone else thinks about it. Am I overlooking anything and are there any serious flaws? So please, let me have all your thoughts about it! [smile] [Edited by - Drew_Benton on October 5, 2009 11:10:39 PM]
The public interface to the network as a whole is handled on the first layer. There would be 1..n of these IOCP servers that handle the network traffic for the entire system. Packet security and physical validation would take place in this layer. When packets are deemed to be complete and physically valid, they would be passed to the second layer. I achieve scalability here by simply being able to add more servers and update the client with a list to connect to. The second layer is a collection of 1..m switch servers that route complete packets from the first layer to the desired destination in the third layer as well as packets from the third layer to other servers in the third layer. The database is used to store connection specific data sent from the first and third layers so that information can be kept to route the response packets back to where they need to go. That logic would be handled through a specific packet protocol not yet described. I achieve scalability here by simply being able to add more servers and update the 1st/3rd layer servers with a list of available switches to use. The third layer is composed of all of the "logical" servers for the system. If servers need to talk to each other, they will go through the second layer so the switch servers can router the packets to the other servers that need the information. Likewise when a server in layer 3 needs to return data to a client, it just sends the data to the second layer with a specific protocol so the switch server then sends it back to the correct layer 1 server that contains the client to send to. I don't have a blueprint on the exact packet protocol for the internal communication, but it would be really simple, it'd contain the local and remote addresses for the client and the original server, possibly some flags and then the data to be sent. There is no specific UDP or TCP protocol specified right now, but ideally that would be up to the user to choose which one would work best. I believe for now I'd just use TCP, but UDP could be used with a simple protocol like enet. Each "Server" listed on the image does not necessary mean a physical machine on the network, but the design should allow for that. It could just as well be another process! For starting out, I will have one physical server and have one IOCP process in layer one, one switch process in layer 2, the database in layer 2, and one server in layer 3 (world). My reasoning for this design has to do with some recent success with splitting up a networking task into two parts, a low level part that does all the performance critical work in C++ and a high level part that uses readily formatted data in C#. With this setup, I envision all of the performance critical networking traffic being processed by C++ IOCP processes and my actual "logical servers" can be done in a variety of languages as I need. The second layer routing servers is to easily allow all the servers to interact as needed. As of right now I am working on the protocol between the 2nd and 1st/3rd layers. The layer 1 server design is done, so that code can be used in the 2nd and 3rd layers for my servers there, even though I plan on making another server in C# for the 3rd layer. I already have an ambition to actually complete this design and see how it works in practice myself, but I'd like to know what everyone else thinks about it. Am I overlooking anything and are there any serious flaws? So please, let me have all your thoughts about it! [smile] [Edited by - Drew_Benton on October 5, 2009 11:10:39 PM]