如何调整在Heroku上运行的Ruby on Rails应用程序,它使用生产级Heroku Postgres?

我工作的公司决定将他们的整个堆栈移动到Heroku。 它的主要动机是易用性:没有sysAdmin,没有哭。 但我仍然有一些问题……

我正在应用程序平台和Postgres服务上进行一些负载和压力测试。 我正在使用blitz作为Heroku的插件。 我用1到250之间的用户数攻击网站。我得到了一些非常有趣的结果,我需要帮助评估它们。

测试堆栈:

应用规格

它没有任何特别的东西。

  • Rails 4.0.4
  • 独角兽
  • database.yml设置为连接到Heroku postgres。
  • 不使用缓存。

数据库

这是一个标准天狗 (Heroku的命名惯例会杀了我一天:)正确连接到应用程序。

Heroku配置

我在unicorn.rb应用了所有内容,如“ 使用Unicorn部署Rails应用程序 ”一文中所述。 我有2个常规的网络动态。

 WEB_CONCURRENCY : 2 DB_POOL : 5 

数据

  • episodes表数100.000~
  • episode_urls表计数300.000~
  • episode_images表计数episode_images ~

episodes_controller.rb

  def index @episodes = Episode.joins(:program).where(programs: {channel_id: 1}).limit(100).includes(:episode_image, :episode_urls) end 

episodes/index.html.erb

   
  • 场景#1:

     Web dynos : 2 Duration : 30 seconds Timeout : 8000 ms Start users : 10 End users : 10 

    结果:

     HITS 100.00% (484) ERRORS 0.00% (0) TIMEOUTS 0.00% (0) 

    这次抢购在30.00秒内成功点击218次,我们将6.04 MB数据传入和传出您的应用。 平均命中率为7.27 /秒,相当于每天约627,840次点击。

    场景#2:

     Web dynos : 2 Duration : 30 seconds Timeout : 8000 ms Start users : 20 End users : 20 

    结果:

     HITS 100.00% (484) ERRORS 0.00% (0) TIMEOUTS 0.00% (0) 

    这次热潮在30.00秒内成功点击365次,我们将10.12 MB的数据传入和传出您的应用。 平均命中率为12.17 /秒,相当于每天约1,051,200次点击。 平均响应时间为622毫秒。

    场景#3:

     Web dynos : 2 Duration : 30 seconds Timeout : 8000 ms Start users : 50 End users : 50 

    结果:

     HITS 100.00% (484) ERRORS 0.00% (0) TIMEOUTS 0.00% (0) 

    这次热潮在30.00秒内成功点击371次,我们将10.29 MB的数据传入和传出您的应用。 平均命中率为12.37 /秒,相当于每天约1,068,480次点击。 平均响应时间为2,631毫秒。

    场景#4:

     Web dynos : 4 Duration : 30 seconds Timeout : 8000 ms Start users : 50 End users : 50 

    结果:

     HITS 100.00% (484) ERRORS 0.00% (0) TIMEOUTS 0.00% (0) 

    这次抢购在30.00秒内成功点击484次,我们将13.43 MB的数据传入和传出您的应用。 平均命中率为16.13 /秒,相当于每天约1,393,920次点击。 平均响应时间为1,856毫秒。

    场景#5:

     Web dynos : 4 Duration : 30 seconds Timeout : 8000 ms Start users : 150 End users : 150 

    结果:

     HITS 71.22% (386) ERRORS 0.00% (0) TIMEOUTS 28.78% (156) 

    这次热潮在30.00秒内成功点击386次,我们将10.76 MB的数据传入和传出您的应用。 平均命中率12.87 /秒转换为大约1,111,680次点击/天。 平均响应时间为5,446毫秒。

    场景#6:

     Web dynos : 10 Duration : 30 seconds Timeout : 8000 ms Start users : 150 End users : 150 

    结果:

     HITS 73.79% (428) ERRORS 0.17% (1) TIMEOUTS 26.03% (151) 

    这次热潮在30.00秒内成功点击428次,我们将11.92 MB的数据传入和传出您的应用。 平均命中率为14.27 /秒,相当于每天约1,232,640次点击。 平均响应时间为4,793毫秒。 但是你遇到了更大的问题:26.21%的用户在这次抢注期间遇到了超时或错误!

    总结:

    • 即使150个用户向应用程序发送请求,“命中率”也不会超过15。
    • 越来越多的web dynos无助于处理请求。

    问题:

    1. 当我使用缓存和memcached(来自Heroku的Memcachier插件)时,即使是2个web dynos也可以处理每秒180次点击。 我只是想了解dynos和postgres服务可以在没有缓存的情况下做什么。 这样我就试着理解如何调整它们。 怎么做?

    2. 据说标准Tengu有200个并发连接。 那为什么它永远不会达到这个数字?

    3. 如果拥有prdouction level db和增加web dynos将无法扩展我的应用程序,那么使用Heroku有什么意义呢?

    4. 可能是最重要的问题:我做错了什么? 🙂

    感谢您阅读这个疯狂的问题!

    我特别想出了这个问题。

    首先,请记住我在视图中的代码:

     <% @episodes.each do |t| %> <% if !t.episode_image.blank? %> 
  • <%= image_tag(t.episode_image.image(:thumb)) %>
  • <% end %>
  • <%= t.episode_urls.first.mas_path if !t.episode_urls.first.blank?%>
  • <%= t.title %>
  • <% end %>

    在这里,我在我的迭代中获得每集剧集episode_image 。 即使我一直在我的控制器中使用includes ,我的表模式也有一个很大的错误。 我的episode_images表中没有episode_id索引! 。 这导致了极高的查询时间。 我发现它使用New Relic的数据库报告。 所有其他查询时间均为0.5毫秒或2-3毫秒,但episode.episode_image导致了近6500毫秒!

    我不太了解查询时间和应用程序执行之间的关系,但是当我在episode_images表中添加索引时,现在我可以清楚地看到差异。 如果您的数据库架构正确,那么通过Heroku进行扩展可能不会遇到任何问题。 但任何dyno都无法帮助你设计一个设计糟糕的数据库。

    对于可能遇到同样问题的人,我想告诉你一些关于Heroku web dynos,Unicorn worker和Postgresql活动连接之间关系的调查结果:

    基本上,Heroku为您提供了一个dyno,这是一种具有1个核心和512MB RAM的小型虚拟机。 在这个小虚拟机中,你的Unicorn服务器运行。 Unicorn有一个主进程和工作进程。 你的每个Unicorn工作者都有自己与你现有的Postgresql服务器的永久连接(不要忘记查看这个 )这基本上意味着当你有一个Heroku dyno与3个Unicorn工作者在其上运行时,你至少有4个活跃连接。 如果您有2个网络动态,则至少有8个活动连接。

    假设你有一个标准T​​engu Postgres,有200个并发连接限制。 如果你有糟糕的数据库设计有问题的查询,数据库也不能更多dynos可以节省你没有缓存…如果你有长时间运行的查询,除了缓存你别无选择,我想。

    以上都是我自己的发现,如果有任何问题请通过您的意见警告我。