Skip to content

Performance difference when using ResponseBuffering middleware #3100

Closed
@chrisckc

Description

@chrisckc

The default configuration of a new .Net Core project does not use Reponse Buffering, instead the response is sent in chunks so that the result payload can start to be sent while it is being serialized which is supposed to improve memory usage and performance. This is a new feature in .NET Core, in my initial testing when coming from the previous generation of .NET i was not aware of this new feature that was enabled by default.

I have done some basic testing to help decide whether it is worth sticking with the default or using the ResponseBuffering middleware which in theory would slow things down and consume more server RAM.

The tests where run from a .Net Core 2 Web API using an in memory data repository. The throughput tests where ran for 10 seconds several times over to obtain an average result. The payload size is the total size including the headers. The memory usage was monitored during a 60 second throughput test. (observing the 3 dotnet processes found).

Everything was performed locally on a Macbook Pro with 16GB RAM.

Throughput tests returning a 730 Byte JSON payload:
Default configuration (no response buffering):

  • Average throughput: ~3500 requests/sec
  • Peak memory usage ~900MB

Using the ResponseBuffering middleware:

  • Average throughput: ~4000 requests/sec
  • Peak memory usage ~900MB

The results were surprising, faster average throughput when using ResponseBuffering with no real difference in memory usage so i then tried the same with a 10KB payload...

Throughput tests returning a 10KB JSON payload:
Default configuration (no response buffering):

  • Average throughput: ~2500 requests/sec
  • Peak memory usage ~400MB

Using the ResponseBuffering middleware:

  • Average throughput: ~2400 requests/sec
  • Peak memory usage ~300MB

The results were very close, so i then tried the same with a 100KB payload...

Throughput tests returning a 100KB JSON payload:
Default configuration (no response buffering):

  • Average throughput: ~350 requests/sec
  • Peak memory usage ~700MB

Using the ResponseBuffering middleware:

  • Average throughput: ~360 requests/sec
  • Peak memory usage ~350MB

Again, the results very close, but notice the significantly less memory overhead when using the Response Buffering middleware, so i then tried the same with a 1MB payload...

Throughput tests returning a 1MB JSON payload:
Default configuration (no response buffering):

  • Average throughput: ~61 requests/sec
  • Peak memory usage ~400MB

Using the ResponseBuffering middleware:

  • Average throughput: ~45 requests/sec
  • Peak memory usage ~350MB

With a 1MB payload the default configuration has faster throughput, but the memory overhead is still higher. Obviously a 1MB payload is excessive and the API should implement paging to split into multiple smaller requests, but for the purposes of testing it was worth seeing what the result would be.

Considering the significant issues that the default configuration without Response Buffering causes when errors occur during serialization, my tests show that it is well worth adding Response Buffering as there seems to be no benefit to not using it, only downsides.

Refer to this thread for a description of the issues:
#2285

I did a quick test from a separate machine over the network as a sanity check and the results were not much different, but i plan to do a better test in the future with a more of a production setup.

Update:
I added a test for 10MB payload and updated the results for the 1MB payload after double checking the my figures:

Throughput tests returning a 10MB JSON payload:
Default configuration (no response buffering):

  • Average throughput: ~6 requests/sec
  • Peak memory usage ~450MB

Using the ResponseBuffering middleware:

  • Average throughput: ~6 requests/sec
  • Peak memory usage ~400MB

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions