2013-05-06

Ruby : Process to Process connection & share objects use EventMachine

hmmm...大概是專案到後面需要...做分散式處理…因為client的預計的量會破5000以上,只用一台伺服器似乎有點找死…所以打算弄成兩層broadcast的方式,也就是Main (N)=> Slave(1024+),這樣就可以有N * 1024+的漂亮數字出來,而前面想辦法用一層的proxy過來即可,類似nginx proxy之類的

然而看了一下Ruby的Socket的Doc…非常難用,自己管起來根本就是想不開的狀態

後來認真的玩了一下EventMachine,包括server和client的部分,以下直接的code demo

server.rb

require 'eventmachine'
require 'pp'

puts 'init server'

Thread.new do
  ##your code like
  while true do
    puts "broadcast_to_client"
    EchoServer.broadcast(["Ser1" , "Ser2" , "Ser3"])
    sleep(3)
  end
end

class EchoServer < EventMachine::Connection
  @@clients = {}

  ##onopen
  def post_init
    @@clients[self.signature] = self
    puts "Add Client : #{self.signature}"
  end

  ##onmessage(msg)
  def receive_data(msg)
    pp get_obj(msg)
    #send_obj(["TEST1" , "TEST2" , "TEST3"])
    #...do something
    #close_connection
  end

  ##onclose
  def unbind
    @@clients.delete(self.signature)

    puts "Remove Client : #{self.signature}"
  end

  ## object <=> string
  def get_obj(msg)
    return Marshal.load(msg)
  end
  def send_obj(obj)
    return send_data(Marshal.dump(obj))
  end

  ##broadcast to client
  def self.broadcast(obj)
    @@clients.each_value do |client|
      client.send_obj(obj)
    end
  end
end

EventMachine.run do
  EventMachine.start_server 'localhost' , 2000 , EchoServer
end

client.rb

require 'eventmachine'
require 'pp'

$echo_client = nil

puts 'init client'

Thread.new do
  ##your code like
  while true do
    puts "send_to_server"
    if $echo_client
      $echo_client.send_obj(["TEST1" , "TEST2" , "TEST3"])
    end
    sleep(3)
  end
end

class EchoClient < EventMachine::Connection
  ##onopen
  def post_init
    $echo_client = self
  end

  ##onmessage(msg)
  def receive_data(msg)
    pp get_obj(msg)
    #send_obj(["TEST1" , "TEST2" , "TEST3"])
    #...do something
  end

  ##onclose
  def unbind
    reconnect 'localhost' , 2000
    post_init
  end

  ## client addon
  def get_obj(msg)
    return Marshal.load(msg)
  end
  def send_obj(obj)
    return send_data(Marshal.dump(obj))
  end
end

EventMachine::run do
  EventMachine::connect('localhost' , 2000 , EchoClient)
end

okay,run server first & multi client is okay

ccc~ 這邊大概demo了一下一般EventMachine的用法,也就是如果你的程式有主流程或是其他控制,而非call-effect的方式,就要另外開Thread來作控制,而Ruby的變數都有做lock,所以就算底層是multi-thread,不過一般用起來應該都是thread safe就是了,而這邊的用法P2P也是ok的就是,你高興也可以開兩個Thread,每個Process都有EM的Client & Server,這就是P2P狀態了

而 Marshal.load(Marshal.dump()) #=> Ruby way deep clone

其實Marshal.dump就是Object.to_s,然後Marshal.load就是String.to_object,就是這簡單的意涵就是,不過傳的物件client和server都要require到,不然會無法重現回來就是…

yoo…分散式完成…不用搞難搞的Socket,可喜可賀可喜可賀X"D

沒有留言:

張貼留言