I have developped a client-server application using 64-bit kbmmw package on Delphi 10.3 IDE.The 64-bit client application send the requests to server by SendRequest method (kbmmwClient class method) setting the request service name and the username properties.Internally the kbmmwClient library create a request stream (TkbmMWCustomRequestTransportStream class) , which will be sent to the server.
Why are the characters of the service name (reqservice) and the username (ANDAPI) words interspersed with null characters?When I had used the 32-bit kbmmwClient, the request stream was sent in the correct format.
The first tests that were executed without concurrency in order to visualize the behavior of servers in a less critical situation. We did two tests, one with 100.000 and another with 1 million requests. This allowed us to evaluate whether the server behavior changes with increasing requests.
We observe in this test that the other servers are practically 13 times faster than Datasnap, the difference is huge. It is also possible to note a bottleneck (since all other servers have obtained the same result), possibly in the amount of requests that the client machine can send using a single thread.
Node.js got the worst result, but do not be fooled, because he got this result using only a single core. It is a limitation of the architecture of that framework, but I could, for example, have four instances initialized it and made a load balancing, which would bring me a performance higher than that obtained in this test. Unfortunately I did not had time to implement this solution.
The results of memory consumption remained similar to previous tests to mORMot, WCF and Node.Js servers. The Java server followed the trend already observed in other tests with a memory consumption proportional to the number of requests, at least concerning.
In this image we can see that the server was running 47 threads and the list of threads being created and destroyed is huge.
Another important detail is that practically all consumption of CPU in DataSnap server is overhead in creating and destroying threads.
There are some different approaches to web serving in Delphi apart from those exponed. Mormot is one of the best solutions, but for me is excesively complex to undestand for a newby. The product is incredibly sucessfull and has a design way ahead of Datasnap aproach.
Some of the issues you noticed and reported here are due to default settings or extra features that are part of DataSnap. For example, each request creates a new session, which expires by default after 20 minutes. And while I often use the IdHTTPserver myself, you might get better threading management deploying your application as an IIS library.
As I said to you by email. The most worrying problem for us is when the application crashes. The high memory consumption may have a way around. The problem of performance is the least critical of all, but also is important.
Interesting. I tried using different amounts of threads. In fact, it seems to me that there is no sufficient amount of threads to make it work. The overhead caused by the indy components kill the application, in my view.
I was getting a big problem when some SEO robots maped my servers. For thas reason I started some stress test using a freeware tool from realthinclient.com, for me the target was support an explosive requests: 10.000 open connection x 100 requests using 64 threads all responded correctly.
WCF and mORMot uses IOCP for serving JSON content over HTTP, via the native kernel-level http.sys server available since XP 2. This is one of the reasons of their stability and performance. mORMot is lighter and has a KISS and modular design, so seems to scale better than WCF, and use less resources.
I work daily in a cross-platform project using WCF, and when compared to mORMot, WCF is much more complex and need much more code to work with. For instance, you have to define one endpoint per interface, and write a client class. All this is transparent with mORMot: you just use interface instances, and you work with it. Take a look at the sources provided with this blog article, or the one available in =SQLite3/Samples/14+-+Interface+based+services and make yourself an idea.
Did you by chance considered actor-based frameworks like Erlang or Scala ? That is probably close to IOCP by idea. And that approach should be easy to millon-of-hello-world type of stress, like in this essay.
I have done some some testing too. Indy does not have a queue but creates as many threads as there are requests (till there are no more threads left) This even happens when you use a thread pool. The other effect of this is that requests are not handled in the order that they came. (Tested this) This will result into random performance because some requests which came in first can be handled much later then request posted afterwards. When you use iis for your websnap application you will have a proper queue and pool. But be aware I know some nice hidden tricks in websnap to do direct database access which may open up your internal database if the attacker can guess some of your internal component names. I would be very care full before connecting a websnap server directly to the internet.
Roberto, have you try to talk with Andreano Lanusse? He is no longer at Embarcadero but he can give you some insights, he is the guy when the topic is Datasnap and his blog ( ) has a lot of good stuffs about Datasnap
The performance issue on DataSnap REST Servers is not only related with Indy, but also with the Delphi JSON parser which is slower than other libraries like mORMot, superobject and jsonchimera. It will in parts affect TCP/IP connections, but TCP is another history.
On benchmarks like this running thousand of time, for sure JSON Parser contribute for the slow performance, on the other hand the other frameworks used has a much faster JSON parser and different architecture of course.
In the mean time would be good to see the same benchmark using TCP/IP and running the 3 different lifecycles. This article can help you to set that in runtime -datasnap-server-class-in-runtime-with-delphi/
I had planned to test the Data Abstract (RemObjects). But when I contacted support they said that does not support REST.
I did some basic tests. I noticed that they also use indy, and apparently also has problems. In performance tests I did RemObjects SDK seemed to be slower than the DataSnap.
There is a ridiculous limitation in the Datasnap. If you use datasnap with Shared connection to connect sqlconnection from client to sqlconnection in the server (DSAdmin.GetConnection) you can only transfer blob minor then 64k. You can increase BufferKbSize but does not work. The datasnap will return blob as null.
I would rather not use IIS as ISAPI extension.
First of all, it will need a 64 bit library to work on any modern system (since IIS will be loaded as 64 bit), and it will add unneeded overhead.
Delphi 64 bit compiler is less optimized than the 32 bit (apart from the floating point), and you certainly do not need more than 2/3 GB of memory, unless you need to change your server architecture. And you will face some compatibility issues when using 64 bit compiler (like third-party dependencies and more bugs).
I work with DataSnap since Delphi 2010. There is a problem when you use a Server on Session lifecycle with statefull work.
The best way to work with DataSnap is Invocation with stateless method. Then your test will not crash! Try it and write, what happens!
To see wether Indy or DataSnap is the bottleneck, I ran a single-threaded JMeter test of the Indy HTTP server on a quite slow system (Mobile Core2 Duo @ 2.1 GHz), with HTTP 1.1 keep-alive enabled. The average throughput was 320 requests/second, with zero (0) % HTTP errors. The CPU load was around 40%, Client and server where running on the same system. In the tests described above, DataSnap with Indy as HTTP transport reached 62 requests/second on a Core i5 750 with 4 x 2,67 GHz system.
With mORmot we tried to make the faster JSON parser possible for our purpose.
In fact, all JSON content is parsed in-place in the input text buffer: no memory is allocated, just data is un-escaped as UTF-8, and an array of pointers to the input buffer is created. This is incredibly fast (a similar algorithm is used in the fastest XML readers).
See -JSON-parsing
This is diverse from SuperObject or the JSON parser included in DWS (which is faster than SuperObject): both creates objects tree in memory to map the content.
Threfore, the parser included in mORMot is in fact *much* faster, especially when used in a multi-threaded server. The same for the JSON producer of mORMot, which avoid as much memory allocation as possible, and try to achieve best possible speed in multi-thread environment.
In the DataSnap server project (DataSnap_Console_Server), I see no KeepAlive setting for the LServer. Your JMeter test has KeepAlive enabled, but the DataSnap server defaults to KeepAlive False (found at -rest-server-enable-http-keepalive). I guess the server will always close the connection immediately, leaving (one million?) of sockets with state TIME_WAIT in the OS,
I want to make clear (Maybe gotten the wrong impression) that I am not wanting a Wizard with more options and everything is configurable thru clicks. None of the other servers I have developed has Wizards and are still working perfectly. I think the documentation of the DataSnap is very weak. I am not charging everything to be easy to implement, just need to have documentation to tell me how the framework works, so I can implement.
The RemObjects support told me that the framework does not support REST. That was one of the reasons why I have not used it in testing. Another reason is that the framework of RemObjects showed a behavior very similar to datasnap in some tests I did. They also use Indy. I did some testing with this framework and server performance was worse than the DataSnap. Of course, there must be optimizations to be made, so with DataSnap, but the framework is very large, I have not had time to study it.
c80f0f1006