• 2-3 события в секунду на юзера • Более 100 http-запросов в минуту на юзера • Более 5 000 000 чатов • Более 45 000 000 сообщений воскресенье, 16 декабря 12 г.
логики Faye (http://faye.jcoglan.com/) Pub/sub Нет серверной логики Socket.io (http://socket.io/) Абстракция над WebSocket, Flash и Polling Произвольная серверная логика воскресенье, 16 декабря 12 г.
код • Нет разделяемого состояния, структуры данных неизменяемы - concurrency проще • Иерархия супервизоров - высокая устойчивость • Прозрачная распределенность • Бесшовный деплой воскресенье, 16 декабря 12 г.
= Time.now.to_i timeout = now + 60 unless redis.setnx("lock", timeout) # Lock is active return if now <= redis.get("lock").to_i # Lock is not expired return if now <= redis.getset("lock", timeout).to_i end # do task actions 11 redis.del "lock" end воскресенье, 16 декабря 12 г.
|t| t.references 'source' t.references 'destination' t.string 'body' t.timestamp 'created_at' t.timestamp 'read_at' end # History of messages received from given user SELECT * FROM messages WHERE destination_id = ? AND source_id = ? ORDER BY created_at DESC LIMIT 10 # Unread messages of user SELECT * FROM messages WHERE destination_id = ? AND read_at IS NULL ORDER BY created_at DESC LIMIT 10 воскресенье, 16 декабря 12 г.
add_index 'messages', ['source_id', 'destination_id'] # Unread messages of user add_index 'messages', ['destination_id'] Limit -> Sort Sort Key: created_at Sort Method: top-N heapsort Memory: 25kB -> Index Scan using messages_between_users on messages Index Cond: ((source_id = ?) AND (destination_id = ?)) Total runtime: 6.451 ms Limit -> Sort Sort Key: created_at Sort Method: quicksort Memory: 26kB -> Bitmap Heap Scan on messages Recheck Cond: (destination_id = ?) Filter: (read_at IS NULL) -> Bitmap Index Scan on messages_unread Index Cond: (destination_id = ?) Total runtime: 123.983 ms воскресенье, 16 декабря 12 г.
add_index 'messages', ['source_id', 'destination_id', 'created_at'], :order => { 'created_at' => 'desc' } # Unread messages of user add_index 'messages', ['destination_id', 'created_at'], :order => { 'created_at' => 'desc' },:where => 'read_at IS NULL' Limit -> Index Scan using messages_between_users on messages Index Cond: ((source_id = ?) AND (destination_id = ?)) Total runtime: 0.209 ms Limit -> Index Scan using messages_unread on messages Index Cond: (destination_id = ?) Total runtime: 0.183 ms воскресенье, 16 декабря 12 г.
AND flag13) Total runtime: 799.959 ms Hstore: Bitmap Heap Scan on users_hstore Recheck Cond: (flags @> '2=>y, 7=>y, 13=>y'::hstore) -> Bitmap Index Scan on users_hstore_flags Index Cond: (flags @> '2=>y, 7=>y, 13=>y'::hstore) Total runtime: 350.778 ms Массив: Bitmap Heap Scan on users_array Recheck Cond: (flags @> '{2,7,13}'::integer[]) -> Bitmap Index Scan on users_array_flags Index Cond: (flags @> '{2,7,13}'::integer[]) Total runtime: 48.118 ms воскресенье, 16 декабря 12 г.
Кэшируем идентификаторы в Redis id = redis.lpop(cache_key) # Get next value from cache unless id # No cached value ids = connection.select_values some_heavy_scope.select('id').to_sql id = ids.shift redis.multi do |r| ids.each{ |id| r.rpush cache_key, id } r.expire cache_key, 7200 # Expire cache after 2 hours end end воскресенье, 16 декабря 12 г.
на 5 мегабайт • Первым делом уменьшайте размер входящих изображений • CarrierWave лучше отделён от модели, чем Paperclip, обратно совместим воскресенье, 16 декабря 12 г.
файла, использует память отдельного процесса, не поддерживает создание изображений • GraphicsMagick — форк ImageMagick, ориентированный на стабильность и производительность • Прирост в скорости до 2-3 раз, но это не серебрянная пуля: меньше фич, иногда производительность страдает воскресенье, 16 декабря 12 г.
• Бинарный, за счет чего выше скорость передачи и footprint воркеров • github.com/raykrueger/ruby-smpp – реализация для EventMachine воскресенье, 16 декабря 12 г.
сессии • Отдельный поток с EM, обслуживающий все соединения • Socket.io поверх em-websocket-client • Очередь входящих сообщений s = open_session_with_chat # Delegates to ActionDispatch::Integration::Session s.post "/users/sign_in", email: '[email protected]', pass: '12345' # Wait for a message (with timeout) s.receive(:connect).should be # Send message s.send_event :contact_message, contact_id, text: "Hi!" воскресенье, 16 декабря 12 г.
em-websocket-client • Набор "шаблонов поведения" class Caller < Wannafun::Actor behave :get_matrix behave :accept_calls behave :call_to_users behave :talk_in_calls end EventMachine.run do Wannafun::ActorSet.new(Caller, options).start! end воскресенье, 16 декабря 12 г.
— сложные сценарии и граничные случаи • Обратная связь пользователь - разработчик. Максимум информации собирается автоматически • Echoes.js (github.com/kossnocorp/echoes). На клиенте собираем логи, фильтруем важные и прикладываем к запросу воскресенье, 16 декабря 12 г.