#19 By: Why not?, February 7th, 2013 03:45
Why does it require so much RAM? I can't figure out a good reason for this software to use anywhere near that much memory. Do you manually cache all the images in RAM without using byte arrays, instead having each pixel be a separate integer object? And if it needs that much for a forum that's two days old, how will it possibly handle a forum with 10,000 users and 100,000 posts?
It would be an interesting exercise to count the heap usage by function and try to figure out exactly which component is using so much. Are there any Ruby tools that do this?
#20 By: Leonardo , February 7th, 2013 06:59
Seconded. Ideally the requirements should be kept to a minimum to ensure a wider adoption. Two flavours, perhaps, or configurable scalability might be considered? I'm guessing there will be lots of instances in which being prepared to receive 10,000 users wouldn't be really necessary.
#21 By: jbn, February 7th, 2013 07:21
@danneu mentioned trying it on Heroku with some progress. Not sure what remained there.
#22 By: TheOnly92, February 7th, 2013 08:35
I have been trying to run this on Heroku, here are the problems I've bumped into so far:
- Redis configuration, had to use ENV["REDISTOGO_URL"].
- Heroku's slug compilation
rake assets:precompile does not work because the environment is not set. <- now here
I'm thinking about compiling assets locally and upload it to Heroku.
#23 By: Dan Neumann, February 7th, 2013 12:07
I'm at work, but tonight I'd like to finish the process of getting this on Heroku or share my progress at the very least. In particular, I've recreated a db/seeds.rb file that may be easier to deal with (and it sets up a complete environment in Heroku included dummy topics, users, an admin user). I didn't even know about seed_fu when I made it.
-
seed_fu not working? Just bypass it. Check out the gem's readme to see what it actually does and manually build the
PostActionTypes yourself in the console or in your own db/seeds.rb file. You can find them in db/fixtures/post_action_types.rb. IIRC those are the necessary seeds to get Discourse into Hello World state.
-
Redis:
heroku addons:add redistogo:nano adds an env var that you can see with $ heroku config | grep REDISTOGO_URL.
I'd like to go back through this process and make a more deliberate step-by-step when I have time.
#24 By: Michael Pell, February 7th, 2013 13:40
@danneu,
Very helpful. Digging into this now.
#25 By: Eric Kidd, February 7th, 2013 13:41
It would be very nice if Discourse's web server component could run comfortably in 512MB of RAM. Scaling a Rails app can often require a lot of web processes. And I've certainly worked some really big and hairy Rails apps that fit in 512MB on Heroku without any problem. The only exceptions turned out involve memory leaks.
I wonder what's going on here. Discourse's server layer is just dealing with JSON, right? It's pulling in a lot of gems, but I doubt that's the problem.
Thank you for documenting the steps you've taken!
(BTW, this is really amazing forum software. I'm seriously impressed.)
#26 By: Michael Pell, February 7th, 2013 14:59
Great News,
Got this running on Heroku!
http://pell-discourse.herokuapp.com/
Culprit line that was stopping me was in connection_management.rb. I commented out the line from Master and made it compatible with Heroku:
def self.current_hostname
# ActiveRecord::Base.connection_pool.spec.config[:host_names].first
ActiveRecord::Base.connection_pool.spec.config[:host]
end
Still can't get seeding to work.
#27 By: Felipe Sabino, February 7th, 2013 17:29
I managed to avoid this issue by using this from heroku labs
https://devcenter.heroku.com/articles/labs-user-env-compile
#28 By: Felipe Sabino, February 7th, 2013 17:35
What if we use redis.yml with
production:
url: <% ENV["REDIS_URL_CONFIG_VAR_NAME"] %>
and change
YAML::load(File.open("#{Rails.root}/config/redis.yml"))
to
YAML::load(ERB.new(File.read("#{Rails.root}/config/redis.yml")).result)
whenever its called?
#29 By: Michael Pell, February 7th, 2013 17:53
That would probably work for not needing to store the host,password, and port in the source. But, the current code never builds the Redis url with a password. I think you'd still have to modify that part of the code. It might not be a problem though: perhaps if the password is left nil then redis ignores it?
#30 By: Dan Neumann, February 7th, 2013 18:04
http://discourse-heroku.herokuapp.com/ (Not guaranteed to be up and running because it's my Discourse playground)
I pulled down master and just did it from scratch:
$ heroku apps:create
$ git push heroku master
$ heroku run rake db:migrate
-
Redis:
-
@michael's patch in vendor/gems/rails_multisite/lib/rails_multisite/connection_management.rb:
def self.current_hostname
ActiveRecord::Base.connection_pool.spec.config[:host]
end
-
Patch to introduce password option in Redis:
-
config/redis.yml (taken from redis://username:{password}@{host}:{port}) in ENV["REDISTOGO_URL"]
production:
<<: *defaults
host: "dory.redistogo.com"
port: 9135
password: "424242424242424242424242"
-
config/application.rb
redis_config = YAML::load(File.open("#{Rails.root}/config/redis.yml"))[Rails.env]
redis_opts = {
host: redis_config["host"],
port: redis_config["port"],
password: redis_config["password"],
namespace: -> { DiscourseRedis.namespace }
}
config.cache_store = :redis_store, redis_opts
-
lib/discourse_redis.rb
def initialize
@config = YAML::load(File.open("#{Rails.root}/config/redis.yml"))[Rails.env]
redis_opts = {
:host => @config['host'],
:port => @config['port'],
:password => @config['password'],
:db => @config['db']}
@redis = Redis.new(redis_opts)
end
# Didn't even look at the code to see if this is necessary
def url
"redis://#{@config['password']}@#{@config['host']}:#{@config['port']}/#{@config['db']}"
end
$ RAILS_ENV=development rake assets:precompile
$ git push heroku
$ heroku run rake db:seed_fu
#31 By: Felipe Sabino, February 7th, 2013 18:09
Looking at redis parameter parsing, I think if we add the url parameter to the redis_config objects used in Redis.new calls, it will work in both cases (if wither the url or the parameters is provided). It seems that it overrides the parameters with the ones from the url.
github.com
def _parse_options(options)
defaults = DEFAULTS.dup
options = options.dup
defaults.keys.each do |key|
# Fill in defaults if needed
if defaults[key].respond_to?(:call)
defaults[key] = defaults[key].call
end
# Symbolize only keys that are needed
options[key] = options[key.to_s] if options.has_key?(key.to_s)
end
url = options[:url] || defaults[:url]
# Override defaults from URL if given
if url
require "uri"
I will have some time later to dig more and check how MiniProfiler, MessaBus and ActiveSupport::Cache::RedisStore handle Redis parameters, if of course they eventually crash the loading from the yml file
#32 By: Dan Neumann, February 7th, 2013 18:29
@felipesabino Yeah, DiscourseRedis should be patched to wrap the rest of Redis' option hash from redis.yml.
#33 By: Michael Pell, February 7th, 2013 19:53
Just issued a pull request for my Deploying to Heroku tutorial. I'm sure it can be improved so I'm looking forward to hearing about it!
https://github.com/discourse/discourse/pull/70
#34 By: Dan Neumann, February 7th, 2013 20:10
Cool stuff.
I'm working on a patch that lets us just set url: <%= ENV["REDISTOGO_URL"] %> in redis.yml and be done with it.
#35 By: Jaime Iniesta, February 7th, 2013 20:16
Thanks!
I'm curious about the redistogo plan that should be needed in production. On your guide you instruct to use the free, nano plan, but on production, how much memory do you think would be needed?
#36 By: Michael Pell, February 7th, 2013 20:17
@danneu,
sounds good. lemme know if I can do anything to help!
@jaimeiniesta
No clue.
#37 By: Dan Neumann, February 7th, 2013 20:46
Discourse specifies one Redis DB for things like the background queue. But it specifies a separate DB for ActiveSupport caching.
It looks like RedisToGo costs 3 figures just to have more than 1 database. So I'd change:
cached_db: 2
to
cached_db: 0 (same as other db)
in Redis.yml so that you're only using one DB. (I haven't checked to see if there are any implications in doing so)
If you ever found yourself needing more Redis space and didn't want to pay for RedisToGo, you could set up a much cheaper Redis instance on another box like an Amazon EC2 instance and just point to it from redis.yml.
#38 By: TheOnly92, February 7th, 2013 22:36
Also due to the low number of maximum connection for the free RedisToGo plan, I occasionally get the maximum connection reached error. I believe you can fix this by limiting the number of connections from sidekiq:
Sidekiq.configure_server do |config|
config.redis = { :url => $redis.url, :namespace => 'sidekiq', :size => 5 }
end
Sidekiq.configure_client do |config|
config.redis = { :url => $redis.url, :namespace => 'sidekiq', :size => 1 }
end
Powered by Discourse, best viewed with JavaScript enabled