别了,摩尔定律!华为“韬定律”如何改写全球半导体的未来
2026-05-29
| <?php $logfile = fopen("/var/log/chroot.log", "w"); chroot("/Users/george"); fputs($logfile, "Hello From Inside The Chroot\n"); ?> |
| $pw=posix_getpwnam('nobody'); posix_setuid($pw['uid']); posix_setgid($pw['gid']); |
| $fp=fopen("/tmp/.lockfile","a"); if(!$fp || !flock($fp, LOCK_EX | LOCK_NB)) { fputs(STDERR, "Failed to acquire lock\n"); exit; } /*成功锁定以安全地执行工作*/ |
注意,有关锁机制的讨论涉及较多内容,在此不多加解释。
四. 构建监视服务
在这一节中,我们将使用PHP来编写一个基本的监视引擎。因为你不会事先知道怎样改变,所以你应该使它的实现既灵活又具可能性。
该记录程序应该能够支持任意的服务检查(例如,HTTP和FTP服务)并且能够以任意方式(通过电子邮件,输出到一个日志文件,等等)记录事件。你当然想让它以一个守护程序方式运行;所以,你应该请求它输出其完整的当前状态。
一个服务需要实现下列抽象类:
| abstract class ServiceCheck { const FAILURE = 0; const SUCCESS = 1; protected $timeout = 30; protected $next_attempt; protected $current_status = ServiceCheck::SUCCESS; protected $previous_status = ServiceCheck::SUCCESS; protected $frequency = 30; protected $description; protected $consecutive_failures = 0; protected $status_time; protected $failure_time; protected $loggers = array(); abstract public function __construct($params); public function __call($name, $args) { if(isset($this->$name)) { return $this->$name; } } public function set_next_attempt() { $this->next_attempt = time() + $this->frequency; } public abstract function run(); public function post_run($status) { if($status !== $this->current_status) { $this->previous_status = $this->current_status; } if($status === self::FAILURE) { if( $this->current_status === self::FAILURE ) { $this->consecutive_failures++; } else { $this->failure_time = time(); } } else { $this->consecutive_failures = 0; } $this->status_time = time(); $this->current_status = $status; $this->log_service_event(); } public function log_current_status() { foreach($this->loggers as $logger) { $logger->log_current_status($this); } } private function log_service_event() { foreach($this->loggers as $logger) { $logger->log_service_event($this); } } public function register_logger(ServiceLogger $logger) { $this->loggers[] = $logger; } } |
| interface ServiceLogger { public function log_service_event(ServiceCheck$service); public function log_current_status(ServiceCheck$service); } |
| class ServiceCheckRunner { private $num_children; private $services = array(); private $children = array(); public function _ _construct($conf, $num_children) { $loggers = array(); $this->num_children = $num_children; $conf = simplexml_load_file($conf); foreach($conf->loggers->logger as $logger) { $class = new Reflection_Class("$logger->class"); if($class->isInstantiable()) { $loggers["$logger->id"] = $class->newInstance(); } else { fputs(STDERR, "{$logger->class} cannot be instantiated.\n"); exit; } } foreach($conf->services->service as $service) { $class = new Reflection_Class("$service->class"); if($class->isInstantiable()) { $item = $class->newInstance($service->params); foreach($service->loggers->logger as $logger) { $item->register_logger($loggers["$logger"]); } $this->services[] = $item; } else { fputs(STDERR, "{$service->class} is not instantiable.\n"); exit; } } } private function next_attempt_sort($a, $b){ if($a->next_attempt() == $b->next_attempt()) { return 0; } return ($a->next_attempt() < $b->next_attempt())? -1 : 1; } private function next(){ usort($this->services,array($this,'next_attempt_sort')); return $this->services[0]; } public function loop(){ declare(ticks=1); pcntl_signal(SIGCHLD, array($this, "sig_child")); pcntl_signal(SIGUSR1, array($this, "sig_usr1")); while(1) { $now = time(); if(count($this->children)< $this->num_children) { $service = $this->next(); if($now < $service->next_attempt()) { sleep(1); continue; } $service->set_next_attempt(); if($pid = pcntl_fork()) { $this->children[$pid] = $service; } else { pcntl_alarm($service->timeout()); exit($service->run()); } } } } public function log_current_status(){ foreach($this->services as $service) { $service->log_current_status(); } } private function sig_child($signal){ $status = ServiceCheck::FAILURE; pcntl_signal(SIGCHLD, array($this, "sig_child")); while(($pid = pcntl_wait($status, WNOHANG)) > 0){ $service = $this->children[$pid]; unset($this->children[$pid]); if(pcntl_wifexited($status) && pcntl_wexitstatus($status) ==ServiceCheck::SUCCESS) { $status = ServiceCheck::SUCCESS; } $service->post_run($status); } } private function sig_usr1($signal){ pcntl_signal(SIGUSR1, array($this, "sig_usr1")); $this->log_current_status(); } } |
| class HTTP_ServiceCheck extends ServiceCheck{ public $url; public function _ _construct($params){ foreach($params as $k => $v) { $k = "$k"; $this->$k = "$v"; } } public function run(){ if(is_resource(@fopen($this->url, "r"))) { return ServiceCheck::SUCCESS; } else { return ServiceCheck::FAILURE; } } } |
与你以前构建的框架相比,这个服务极其简单,在此恕不多描述。
五. 示例ServiceLogger进程
下面是一个示例ServiceLogger进程。当一个服务停用时,它负责把一个电子邮件发送给一个待命人员:
| class EmailMe_ServiceLogger implements ServiceLogger { public function log_service_event(ServiceCheck$service) { if($service->current_status ==ServiceCheck::FAILURE) { $message = "Problem with{$service->description()}\r\n"; mail('oncall@example.com', 'Service Event',$message); if($service->consecutive_failures() > 5) { mail('oncall_backup@example.com', 'Service Event', $message); } } } public function log_current_status(ServiceCheck$service){ return; } } |
| class ErrorLog_ServiceLogger implements ServiceLogger { public function log_service_event(ServiceCheck$service) { if($service->current_status() !==$service->previous_status()) { if($service->current_status() ===ServiceCheck::FAILURE) { $status = 'DOWN'; } else { $status = 'UP'; } error_log("{$service->description()} changed status to $status"); } } public function log_current_status(ServiceCheck$service) { error_log("{$service->description()}: $status"); } } |
| <config> <loggers> <logger> <id>errorlog</id> <class>ErrorLog_ServiceLogger</class> </logger> <logger> <id>emailme</id> <class>EmailMe_ServiceLogger</class> </logger> </loggers> <services> <service> <class>HTTP_ServiceCheck</class> <params> <description>OmniTI HTTP Check</description> <url>http://www.omniti.com</url> <timeout>30</timeout> <frequency>900</frequency> </params> <loggers> <logger>errorlog</logger> <logger>emailme</logger> </loggers> </service> <service> <class>HTTP_ServiceCheck</class> <params> <description>Home Page HTTP Check</description> <url>http://www.schlossnagle.org/~george</url> <timeout>30</timeout> <frequency>3600</frequency> </params> <loggers> <logger>errorlog</logger> </loggers> </service> </services> </config> |
| 选项 | 描述 |
| [-f] | 引擎的配置文件的一个位置,默认是monitor.xml。 |
| [-n] | 引擎允许的子进程池的大小,默认是5。 |
| [-d] | 一个停用该引擎的守护功能的标志。在你编写一个把信息输出到stdout或stderr的调试ServiceLogger进程时,这是很有用的。 |
| require_once "Service.inc"; require_once "Console/Getopt.php"; $shortoptions = "n:f:d"; $default_opts = array('n' => 5, 'f' =>'monitor.xml'); $args = getOptions($default_opts, $shortoptions,null); $fp = fopen("/tmp/.lockfile", "a"); if(!$fp || !flock($fp, LOCK_EX | LOCK_NB)) { fputs($stderr, "Failed to acquire lock\n"); exit; } if(!$args['d']) { if(pcntl_fork()) { exit; } posix_setsid(); if(pcntl_fork()) { exit; } } fwrite($fp, getmypid()); fflush($fp); $engine = new ServiceCheckRunner($args['f'],$args['n']); $engine->loop(); |
评论 {{userinfo.comments}}
{{child.content}}



{{question.question}}
提交