{"action":"created","issue":{"url":"https://api.github.com/repos/thoughtbot/suspenders/issues/630","labels_url":"https://api.github.com/repos/thoughtbot/suspenders/issues/630/labels{/name}","comments_url":"https://api.github.com/repos/thoughtbot/suspenders/issues/630/comments","events_url":"https://api.github.com/repos/thoughtbot/suspenders/issues/630/events","html_url":"https://github.com/thoughtbot/suspenders/pull/630","id":112438191,"number":630,"title":"Reduce number of Puma processes and threads","user":{"login":"jferris","id":7591,"avatar_url":"https://avatars.githubusercontent.com/u/7591?v=3","gravatar_id":"","url":"https://api.github.com/users/jferris","html_url":"https://github.com/jferris","followers_url":"https://api.github.com/users/jferris/followers","following_url":"https://api.github.com/users/jferris/following{/other_user}","gists_url":"https://api.github.com/users/jferris/gists{/gist_id}","starred_url":"https://api.github.com/users/jferris/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jferris/subscriptions","organizations_url":"https://api.github.com/users/jferris/orgs","repos_url":"https://api.github.com/users/jferris/repos","events_url":"https://api.github.com/users/jferris/events{/privacy}","received_events_url":"https://api.github.com/users/jferris/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":1,"created_at":"2015-10-20T19:03:26Z","updated_at":"2015-10-20T19:32:09Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/thoughtbot/suspenders/pulls/630","html_url":"https://github.com/thoughtbot/suspenders/pull/630","diff_url":"https://github.com/thoughtbot/suspenders/pull/630.diff","patch_url":"https://github.com/thoughtbot/suspenders/pull/630.patch"},"body":"Using a simple Suspenders application, I profiled memory usage for our\ndefault configuration, as well as a few others. I found the following:\n\n* A Puma cluster uses a master process and multiple worker processes.\n  The amount of memory used by a cluster is equal to the memory usage of\n  the master process plus the possible bloated size of a worker process\n  times the number of worker processes.\n* At boot, a simple Suspenders application uses about 117MB for the\n  master process and 109M for each worker.\n* After the first request is served, a process increases to around 117M,\n  like the master process.\n* The amount of potential bloat increases with each thread, because it's\n  possible for every thread to be handling a bloated request at once.\n* Using [siege], I determined that the expected bloat in a simple\n  scenario is around 10M per thread. This will be much worse in some\n  applications.\n\nThis provides the following formula for maximum memory usage under load:\n\n    master_usage + worker_count * (worker_usage + bloat * thread_count)\n\nFor this simple Suspenders application, this formula provides the\nfollowing worst-case usage:\n\n    117 + 3 * (117 + 10 * 5) = 618\n\nThis is over the 512MB limit for a 1x Heroku dyno, and the application\nis very simple.\n\nI recommend changing to a default of two worker processes and two\nthreads per dyno, changing the usage to:\n\n    117 + 2 * (117 + 10 * 2) = 391\n\nThis provides reasonable performance with a high memory ceiling. When\napplications begin to show troublesome performance characteristics under\nload, developers can tune the application's process and thread count\naccording to its real-world memory usage, possibly upgrading the dyno\nsize as appropriate.\n\n[siege]: https://www.joedog.org/siege-home/"},"comment":{"url":"https://api.github.com/repos/thoughtbot/suspenders/issues/comments/149676699","html_url":"https://github.com/thoughtbot/suspenders/pull/630#issuecomment-149676699","issue_url":"https://api.github.com/repos/thoughtbot/suspenders/issues/630","id":149676699,"user":{"login":"tute","id":54260,"avatar_url":"https://avatars.githubusercontent.com/u/54260?v=3","gravatar_id":"","url":"https://api.github.com/users/tute","html_url":"https://github.com/tute","followers_url":"https://api.github.com/users/tute/followers","following_url":"https://api.github.com/users/tute/following{/other_user}","gists_url":"https://api.github.com/users/tute/gists{/gist_id}","starred_url":"https://api.github.com/users/tute/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tute/subscriptions","organizations_url":"https://api.github.com/users/tute/orgs","repos_url":"https://api.github.com/users/tute/repos","events_url":"https://api.github.com/users/tute/events{/privacy}","received_events_url":"https://api.github.com/users/tute/received_events","type":"User","site_admin":false},"created_at":"2015-10-20T19:32:09Z","updated_at":"2015-10-20T19:32:09Z","body":"Does 2 processes and 2 threads mean that we can handle four requests concurrently? How does that compare with 1 process with 4 threads, which would use 274MB?"}}