MogileFS启动流程

MogileFS启动流程实例化MogileFS::Server并运行my $server; # server singletonsub server {my ($pkg) = @_;return $server ||= bless {}, $pkg;#空就创建对象,有就返回,单例}$server->run();读取配置

优先级,命令行>配置文件>默认配置

MogileFS::Config->load_config;获得数据库操作句柄

MogileFS::Store是数据库操作的基类,实际返回的对象是MogileFS::Store::MySQL

MogileFS::Config->check_database;my $sto = eval { Mgd::get_store() };sub get_store {return $store = MogileFS::Store->new;}$sto->ping;sub ping {my $self = shift;return $self->dbh->ping;}$self->{dbh} = DBI->connect($self->{dsn}, $self->{user}, $self->{pass}设置fidid fidid就是数据库中fid的最大值,但对这次启动来说是最小值my $min_fidid = $sto->max_fidid;sub max_fidid {my $self = shift;return $self->dbh->selectrow_array("SELECT MAX(fid) FROM file");}设置为守护进程 MogileFS::Util->daemonize()

两次fork后成为守护进程

第一次fork后,父进程关闭,子进程成为孤儿进程,init接管

setsid让孤儿进程脱离会话,并成为进程组,脱离终端。

忽略挂起信号

第二次fork后,父进程关闭,子进程成为孤儿进程,init接管,成为守护进程

据说调用第二次fork可以彻底排除取得会话的可能

daemonize() if MogileFS->config("daemonize");sub daemonize {if ($pid = fork) { exit 0; }croak "Cannot detach from controlling terminal"unless $sess_id = POSIX::setsid();$SIG{‘HUP’} = ‘IGNORE’;if ($pid = fork) { exit 0; }chdir "/";umask 0;}设置进程信号处理

程序自己中断的信号TERM和外部中断信号INT是类似的,干掉所有子进程,删除PID文件

管道信号忽略,(只有写,没有读的管道,会发出这种信号)

$SIG{TERM} = sub {my @children = MogileFS::ProcManager->child_pids;print STDERR scalar @children, " children to kill.\n" if $DEBUG;my $count = kill( ‘TERM’ => @children );print STDERR "Sent SIGTERM to $count children.\n" if $DEBUG;MogileFS::ProcManager->remove_pidfile;Mgd::log(‘info’, ‘ending run due to SIGTERM’);Sys::Syslog::closelog();exit 0;};$SIG{INT} = sub{同上}$SIG{PIPE} = ‘IGNORE’;创建服务器端socket

Danga::Socket是一个socket事件驱动,处理客户端请求的是MogileFS::Connection::Client

设置%OtherFds

my @servers;foreach my $listen (@{ MogileFS->config(‘listen’) }) {my $server = IO::Socket::INET->new(LocalAddr => $listen,Type=> SOCK_STREAM,Proto=> ‘tcp’,Blocking => 0,Reuse=> 1,#调用Reuse可以免去服务器在终止到重启之间的所停留的时间Listen => 1024 ) #监听队列,其实就是连接数or die "Error creating socket: $@\n";$server->sockopt(SO_KEEPALIVE, 1);# save sub to accept a clientpush @servers, $server;Danga::Socket->AddOtherFds( fileno($server) => sub {while (my $csock = $server->accept) {MogileFS::Connection::Client->new($csock);#也会被加到%DescriptorMap}} );}设置socket事件处理后的回调,并开始循环

MogileFS::ProcManager 进程管理工具

EventLoop = FirstTimeEventLoop; 符号表设置,调用的是FirstTimeEventLoop

MogileFS::ProcManager->push_pre_fork_cleanup(sub {# so children don’t hold server connection open#关闭连接的匿名函数,给子进程用的close($_) foreach @servers;});# setup the post event loop callback to spawn jobs, and the timeoutDanga::Socket->DebugLevel(3);#始终是0Danga::Socket->SetLoopTimeout( 250 ); #事件超时 250 millisecondsDanga::Socket->SetPostLoopCallback(MogileFS::ProcManager->PostEventLoopChecker);#每次事件驱动完成后执行的函数Danga::Socket->EventLoop();Socket轮询器选择

我本机为Poll,以后调用EventLoop就是PollEventLoop了,Poll需要轮询,,

线上应该为Epoll,Epoll内核提供反射模式,无需轮询

Epoll和Poll那种更好,可能取决于活跃的Socket。。。,如果全是活跃的呢

sub FirstTimeEventLoop {my $class = shift;_InitPoller();if ($HaveEpoll) {EpollEventLoop($class);} elsif ($HaveKQueue) {KQueueEventLoop($class);} else {PollEventLoop($class);}}*EventLoop = *PollEventLoop;第一次轮询开始

还记得Danga::Socket->SetPostLoopCallback(MogileFS::ProcManager->PostEventLoopChecker);吗?,第一次轮询直接回调

还记得%OtherFds吗,主进程的socket在里面,%DescriptorMap暂时还没,不过这个散列很重要

my @poll;foreach my $fd ( keys %OtherFds ) {push @poll, $fd, POLLIN;}while ( my ($fd, $sock) = each %DescriptorMap ) {push @poll, $fd, $sock->{event_watch};}my $count = IO::Poll::_poll($timeout, @poll);unless ($count) {return unless PostEventLoop();next;}创建Monitor子进程

创建一副IPC通信一个给父进程,一个给子进程,并切无缓冲

socketpair(my $parents_ipc, my $childs_ipc, AF_UNIX, SOCK_STREAM, PF_UNSPEC )or die( "Sockpair failed" );select((select( $parents_ipc ), $|++)[0]);select((select( $childs_ipc ), $|++)[0]);

父类返回MogileFS::Connection::Worker对象,构造参数是IPC中的一个

MogileFS::Connection::Worker继承Danga::Socket,会增加到$DescriptorMap{$fd} = $self;

所有的胜利,与征服自己的胜利比起来,都是微不足道

MogileFS启动流程

相关文章:

你感兴趣的文章:

标签云: