Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement sliding window scale logic. #110

Open
lzaiats opened this issue Nov 5, 2017 · 110 comments
Open

Implement sliding window scale logic. #110

lzaiats opened this issue Nov 5, 2017 · 110 comments
Assignees

Comments

@lzaiats
Copy link

lzaiats commented Nov 5, 2017

I have been testing LiteNetLib, Lidgren-gen3 and Lidgren-old (the one from Google Code) and Lidgren-old is beating the competitors by far... On my test I have 750 clients connected to a single server instance, receiving ~15 reliable msgs/s and ~100 unreliable msgs/s and Lidgren-old can handle all this data perfectly! Using the same "game code" but using Lidgren-gen3 or LiteNetLib the test "fails" between 100 and 120 clients... Maybe I am missing something with LiteNetLib API, so I can achieve better performance... Do you have any idea where I am doing wrong with your Lib? If you need I can share the code :)

  • My test is using my area of interest management layer, so it can efficiently send to clients only data important to them. Only using this technique I was able to achieve 750 clients on a single server :) Every client is also sending ~15 unreliable msgs/s (movement messages)

Thanks and keep the awesome work!

@lzaiats lzaiats changed the title BEMCHMARK BENCHMARK Nov 5, 2017
@RevenantX
Copy link
Owner

@lzaiats Hi!

? If you need I can share the code :)

Can you show minimal sample code that works slower than Lidgren-old?

@lzaiats
Copy link
Author

lzaiats commented Nov 5, 2017

Basically it is UDP congestion the problem.. Lidgren-old appears to drop less packets than LiteNetLib, for example... I will reproduce a little sample code, with LiteNetLib, Lidgren-gen3 and Lidgren-old so you can see the "thing" on your local machine ;)

BTW, i've implemented a custom NetSerializer that use MessagePack (the optimized from neuecc) for serialization and it works great! Maybe it can be usefull to other LiteNetLib users ;)

@lzaiats
Copy link
Author

lzaiats commented Nov 6, 2017

Hi @RevenantX !

Here is the simple benchmark I made... It sends reliable and unreliable messages and count sent and received messages... LiteNetLib reliable performance is not good compared to Lidgren-old! On my "game project" after some time, the clients simply stops receiving reliable instantiate messages and the game stops working... Another important point to mention is the memory consumption... Lidgren-old test is almost not using memory allocations at all, while LiteNetLib test uses > 2Gig...

Here is the results:

Testing Lidgren-old...
Processing...
CLIENT SENT -> Reliable: 261800, Unreliable: 748000
SERVER RECEIVED -> Reliable: 261800, Unreliable: 748000


Testing LiteNetLib...
Processing...
CLIENT SENT -> Reliable: 262500, Unreliable: 750000
SERVER RECEIVED -> Reliable: 51215, Unreliable: 750000

UDPLibBench.zip

@RevenantX
Copy link
Owner

@lzaiats thank you! I will investigate this. Something wrong with send speed.

@RevenantX
Copy link
Owner

@lzaiats high memory consumption caused by packet pooling. I think i must add some limits to pooled packets.

@mgamache
Copy link

mgamache commented Dec 8, 2017

By staring a second client on the same machine I was able to double the bandwidth transfer on the same connection so this suggests a rate limit inside each client. Would a bounty help you find the time to work on this issue?

@RevenantX
Copy link
Owner

RevenantX commented Dec 8, 2017

@mgamache i know why this problem exits) As i said before - this because i don't implemented "sliding window scale" logic. This requires some time to implement.

Would a bounty help you find the time to work on this issue?

Donations always help to find the time to work on library entirely :) But i can't promise fast fix(implementaiton) right now, because i'm working on two projects. But soon (end of december) i will have some time for library features and improvements.

@RevenantX RevenantX changed the title BENCHMARK Implement sliding window logic. Dec 8, 2017
@RevenantX RevenantX changed the title Implement sliding window logic. Implement sliding window scale logic. Dec 8, 2017
@RevenantX RevenantX added this to the LiteNetLib 0.8 milestone Dec 8, 2017
@Saishy
Copy link
Contributor

Saishy commented Dec 8, 2017

Hey, remember me?

So was going to ask if you want to share profits on releasing https://github.com/Saishy/TinyBirdNet-Unity at the asset store.
I was intending it to be free for free projects and paid for commercial ones. (still open source tho)

@RevenantX
Copy link
Owner

@lzaiats hi! Try latest version from github. I heavily optimized sending code. Your problem (with 750 clients) must be fixed. (but not benchmark)

@RevenantX
Copy link
Owner

@Saishy

Hey, remember me?

Yes)

So was going to ask if you want to share profits on releasing https://github.com/Saishy/TinyBirdNet-Unity at the asset store.
I was intending it to be free for free projects and paid for commercial ones. (still open source tho)

You can donate any amount that you think is necessary)

@lzaiats
Copy link
Author

lzaiats commented Dec 14, 2017

@RevenantX Heeeey! Awesome news!

I ran the tests changing the values of the NetConstants.DefaultWindowSize and here are the results:

---- WindowSize = 16
Testing LiteNetLib...
Processing...
DataSize: 43537500b, 42517kb, 41mb
CLIENT SENT -> Reliable: 262500, Unreliable: 750000
SERVER RECEIVED -> Reliable: 11984, Unreliable: 749242

---- WindowSize = 32
Testing LiteNetLib...
Processing...
DataSize: 43537500b, 42517kb, 41mb
CLIENT SENT -> Reliable: 262500, Unreliable: 750000
SERVER RECEIVED -> Reliable: 23968, Unreliable: 749236

---- WindowSize = 64
Testing LiteNetLib...
Processing...
DataSize: 43537500b, 42517kb, 41mb
CLIENT SENT -> Reliable: 262500, Unreliable: 750000
SERVER RECEIVED -> Reliable: 46080, Unreliable: 749177

---- WindowSize = 128
Testing LiteNetLib...
Processing...
DataSize: 43537500b, 42517kb, 41mb
CLIENT SENT -> Reliable: 262500, Unreliable: 750000
SERVER RECEIVED -> Reliable: 88832, Unreliable: 749097

---- WindowSize = 256
Testing LiteNetLib...
Processing...
DataSize: 43537500b, 42517kb, 41mb
CLIENT SENT -> Reliable: 262500, Unreliable: 750000
SERVER RECEIVED -> Reliable: 137728, Unreliable: 749429

---- WindowSize = 512
Testing LiteNetLib...
Processing...
DataSize: 43537500b, 42517kb, 41mb
CLIENT SENT -> Reliable: 262500, Unreliable: 750000
SERVER RECEIVED -> Reliable: 219674, Unreliable: 749907

---- WindowSize = 1024
Testing LiteNetLib...
Processing...
DataSize: 43537500b, 42517kb, 41mb
CLIENT SENT -> Reliable: 262500, Unreliable: 750000
SERVER RECEIVED -> Reliable: 262150, Unreliable: 750000

IMPRESSIVE!

I'll do some more testing using the real 750 clients and share the results with you! Thank you!

@RevenantX
Copy link
Owner

RevenantX commented Dec 14, 2017

@lzaiats don't increase it manually. It must be increased automatically (later).
My current fix must increase performance of real game server (with many clients!). (not file transfer to 1 peer)

@lzaiats
Copy link
Author

lzaiats commented Dec 14, 2017

@RevenantX ;) Actually I only increased the value by hand to understand the maximum throughput the lib could achieve... On the game (production) I will not touch this number ;)

One thing that is still making me a little confused is that on all circunstances, the bytes sent by the client and the bytes received by the server are almost the same... But the number of messages are completely different... Have a look:

Testing LiteNetLib...
Processing...
DataSize: 43537500b, 42517kb, 41mb
CLIENT SENT -> Reliable: 262500, Unreliable: 750000
CLIENT STATS:
BytesReceived: 36632
PacketsReceived: 1599
BytesSent: 41320993
PacketsSent: 839281
PacketLoss: 2797
PacketLossPercent: 0

SERVER RECEIVED -> Reliable: 89536, Unreliable: 749593
SERVER STATS:
BytesReceived: 41335938
PacketsReceived: 839586
BytesSent: 36632
PacketsSent: 1599
PacketLoss: 0
PacketLossPercent: 0

@RevenantX
Copy link
Owner

RevenantX commented Dec 14, 2017

@lzaiats after some time all reliable messages will be received. Add more time before showing statistics) They just in queue.

@RevenantX
Copy link
Owner

@lzaiats real packets sent is - PacketsSent: 839281

@RevenantX
Copy link
Owner

@lzaiats

I'll do some more testing using the real 750 clients and share the results with you! Thank you!

Any news?)

@DanisJoyal
Copy link

@Izaiats Hi,

Did you try with a lower DefaultUpdateTime ? Like 5 ms. Can it help ? Maybe the thread shouldnt stop until there is nothing else to process, wait after that.

@nxrighthere
Copy link

nxrighthere commented Jan 14, 2018

@DanisJoyal It doesn't help, I already tried.

@DanisJoyal
Copy link

@nxrighthere Maybe 1 ms sleep too much. Maybe it needs to none stop update until its done.

@lzaiats
Copy link
Author

lzaiats commented Jan 14, 2018

@DanisJoyal I tried a lot of configurations and I had no luck!

@nxrighthere Nice to see your benchmark suite! Also I made one using exact the same libs you did and the results are just the same! Using ENet wrapper gives the best result always! If you want to see good results with another lib, try this OLD lidgren version: https://code.google.com/archive/p/lidgren-network/downloads , the one from Jan 22, 2010... It's almost the same API as Lidgren-v3 but will show you results comparable to ENet ;)

@RevenantX I stopped benchmarking for now, maybe we can continue the investigation using @nxrighthere test suite now, since it's more complete and modular than mine!

@DanisJoyal
Copy link

@lzaiats Hi,

I just ran your UDPLibBench.zip. I ve got to adapt it to my latest version, on my fork. So far, Ive got this:

Testing LiteNetLib...
Processing...
CLIENT SENT -> Reliable: 262500, Unreliable: 750000
PacketLossPercent: 0(672)
Bytes Received/Sent: 57281/50915910
Packets Received/Sent: 4215/1007890
SERVER RECEIVED -> Reliable: 262500, Unreliable: 750000
PacketLossPercent: 0(0)
Bytes Received/Sent: 51156422/57568
Packets Received/Sent: 1012621/4241

No Issue, except a little bit packets loss on client side.

Im running 2 clients thread at the same time on the same server to see if it last.

Cheers

@nxrighthere
Copy link

nxrighthere commented Jan 25, 2018

I'm so confused right now... I did a test with the old version of Lidgren as @lzaiats suggested, and you know what? It's passed the test with 1000 clients... CPU usage 60%, memory consumption 360 megabytes.

@lzaiats
Copy link
Author

lzaiats commented Jan 25, 2018

@nxrighthere Bingo! :) The old lidgren version is far better than the gen3, and its also almost the same performance than ENet... Amazing ;)

@DanisJoyal
Copy link

Thats funny. So, you re telling me that google are so dumb to create a new version of the lib worst than the first one. I think that it s an issue from the .Net Framework. Maybe you can try the old Lidgren to use .Net Framework > 4.5. I didnt have time since 1 week to continue my investigation. But, I saw that the framework its not using the same sendto function as Enet. I will check that this week end. Cheers.

@nxrighthere
Copy link

nxrighthere commented Jan 25, 2018

I'm using .NET Framework 4.7.1 for all libraries.

@DanisJoyal
Copy link

You re overwriting the framework set by default ? The old lidgren is using .Net Framework 2.0. Anyway, if Lidgren is able to do it. LiteNetLib should be able too.

@nxrighthere
Copy link

nxrighthere commented Jan 25, 2018

I'm not using the csproj at all, I compile everything directly with Roslyn.

@RevenantX
Copy link
Owner

@nxrighthere @DanisJoyal added DISABLE_IPV6 ifdef. So you can disable ipv6 thread (so this is 1000 less threads in that test). Passed test with 1200 clients.

@nxrighthere
Copy link

nxrighthere commented Jan 27, 2018

Yea, works better now. 900 clients are connected and after that the CPU usage raises 92% and the application becomes unresponsive. But very nice anyway.

@nxrighthere
Copy link

nxrighthere commented Jan 27, 2018

GC is still the biggest performance killer. I tried to build the library with built-in Roslyn's optimization logic and now 950 connections is reached, but the server thread just crashed.

@nxrighthere
Copy link

nxrighthere commented Jan 29, 2018

[Link removed] @DanisJoyal @RevenantX!

@RevenantX
Copy link
Owner

@nxrighthere O_o. There is crash and bytes count is diffferent...

@nxrighthere
Copy link

Yea, it breaks for some reason.

@nxrighthere
Copy link

nxrighthere commented Jan 30, 2018

Now it works much better.

@RevenantX
Copy link
Owner

@nxrighthere how?

@nxrighthere
Copy link

nxrighthere commented Jan 30, 2018

@nxrighthere
Copy link

Take a look at this.

@lzaiats
Copy link
Author

lzaiats commented May 21, 2018

