SlideShare ist ein Scribd-Unternehmen logo
1 von 81
Downloaden Sie, um offline zu lesen
How	 to	 create	 multiprocess	 server	 	 
on	 windows	 with	 ruby
Rubykaigi	 2016
Ritta Narita
@naritta @narittan
Treasure Data, Inc.
Treasure Data Service Architecture
Treasure Data Service Architecture
As one of solutions for importing data, we use fluentd
Fluentd is an open source data collector for unified logging layer.
For example…
<source>
@type http
port 8000
bind 0.0.0.0
</source>
in_http out_stdout
<match pattern>
@type stdout
</match>
http:8000
in_http → out_stdout
For example…
<source>
@type forward
port 24224
bind 0.0.0.0
</source>
in_forward out_stdout
<match pattern>
@type stdout
</match>
24224
fluent-cat:
send json to the port
in_forward → out_stdout
fluentd uses multiprocess server framework
github.com/fluent/serverengine
ServerEngine
What’s ServerEngine?
A framework to implement robust multiprocess servers like Unicorn
Dynamic reconfig

live restart
Heartbeat via pipe
auto restart
serversupervisor
worker
worker
worker
Auto Restart
Heartbeat via pipe
auto restart
serversupervisor
worker
worker
worker
Heartbeat via pipe
auto restart
serversupervisor
worker
worker
worker
if worker died unexpectedly…
It’s detected by heartbeat and server launch worker again.
Heartbeat via pipe
auto restart
serversupervisor
worker
worker
worker
if worker died unexpectedly…
How to use ServerEngine
1. write server module and worker module
serversupervisor worker
module MyServer
def before_run
@sock = TCPServer.new(
config[:bind],
config[:port])
end
attr_reader :sock
end
module MyWorker
def run
c = server.sock.accept
c.write "work"
end
def stop
c.close
end
end
2. write configuration and run
How to use ServerEngine
serversupervisor worker
se = ServerEngine.create(MyServer, MyWorker, {
daemonize: true,
log: 'myserver.log',
pid_path: 'myserver.pid',
worker_type: 'process',
workers: 4,
bind: '0.0.0.0',
port: 9071,
})
se.run
Worker type
thread
spawnprocess
server worker
server worker
thread
process
Worker type
ServerEngine.create(MyServer, MyWorker, {
worker_type: 'thread'
})
ServerEngine.create(MyServer, MyWorker, {
worker_type: 'process'
})
server worker
spawn
Worker type
module MyWorker
def spawn(process_manager)
process_manager.spawn(env, config[:spawn_cmd])
end
end
ServerEngine.create(MyServer, MyWorker, {
worker_type: 'spawn',
spawn_cmd: cmd
})
in_multiprocess plugin
you have to use multi sockets and assign each ports
port:
24224
port:
24226
port:
24225server
worker
worker
worker
conventional multiprocess model on fluentd
Multiprocess model with ServerEngine
port:
24224
using Socket Manager, share one listening socket
→can use multicore without any assignment
port:
24224
port:
24224
server
worker
socket
manager
server
socket
manager
client
worker
socket
manager
client
worker
socket
manager
client
What differs from other prefork server like unicorn or nginx
Ordinal prefork model
can know which port before fork
only have to pass the socket when fork
server workersocket
In ServerEngine,
For example, in fluentd
Assuming that you can know which port after fork
port information is written in config,
it parses config in worker after fork
port
information
server worker
serverengine prefork model
After fork, have to send request from worker firstly,
As a response, send socket to worker
request
socket
server worker
server worker
socket request
socket
manager
server
socket
manager
client
socket socket information
create worker
socket
http
How do you create multiprocess server for windows with ruby?
I’ll introduce ruby function and tips to develop for windows.
server worker
socket request
socket
manager
server
socket
manager
client
socket socket information
create worker
socket
http
To create worker
To create worker
There is no fork in Windows, then I used spawn
executes specified command and return its pid
pid = spawn(RbConfig.ruby, "-e puts 'Hello, world!'")
Process.wait pid
Create Daemon with spawn
serversupervisor
spawn(config[:daemon_cmdline])
serversupervisor
ruby daemon.rb
execute script for daemon from application side
:
ServerEngine::Daemon.run_server(
:
spawn(config[:daemon_cmdline])
Create Daemon with spawn
server worker
socket request
socket
manager
server
socket
manager
client
socket socket
create worker
socket
http
How to send a socket
There is a problem about File descriptor
In unix
it can share file descriptor for other process.
server worker
FD FD
FD
In Windows
FD is independent for processes.
you cannot share file descriptor
server worker
FD FD
FD
Then, How do you send a socket in windows?
process
pid:1000
process
pid:2000
Windows API : WSADuplicatesocket
you can get duplicated socket only for assigned PID
socket
dup socket
for 2000
socket
for 2000
pass
But this API is only for C
Almost all of Windows API is for C.
It’s important to call API from Others.
How do you call this API from Ruby?
1. C extension
The most general way
There is no C extension code in ServerEngine.
If possible, I want to write with only ruby.
void Init_test()
{
VALUE module;
module = rb_define_module("Test");
rb_define_module_function(module, "hello", wrap_hello,
0);
}
2. ffi
Foreign function interface (FFI) for Ruby
require 'ffi'
module MyLib
extend FFI::Library
ffi_lib 'c'
attach_function :puts, [ :string ], :int
end
MyLib.puts 'Hello, World using libc!’
2. ffi
typedef :ulong, :dword
typedef :uintptr_t, :socket
typedef :pointer, :ptr
ffi_lib :ws2_32
attach_function :WSADuplicateSocketA,
[:socket, :dword, :ptr], :int
class WSAPROTOCOL_INFO < FFI::Struct
layout(
:dwServiceFlags1, :dword,
)
end
proto = WinSock::WSAPROTOCOL_INFO.new
WSADuplicateSocketA(sock, pid, proto)
Definition
Use
This will increase gem dependency.
I want to reduce dependency as possible.
2. ffi
3. fiddle
This is built-in library, then you can call without gem dependency
require "fiddle/import"
module M
extend Fiddle::Importer
dlload "libc.so.6","libm.so.6"
extern "int strlen(char*)"
end
p M.strlen('abc') #=> 3
the library to deal with shared library
how to use fiddle
you can just define using extern and c sentence.
extern "int WSADuplicateSocketA(int, DWORD, void *)"
WSADuplicateSocketA(sock.handle, pid, proto)
Definition
Use
how to use fiddle
you can get protocol of duplicated socket
extern "int WSADuplicateSocketA(int, DWORD, void *)"
WSADuplicateSocketA(sock.handle, pid, proto)
Definition
Use
how to use fiddle
extern "int WSADuplicateSocketA(int, DWORD, void *)"
proto = WSAPROTOCOL_INFO.malloc
WSADuplicateSocketA(sock.handle, pid, proto)
Definition
Use
WSAPROTOCOL_INFO = struct([
         "DWORD dwServiceFlags1",
"DWORD dwServiceFlags2”,
・・・
])
proto = WSAPROTOCOL_INFO.malloc
you can use struct
you can get struct pointer by calling malloc
server worker
socket request
socket
manager
server
socket
manager
client
socket socket information
create worker
socket
http
To share this protocol with worker
worker
server
bin = proto.to_ptr.to_s
proto = WSAPROTOCOL_INFO.malloc
proto.to_ptr.ref.ptr[0, size] = bin
send binary
How to share this protocol with worker
protocol → binary
binary → protocol
server worker
socket request
socket
manager
server
socket
manager
client
socket socket information
create worker
socket
http
To create socket from sent information
Get socket from protocol
extern "int WSASocketA(int, int, int, void *, int, DWORD)”
socket = WSASocketA(Socket::AF_INET, Socket::SOCK_STREAM, 0, proto, 0, 1)
Definition
Use
This socket WSASocket is handle
what’s handle?
Handle is like FD, but we can’t duplicate handle like FD.
For UNIX compatibility,
There is function to convert handle to FD in Windows CRT
This handle is C layer
we can’t useTCPServer class
it’s inconvenient!
we have to use ffi for everything
like WSASend or WSAReceive for write or read
I want to deal with socket in ruby layer
Ruby API: rb_w32_wrap_io_handle
It can convert handle to FD
socklist
sock
ioinfo
sock
ioinfo
sock
ioinfo
handle
you can deal with socket in ruby layer
handle
fd(7)
wrap _open_osfhandle(assign FD)
and create io object
rb_w32_wrap_io_handle
Use fiddle to call rb_w32_wrap_io_handle
ruby_dll_paths = File.dirname(ruby_bin_path) + '/*msvcr*ruby*.dll'
ruby_dll_path = Dir.glob(ruby_dll_paths).first
dlload ruby_dll_path
extern "int rb_w32_wrap_io_handle(int, int)"
you can call with loading ruby dll
you can deal with socket in Ruby layer
server worker
socket request
socket
manager
server
socket
manager
client
socket socket information
create worker
socket
http
To send request/response
There is no UDS in windows, then I used drb as first idea
server
worker
worker
drb
drb
drb
socket
method call
method
create socket
socket
send_io
receive_io
This has race condition problem
server
workerA
workerB
drb
drb
drbmethod call
create socket for workerA
socketA
send_io
This has race condition problem
server
workerA
workerB
drb
drb
drb
create socket for workerB
socketA
send_io
method call
socketB
send_io
This has race condition problem
server
workerA
workerB
drb
drb
drb
create socket for workerB
socketB
send_io
socketAcall receive_io
This has race condition problem
server
workerA
workerB
drb
drb
drb
create socket for workerB
socketBcall receive_io
This rarely happens but its impact is significant if it happens.
server
worker
worker
uds
uds
uds
socket
request
Against this problem, I used UDS andTCPServer
Create several UDS for each worker
uds
To send request/result
In Unix, can use Unix domain socket
There is no UDS in windows,
Then I usedTCPServer
for port in 10000..65535
if `netstat -na | find "#{port}"`.length == 0
return port
end
end
Use netstat to find unused port
If there is NamedPipe in ruby, I’ll use it.
server worker
socket request
socket
manager
server
socket
manager
client
socket socket information
create worker
socket
http
Then you can share socket with worker,
it can listen with multiple worker
server worker
socket request
socket
manager
server
socket
manager
client
socket socket information
create worker
socket
http
To deal with http request
There is no read_nonblock in windows.
Used readpartial
read_nonblock
readpartial
with O_NONBLOCK
raise an exception if there is no data
block if there is no data
without O_NONBLOCK
difference between read_nonblock and readpartial
readpartial(n)
read
difference between read and readpartial
read less than 2048 bytes
read less than n bytes
return nil if EOF
raise an exception if EOF
There is no thundering herd problem on Windows?
But I implemented accept mutex at first
As a result of benchmark test,
I found that thundering herd doesn’t occur.
worker
worker
request
accept!
accept!
Accept Mutex
get
mutex
accept
mutex between processes
read and send data
to buffer/output
server socket
get
mutex
accept
read and send data
to buffer/output
deal with post processing
other process can listen while this process is dealing with data
detach
release
mutex
attach
listening socket
to event loop
detach
release
mutex
attach
listening socket
to event loop
worker
worker
rotation in order by accept mutex
Better way using IOCP?
completion port
thread threadthread
socket socketsocket
CreateIoCompletionPort
Using WindowAPI for IOCP(I/O Completion Port),
can implement asynchronous IO in Windows.
Better way using IOCP?
completion port
thread threadthread
socket socketsocket
GetQueued
CompletionStatus
GetQueued
CompletionStatus
listen
accept
create worker thread pool and IOCP manage it
Better way using IOCP?
completion port
thread threadthread
socket socketsocket
GetQueued
CompletionStatus
GetQueued
CompletionStatus
listen
GetQueuedCompletionStatus
accept
Better way using IOCP?
・Create IOCP in Server process and share socket?
CreateIoCompletionPort
server worker
socket socket
・Or create it in only Worker process?
CreateIoCompletionPort
Benchmark result
AWS Microsoft Windows Server 2012 R2 m4.xlarge
RPS IO
conventional
model
1834.01
/sec
385.07
kb/s
new model
(4 workers)
3513.31
/sec
737.66
kb/s
in_http → out_forward
Conclusion
We need to care about some problems using windows API.
There is very helpful and niche function to deal with
the difference between OS in ruby.

Weitere ähnliche Inhalte

Was ist angesagt?

Dependency management with Composer
Dependency management with ComposerDependency management with Composer
Dependency management with Composer
Jason Grimes
 
OpenNebula and SaltStack - OpenNebulaConf 2013
OpenNebula and SaltStack - OpenNebulaConf 2013OpenNebula and SaltStack - OpenNebulaConf 2013
OpenNebula and SaltStack - OpenNebulaConf 2013
databus.pro
 

Was ist angesagt? (20)

Router と WebSocket
Router と WebSocketRouter と WebSocket
Router と WebSocket
 
Ninja Build: Simple Guide for Beginners
Ninja Build: Simple Guide for BeginnersNinja Build: Simple Guide for Beginners
Ninja Build: Simple Guide for Beginners
 
Composer | PHP Dependency Manager
Composer | PHP Dependency ManagerComposer | PHP Dependency Manager
Composer | PHP Dependency Manager
 
PHP Dependency Management with Composer
PHP Dependency Management with ComposerPHP Dependency Management with Composer
PHP Dependency Management with Composer
 
DevOps(4) : Ansible(2) - (MOSG)
DevOps(4) : Ansible(2) - (MOSG)DevOps(4) : Ansible(2) - (MOSG)
DevOps(4) : Ansible(2) - (MOSG)
 
Preparation study of_docker - (MOSG)
Preparation study of_docker  - (MOSG)Preparation study of_docker  - (MOSG)
Preparation study of_docker - (MOSG)
 
Create your own composer package
Create your own composer packageCreate your own composer package
Create your own composer package
 
What is new in Go 1.8
What is new in Go 1.8What is new in Go 1.8
What is new in Go 1.8
 
Test driven infrastructure
Test driven infrastructureTest driven infrastructure
Test driven infrastructure
 
Instruction: dev environment
Instruction: dev environmentInstruction: dev environment
Instruction: dev environment
 
Learn basic ansible using docker
Learn basic ansible using dockerLearn basic ansible using docker
Learn basic ansible using docker
 
Ruby C10K: High Performance Networking - RubyKaigi '09
Ruby C10K: High Performance Networking - RubyKaigi '09Ruby C10K: High Performance Networking - RubyKaigi '09
Ruby C10K: High Performance Networking - RubyKaigi '09
 
Ansible 2.0 - How to use Ansible to automate your applications in AWS.
Ansible 2.0 - How to use Ansible to automate your applications in AWS.Ansible 2.0 - How to use Ansible to automate your applications in AWS.
Ansible 2.0 - How to use Ansible to automate your applications in AWS.
 
meet.php #11 - Huston, we have an airbrake
meet.php #11 - Huston, we have an airbrakemeet.php #11 - Huston, we have an airbrake
meet.php #11 - Huston, we have an airbrake
 
Communication in Python and the C10k problem
Communication in Python and the C10k problemCommunication in Python and the C10k problem
Communication in Python and the C10k problem
 
DevOps(3) : Ansible - (MOSG)
DevOps(3) : Ansible - (MOSG)DevOps(3) : Ansible - (MOSG)
DevOps(3) : Ansible - (MOSG)
 
Dependency management with Composer
Dependency management with ComposerDependency management with Composer
Dependency management with Composer
 
Managing Puppet using MCollective
Managing Puppet using MCollectiveManaging Puppet using MCollective
Managing Puppet using MCollective
 
Treasure Data Summer Internship 2016
Treasure Data Summer Internship 2016Treasure Data Summer Internship 2016
Treasure Data Summer Internship 2016
 
OpenNebula and SaltStack - OpenNebulaConf 2013
OpenNebula and SaltStack - OpenNebulaConf 2013OpenNebula and SaltStack - OpenNebulaConf 2013
OpenNebula and SaltStack - OpenNebulaConf 2013
 

Ähnlich wie How to create multiprocess server on windows with ruby - rubykaigi2016 Ritta Narita-

Why Node.js
Why Node.jsWhy Node.js
Why Node.js
guileen
 
Developing and Deploying PHP with Docker
Developing and Deploying PHP with DockerDeveloping and Deploying PHP with Docker
Developing and Deploying PHP with Docker
Patrick Mizer
 
Tornado Web Server Internals
Tornado Web Server InternalsTornado Web Server Internals
Tornado Web Server Internals
Praveen Gollakota
 

Ähnlich wie How to create multiprocess server on windows with ruby - rubykaigi2016 Ritta Narita- (20)

node.js: Javascript's in your backend
node.js: Javascript's in your backendnode.js: Javascript's in your backend
node.js: Javascript's in your backend
 
Book
BookBook
Book
 
Original slides from Ryan Dahl's NodeJs intro talk
Original slides from Ryan Dahl's NodeJs intro talkOriginal slides from Ryan Dahl's NodeJs intro talk
Original slides from Ryan Dahl's NodeJs intro talk
 
Exploring Async PHP (SF Live Berlin 2019)
Exploring Async PHP (SF Live Berlin 2019)Exploring Async PHP (SF Live Berlin 2019)
Exploring Async PHP (SF Live Berlin 2019)
 
Rails web api 开发
Rails web api 开发Rails web api 开发
Rails web api 开发
 
Introduction to Node.js
Introduction to Node.jsIntroduction to Node.js
Introduction to Node.js
 
NodeJS for Beginner
NodeJS for BeginnerNodeJS for Beginner
NodeJS for Beginner
 
MongoDB World 2018: Tutorial - Got Dibs? Building a Real-Time Bidding App wit...
MongoDB World 2018: Tutorial - Got Dibs? Building a Real-Time Bidding App wit...MongoDB World 2018: Tutorial - Got Dibs? Building a Real-Time Bidding App wit...
MongoDB World 2018: Tutorial - Got Dibs? Building a Real-Time Bidding App wit...
 
Sinatra for REST services
Sinatra for REST servicesSinatra for REST services
Sinatra for REST services
 
Why Nodejs Guilin Shanghai
Why Nodejs Guilin ShanghaiWhy Nodejs Guilin Shanghai
Why Nodejs Guilin Shanghai
 
Why Node.js
Why Node.jsWhy Node.js
Why Node.js
 
An introduction to workflow-based programming with Node-RED
An introduction to workflow-based programming with Node-REDAn introduction to workflow-based programming with Node-RED
An introduction to workflow-based programming with Node-RED
 
Developing and Deploying PHP with Docker
Developing and Deploying PHP with DockerDeveloping and Deploying PHP with Docker
Developing and Deploying PHP with Docker
 
Get your teeth into Plack
Get your teeth into PlackGet your teeth into Plack
Get your teeth into Plack
 
Make your application expressive
Make your application expressiveMake your application expressive
Make your application expressive
 
Proposal
ProposalProposal
Proposal
 
Socket.io (part 1)
Socket.io (part 1)Socket.io (part 1)
Socket.io (part 1)
 
Kioptrix 2014 5
Kioptrix 2014 5Kioptrix 2014 5
Kioptrix 2014 5
 
Tornado Web Server Internals
Tornado Web Server InternalsTornado Web Server Internals
Tornado Web Server Internals
 
From Ruby to Node.js
From Ruby to Node.jsFrom Ruby to Node.js
From Ruby to Node.js
 

Kürzlich hochgeladen

%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
masabamasaba
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
VictorSzoltysek
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
masabamasaba
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
masabamasaba
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
masabamasaba
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Medical / Health Care (+971588192166) Mifepristone and Misoprostol tablets 200mg
 

Kürzlich hochgeladen (20)

%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go Platformless
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 

How to create multiprocess server on windows with ruby - rubykaigi2016 Ritta Narita-

  • 1. How to create multiprocess server on windows with ruby Rubykaigi 2016
  • 3. Treasure Data Service Architecture
  • 4. Treasure Data Service Architecture As one of solutions for importing data, we use fluentd
  • 5. Fluentd is an open source data collector for unified logging layer.
  • 6. For example… <source> @type http port 8000 bind 0.0.0.0 </source> in_http out_stdout <match pattern> @type stdout </match> http:8000
  • 8. For example… <source> @type forward port 24224 bind 0.0.0.0 </source> in_forward out_stdout <match pattern> @type stdout </match> 24224 fluent-cat: send json to the port
  • 10. fluentd uses multiprocess server framework github.com/fluent/serverengine ServerEngine
  • 11. What’s ServerEngine? A framework to implement robust multiprocess servers like Unicorn Dynamic reconfig
 live restart Heartbeat via pipe auto restart serversupervisor worker worker worker
  • 12. Auto Restart Heartbeat via pipe auto restart serversupervisor worker worker worker
  • 13. Heartbeat via pipe auto restart serversupervisor worker worker worker if worker died unexpectedly…
  • 14. It’s detected by heartbeat and server launch worker again. Heartbeat via pipe auto restart serversupervisor worker worker worker if worker died unexpectedly…
  • 15.
  • 16.
  • 17. How to use ServerEngine 1. write server module and worker module serversupervisor worker module MyServer def before_run @sock = TCPServer.new( config[:bind], config[:port]) end attr_reader :sock end module MyWorker def run c = server.sock.accept c.write "work" end def stop c.close end end
  • 18. 2. write configuration and run How to use ServerEngine serversupervisor worker se = ServerEngine.create(MyServer, MyWorker, { daemonize: true, log: 'myserver.log', pid_path: 'myserver.pid', worker_type: 'process', workers: 4, bind: '0.0.0.0', port: 9071, }) se.run
  • 20. server worker server worker thread process Worker type ServerEngine.create(MyServer, MyWorker, { worker_type: 'thread' }) ServerEngine.create(MyServer, MyWorker, { worker_type: 'process' })
  • 21. server worker spawn Worker type module MyWorker def spawn(process_manager) process_manager.spawn(env, config[:spawn_cmd]) end end ServerEngine.create(MyServer, MyWorker, { worker_type: 'spawn', spawn_cmd: cmd })
  • 22. in_multiprocess plugin you have to use multi sockets and assign each ports port: 24224 port: 24226 port: 24225server worker worker worker conventional multiprocess model on fluentd
  • 23. Multiprocess model with ServerEngine port: 24224 using Socket Manager, share one listening socket →can use multicore without any assignment port: 24224 port: 24224 server worker socket manager server socket manager client worker socket manager client worker socket manager client
  • 24. What differs from other prefork server like unicorn or nginx
  • 25. Ordinal prefork model can know which port before fork only have to pass the socket when fork server workersocket
  • 26. In ServerEngine, For example, in fluentd Assuming that you can know which port after fork port information is written in config, it parses config in worker after fork port information server worker
  • 27. serverengine prefork model After fork, have to send request from worker firstly, As a response, send socket to worker request socket server worker
  • 28. server worker socket request socket manager server socket manager client socket socket information create worker socket http How do you create multiprocess server for windows with ruby? I’ll introduce ruby function and tips to develop for windows.
  • 29. server worker socket request socket manager server socket manager client socket socket information create worker socket http To create worker
  • 30. To create worker There is no fork in Windows, then I used spawn executes specified command and return its pid pid = spawn(RbConfig.ruby, "-e puts 'Hello, world!'") Process.wait pid
  • 31. Create Daemon with spawn serversupervisor spawn(config[:daemon_cmdline])
  • 32. serversupervisor ruby daemon.rb execute script for daemon from application side : ServerEngine::Daemon.run_server( : spawn(config[:daemon_cmdline]) Create Daemon with spawn
  • 33. server worker socket request socket manager server socket manager client socket socket create worker socket http How to send a socket
  • 34. There is a problem about File descriptor
  • 35. In unix it can share file descriptor for other process. server worker FD FD FD
  • 36. In Windows FD is independent for processes. you cannot share file descriptor server worker FD FD FD
  • 37. Then, How do you send a socket in windows?
  • 38. process pid:1000 process pid:2000 Windows API : WSADuplicatesocket you can get duplicated socket only for assigned PID socket dup socket for 2000 socket for 2000 pass
  • 39. But this API is only for C Almost all of Windows API is for C. It’s important to call API from Others.
  • 40. How do you call this API from Ruby?
  • 41. 1. C extension The most general way There is no C extension code in ServerEngine. If possible, I want to write with only ruby. void Init_test() { VALUE module; module = rb_define_module("Test"); rb_define_module_function(module, "hello", wrap_hello, 0); }
  • 42. 2. ffi Foreign function interface (FFI) for Ruby require 'ffi' module MyLib extend FFI::Library ffi_lib 'c' attach_function :puts, [ :string ], :int end MyLib.puts 'Hello, World using libc!’
  • 43. 2. ffi typedef :ulong, :dword typedef :uintptr_t, :socket typedef :pointer, :ptr ffi_lib :ws2_32 attach_function :WSADuplicateSocketA, [:socket, :dword, :ptr], :int class WSAPROTOCOL_INFO < FFI::Struct layout( :dwServiceFlags1, :dword, ) end proto = WinSock::WSAPROTOCOL_INFO.new WSADuplicateSocketA(sock, pid, proto) Definition Use
  • 44. This will increase gem dependency. I want to reduce dependency as possible. 2. ffi
  • 45. 3. fiddle This is built-in library, then you can call without gem dependency require "fiddle/import" module M extend Fiddle::Importer dlload "libc.so.6","libm.so.6" extern "int strlen(char*)" end p M.strlen('abc') #=> 3 the library to deal with shared library
  • 46. how to use fiddle you can just define using extern and c sentence. extern "int WSADuplicateSocketA(int, DWORD, void *)" WSADuplicateSocketA(sock.handle, pid, proto) Definition Use
  • 47. how to use fiddle you can get protocol of duplicated socket extern "int WSADuplicateSocketA(int, DWORD, void *)" WSADuplicateSocketA(sock.handle, pid, proto) Definition Use
  • 48. how to use fiddle extern "int WSADuplicateSocketA(int, DWORD, void *)" proto = WSAPROTOCOL_INFO.malloc WSADuplicateSocketA(sock.handle, pid, proto) Definition Use
  • 49. WSAPROTOCOL_INFO = struct([          "DWORD dwServiceFlags1", "DWORD dwServiceFlags2”, ・・・ ]) proto = WSAPROTOCOL_INFO.malloc you can use struct you can get struct pointer by calling malloc
  • 50. server worker socket request socket manager server socket manager client socket socket information create worker socket http To share this protocol with worker
  • 51. worker server bin = proto.to_ptr.to_s proto = WSAPROTOCOL_INFO.malloc proto.to_ptr.ref.ptr[0, size] = bin send binary How to share this protocol with worker protocol → binary binary → protocol
  • 52. server worker socket request socket manager server socket manager client socket socket information create worker socket http To create socket from sent information
  • 53. Get socket from protocol extern "int WSASocketA(int, int, int, void *, int, DWORD)” socket = WSASocketA(Socket::AF_INET, Socket::SOCK_STREAM, 0, proto, 0, 1) Definition Use
  • 54. This socket WSASocket is handle what’s handle? Handle is like FD, but we can’t duplicate handle like FD. For UNIX compatibility, There is function to convert handle to FD in Windows CRT
  • 55. This handle is C layer we can’t useTCPServer class it’s inconvenient! we have to use ffi for everything like WSASend or WSAReceive for write or read I want to deal with socket in ruby layer
  • 56. Ruby API: rb_w32_wrap_io_handle It can convert handle to FD socklist sock ioinfo sock ioinfo sock ioinfo handle you can deal with socket in ruby layer handle fd(7) wrap _open_osfhandle(assign FD) and create io object rb_w32_wrap_io_handle
  • 57. Use fiddle to call rb_w32_wrap_io_handle ruby_dll_paths = File.dirname(ruby_bin_path) + '/*msvcr*ruby*.dll' ruby_dll_path = Dir.glob(ruby_dll_paths).first dlload ruby_dll_path extern "int rb_w32_wrap_io_handle(int, int)" you can call with loading ruby dll
  • 58. you can deal with socket in Ruby layer
  • 59. server worker socket request socket manager server socket manager client socket socket information create worker socket http To send request/response
  • 60. There is no UDS in windows, then I used drb as first idea server worker worker drb drb drb socket method call method create socket socket send_io receive_io
  • 61. This has race condition problem server workerA workerB drb drb drbmethod call create socket for workerA socketA send_io
  • 62. This has race condition problem server workerA workerB drb drb drb create socket for workerB socketA send_io method call socketB send_io
  • 63. This has race condition problem server workerA workerB drb drb drb create socket for workerB socketB send_io socketAcall receive_io
  • 64. This has race condition problem server workerA workerB drb drb drb create socket for workerB socketBcall receive_io This rarely happens but its impact is significant if it happens.
  • 65. server worker worker uds uds uds socket request Against this problem, I used UDS andTCPServer Create several UDS for each worker uds
  • 66. To send request/result In Unix, can use Unix domain socket There is no UDS in windows, Then I usedTCPServer for port in 10000..65535 if `netstat -na | find "#{port}"`.length == 0 return port end end Use netstat to find unused port If there is NamedPipe in ruby, I’ll use it.
  • 67. server worker socket request socket manager server socket manager client socket socket information create worker socket http Then you can share socket with worker, it can listen with multiple worker
  • 68. server worker socket request socket manager server socket manager client socket socket information create worker socket http To deal with http request
  • 69. There is no read_nonblock in windows. Used readpartial
  • 70. read_nonblock readpartial with O_NONBLOCK raise an exception if there is no data block if there is no data without O_NONBLOCK difference between read_nonblock and readpartial
  • 71. readpartial(n) read difference between read and readpartial read less than 2048 bytes read less than n bytes return nil if EOF raise an exception if EOF
  • 72. There is no thundering herd problem on Windows? But I implemented accept mutex at first As a result of benchmark test, I found that thundering herd doesn’t occur. worker worker request accept! accept!
  • 73. Accept Mutex get mutex accept mutex between processes read and send data to buffer/output server socket get mutex accept read and send data to buffer/output deal with post processing other process can listen while this process is dealing with data detach release mutex attach listening socket to event loop detach release mutex attach listening socket to event loop worker worker
  • 74. rotation in order by accept mutex
  • 75. Better way using IOCP? completion port thread threadthread socket socketsocket CreateIoCompletionPort Using WindowAPI for IOCP(I/O Completion Port), can implement asynchronous IO in Windows.
  • 76. Better way using IOCP? completion port thread threadthread socket socketsocket GetQueued CompletionStatus GetQueued CompletionStatus listen accept create worker thread pool and IOCP manage it
  • 77. Better way using IOCP? completion port thread threadthread socket socketsocket GetQueued CompletionStatus GetQueued CompletionStatus listen GetQueuedCompletionStatus accept
  • 78. Better way using IOCP? ・Create IOCP in Server process and share socket? CreateIoCompletionPort server worker socket socket ・Or create it in only Worker process? CreateIoCompletionPort
  • 79.
  • 80. Benchmark result AWS Microsoft Windows Server 2012 R2 m4.xlarge RPS IO conventional model 1834.01 /sec 385.07 kb/s new model (4 workers) 3513.31 /sec 737.66 kb/s in_http → out_forward
  • 81. Conclusion We need to care about some problems using windows API. There is very helpful and niche function to deal with the difference between OS in ruby.