Hi guys! Long time since my last post here =)

I just wanted to share with you the current stage of my MMO server architecture and the feedback coming from you guys (@RevenantX @nxrighthere @DanisJoyal ) is a pot of gold to me!

https://youtu.be/OZ4j574VYrk


Welcome to netEngineX (temporary name) showcase! A distributed MMO server architecture using C# and Unity (other game engines soon)!

Basically, netEngineX consists of three parts:

  1. State Server (entities and infrastructure management)
  2. Workers (unity instances for world simulation)
  3. Clients (unity instances for players)

This is a simple demo to show the current state of this technology:

  1. We start a spectator client @ 10 statesyncs per second (no player controlled character for this demo)
  2. We spawn 50 dumb AIs with one CharacterController each;
  3. We spawn 1 Worker and assign the 50 AIs to its simulation;
  4. We spawn more 550 dumb AIs and assign to this Worker simulation;
  5. As you can see, the Worker FPS is low due to 600 CharacterControllers...
  6. We spawn 2 more Workers and divide the simulation over the 3 Workers;
  7. Now the load is distributed over the 3 Workers \o/
  8. Now we show some more cool features like: Auto Worker Assignment when Worker dies, Stopped game simulation without Workers and other stuff... =)
  • One client is connected as spectator so you can see that all the entities redistribution works seamlessly...

** netEngineX have built-in Network LOD using groups to save bandwidth...

*** This is not a real game, but if you can imagine all the possibilities =) All Workers are running locally, but yes, they can be run across the network... We are using CharacterController (heavy) to simulate AIs so we have a more close simulation of (600) player controlled characters...

**** netEngineX can be adapted to use any UDP lib (lidgren, litenetlib, enet or any other). Currently using lidgren-old (from Google Code)...

Suggestions and questions, feel free to email me!

Thanks for watching!

@OlegGlushko
Copy link

@lzaiats
Hey I am building similar architecture myself and was curious if you could share some of your ideas/knowledge. Do you have an email I could contact you at?

@Frooxius
Copy link
Contributor

Hello!

Can I ask what's the status of this feature - specifically the sliding window scale logic? Is this still something that's being considered? I see there's a lot of talk about performance and other things in this thread, so I'm not fully certain if that's still the focus.

With our use-case, we often run into an issue, where the higher someone's latency is (often times between US <--> Australia and such), the throughput degrades. I believe this is in big part happening due to the sliding window not being large enough to properly saturate that distance, so I think this could help with those kinds of connections.

@RevenantX
Copy link
Owner

@Frooxius well ReliableOrdered should be used in RUDP last of all. Mostly packets should be Unreliable/Sequenced - and then you will not get that problem.
If 80-90% of your packets is ReliableOrderd - it will be much better to use just TCP socket

@RevenantX
Copy link
Owner

@Frooxius also if you will use GetMaxSinglePacketSize and pack your Reliable packets tightly - you will get better performance

@Frooxius
Copy link
Contributor

@RevenantX We use Unrealiable/Sequenced for what we can - continuously changing poses, voice data and so on.

However we have other type of changes, which require reliable transmission, because they are various delta changes to the state of the world - they can be random and they need to happen in the right order as well. This normally works well for our purposes, but the transmission throughput degrades with latency, which is the primary issue we're having.

TCP socket is not suitable our purposes for two main reasons. One it's generally not recommended to mix both UDP and TCP (e.g.: https://gamedev.stackexchange.com/questions/165392/will-tcp-really-affects-udp-if-used-in-different-context and https://gamedev.stackexchange.com/questions/120115/does-it-make-sense-to-use-both-tcp-and-udp-at-once) and second, UDP allows for hole punching, but TCP not as much.

@RevenantX
Copy link
Owner

@Frooxius you can check https://github.com/RevenantX/LiteEntitySystem/ it uses ReliableOrdered only for BaseState (full game state). And later Unreliable for delta states (that include rpcs). So you can achieve reliability without using ReliableOrdered in much better way. User input also sent to server as Unreliable

@emrys90
Copy link

emrys90 commented Jan 26, 2024

+1 for sliding window scale

@Frooxius
Copy link
Contributor

@RevenantX Unfortunately that approach is not applicable for our project, because we need to synchronize complex state changes of data model.

I am not really looking here for suggestions for alternate approaches and workarounds for our project to get around this issue, we do what we can on our end there.

My main interest was if there are any plans to work on this issue to improve the networking performance, especially with higher latency between endpoints?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants