2015년 9월 8일 화요일

[PHP] 프로그램 중복 실행 방지

crontab 에 스케줄을 등록해 놓고, 반복해서 프로그램을 실행하다 보면
중복 실행이 되지 않게 해 줘야 하는데, 
간단하게 프로그램에서 하는 방법을 설명한다.

예)
 $nExecuteNumber = 9;

 // convert mov => mp4
 $mExistFile = '/home/account/footage_convert_mp4_' . $nExecuteNumber . '.chk';
 if(file_exists( $mExistFile )) {
  exit;
 }

중략
...
        # insert last line, delete file extend "chk".
 shell_exec( sprintf("rm -rf %s", $mExistFile) );


에러가 발생해 중간에서 실행이 멈추는 경우가 발생하면 사용하지 않아야 한다.

이런 경우는 아래

쉘 스크립트를 이용하여 중복 실행을 방지하는 방법은 쉘 스크립트를 이용하여 중복방지를 참조하기 바란다.

앤트맨이란 영화를 보고 나서.

앤트맨이라 영화를 한다기에 별 기대를 하지 않고 봤는데,
(이전에 봤던 앤트맨 이란 영화와 내용을 별 다르지 않을 것으로 봤다.)

이전에 봤던 영화와는 다르게 유머코드도 재법 있고, 어벤져스와 역이는 내용도 다소 흥미있는 내용이였다.
유머를 담당하고 있는 마이클 페나(Michael Pena) 이란 배우가 이전과는 다른 재미있는 케릭터로 나온 것도 재미 있었다.

마벨 유니버스 라인...

다음 개봉하는 시빌 워도 기대가 된다.

걍 추억하기 위해 사진 한 컷. 마이클 더글라스(Michael Douglas) 와 폴 러드(Paul Rudd) 사진 한장.

[shell script]서버간 파일 복사를 위한 scp 사용법

linux 상에서 파일을 복사하는 방법 cp 를 주로 사용하는데,
서버 간에 파일을 복사하려면 scp 라는 명령어를 사용하여 복사를 한다.
예)
root>scp ./*.php 192.168.0.1:/home/account/php/lib/

설명)
"scp"란 명령어를 사용하여 현재 디렉토리에 있는 "php"란 확장자를 가진 파일을 192.168.0.1 이란 서버의 해당 디렉토리에 옮기는 예제이다.
명령어를 실행하면 파일을 복사할 서버의 권한이 있는지 체크하기 위해 "root"의 패스워드를 물어본다.

2015년 9월 6일 일요일

[memcache] 서버구성 (memcached)

memcached 서버구성
http://memcached.org/
 
필요 패키지 설치
[root@localhost ~]# yum install libevent-devel
[root@localhost ~]# tar -zxvf memcached-1.x.x.tar.gz
[root@localhost ~]# cd memcached-1.x.x
[root@localhost ~]# ./configure --with-libevent=/usr/lib64/
[root@localhost ~]# make && make test && make install

[root@localhost ~]# vi /etc/memcached.conf
--------------------------------------------
# run as a daemon
-d
# user to run daemon nobody/apache/www-data
-u nobody
#Memory a usar
-m 512
# default port
-p 11211
#max simultaneous connections
-c 9216
# only listen locally
#-l 127.0.0.1
--------------------------------------------

실행스크립트 및 데몬스크립트
[root@localhost ~]# touch /etc/init.d/memcached
[root@localhost ~]# chmod +x /etc/init.d/memcached
------------------------------------------------------------------------
#!/bin/bash
#
# memcached    This shell script takes care of starting and stopping
#              standalone memcached.
#
# chkconfig: - 80 12
# description: memcached is a high-performance, distributed memory
#              object caching system, generic in nature, but
#              intended for use in speeding up dynamic web
#              applications by alleviating database load.
# processname: memcached
# config: /etc/memcached.conf
# Source function library.
. /etc/rc.d/init.d/functions
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/local/bin/memcached
DAEMONBOOTSTRAP=/usr/local/bin/start-memcached
DAEMONCONF=/etc/memcached.conf
NAME=memcached
DESC=memcached
PIDFILE=/var/run/$NAME.pid
[ -x $DAEMON ] || exit 0
[ -x $DAEMONBOOTSTRAP ] || exit 0
RETVAL=0
start() {
        echo -n $"Starting $DESC: "
        daemon $DAEMONBOOTSTRAP $DAEMONCONF
        RETVAL=$?
        [ $RETVAL -eq 0 ] && touch $PIDFILE
        echo
        return $RETVAL
        }
stop() {
        echo -n $"Shutting down $DESC: "
        killproc $NAME
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ] && rm -f $PIDFILE
        return $RETVAL
        }
# See how we were called.
case "$1" in
        start)
                start
                ;;
        stop)
                stop
                ;;
        restart|reload)
                stop
                start
                RETVAL=$?
                ;;
        status)
                status $prog
                RETVAL=$?
                ;;
        *)
                echo $"Usage: $0 {start|stop|restart|status}"
                exit 1
esac
exit $RETVAL
------------------------------------------------------------------------
 
[root@localhost ~]# touch /usr/local/bin/start-memcached
[root@localhost ~]# chmod +x  /usr/local/bin/start-memcached
------------------------------------------------------------------------------ 
#!/usr/bin/perl -w
# start-memcached
# 2003/2004 - Jay Bonci 
# This script handles the parsing of the /etc/memcached.conf file
# and was originally created for the Debian distribution.
# Anyone may use this little script under the same terms as
# memcached itself.
use strict;
if ($> != 0 and $< != 0) {
 print STDERR "Only root wants to run start-memcached.\n";
 exit;
}
my $etcfile = shift || "/etc/memcached.conf";
my $params = [];
my $etchandle; 
# This script assumes that memcached is located at /usr/bin/memcached, and
# that the pidfile is writable at /var/run/memcached.pid
my $memcached = "/usr/local/bin/memcached";
my $pidfile = "/var/run/memcached.pid";
# If we don't get a valid logfile parameter in the /etc/memcached.conf file,
# we'll just throw away all of our in-daemon output. We need to re-tie it so
# that non-bash shells will not hang on logout. Thanks to Michael Renner for 
# the tip
my $fd_reopened = "/dev/null";
sub handle_logfile {
 my ($logfile) = @_;
 $fd_reopened = $logfile;
}
sub reopen_logfile {
 my ($logfile) = @_;
 open *STDERR, ">>$logfile";
 open *STDOUT, ">>$logfile";
 open *STDIN, ">>/dev/null";
 $fd_reopened = $logfile;
}
# This is set up in place here to support other non -[a-z] directives
my $conf_directives = {
 "logfile" => \&handle_logfile
};
if (open $etchandle, $etcfile) {
 foreach my $line (<$etchandle>) {
  $line =~ s/\#.*//go;
  $line = join ' ', split ' ', $line;
  next unless $line;
  next if $line =~ /^\-[dh]/o;
  if ($line =~ /^[^\-]/o) {
   my ($directive, $arg) = $line =~ /^(.*?)\s+(.*)/; 
   $conf_directives->{$directive}->($arg);
   next;
  }
  push @$params, $line;
 }
}
unshift @$params, "-u root" unless (grep $_ eq '-u', @$params);
$params = join " ", @$params;
if (-e $pidfile) {
 open PIDHANDLE, "$pidfile";
 my $localpid = ;
 close PIDHANDLE;
 chomp $localpid;
 if (-d "/proc/$localpid") {
  print STDERR "memcached is already running.\n"; 
  exit;
 } else {
  `rm -f $localpid`;
 }
}
my $pid = fork();
if ($pid == 0) {
 reopen_logfile($fd_reopened);
 exec "$memcached $params";
 exit(0);
} elsif (open PIDHANDLE,">$pidfile") {
 print PIDHANDLE $pid;
 close PIDHANDLE;
} else {
 print STDERR "Can't write pidfile to $pidfile.\n";
}
------------------------------------------------------------------------------
# /etc/init.d/memcached restart
Shutting down memcached:                                   [  OK  ]
Starting memcached:                                        [  OK  ]
데몬 확인

[root@localhost ~]# ps ax | grep memcach
14688 pts/0    Sl     0:00 /usr/local/bin/memcached -u root -u nobody -m 512 -p 11211 -c 9216
 
 
client (web서버)
memcache 모듈 설치
# wget http://pecl.php.net/get/memcache-2.2.4.tgz
# tar xzfv memcache-2.2.4.tgz
# cd memcache-2.2.4
# phpize
# ./configure --enable-memcache
# make 
# make install
# vi /usr/local/apache/conf/php.ini
extension_dir = "/usr/local/lib/php/extensions/no-debug-non-zts-20060613/"
extension=memcache.so
[Session]
; Handler used to store/retrieve data.
;session.save_handler = files
session.save_handler = memcache
session.save_path = "tcp://192.168.0.101:11211"   <--- memcached 서버 IP
 
저장 후 apache restart


2015년 7월 31일 금요일


혹시 video tag를 이용하여 로딩하는데, 첫화면이 뭉게지거나 깨진다면 "canplaythrough" 이벤트 속성에 프로그램을 하면 PC 성능이 않 좋을수록 기다리는 시간은 오래 걸리지만, 좀 더 나은 결과를 얻을 수 있다. (maybe can not load first shot, you can use "canplaythrough" instead "canplay" in video tag.)
$(document).ready(function() {
 document.body.focus();

 $("#jquery_jplayer_1").jPlayer({
  ready: function () {
   $(this).jPlayer("setMedia", {
    title: "제목",
    m4v: mMpegSrc,
    poster: "/images/footage/video_error.jpg"
   });
  },
  canplaythrough: function() {
   
   $("#jquery_jplayer_1").jPlayer("play");

   $.wait( function(){ 
     
     if(mTimes == 1) {
      $("#jquery_jplayer_1").jPlayer("stop");
      $("#jquery_jplayer_1").jPlayer("play"); 

      mTimes = 0;
     }
      }, 80
   );

   /*
   $("#jquery_jplayer_1").jPlayer("stop");
   setTimeout(function () {
    $("#jquery_jplayer_1").jPlayer("play");
    }, 500);
   */
  },
  swfPath: '/js/plugin/jquery.jPlayer',
  preload: "auto",
  supplied: "m4v",
  size: {
   width: "640px",
   height: "360px",
   cssClass: "jp-video-360p"
  },
  smoothPlayBar: true,
  keyEnabled: true,
  remainingDuration: true,
  toggleDuration: true,
 });

 $.wait = function( callback, seconds){
    return window.setTimeout( callback, seconds);
 }
});

참조 (below from) : http://cafe.naver
나만의 콘트를, 첫 시작을 위한 몇 가지 마크업과 스타일
콘트롤의 세가지 구성요소 :
-재생/정지 버튼
-0부터 증가하는 타이머
-음소거/음소거 해제 버튼

재생/정지와 음소거/음소거 해제 버튼의 텍스트는 text-indent속성을 이용해 화면에서 제거된다.
하나의 CSS 스프라이트 이미지가 이처럼 다양한 버튼의 상태(재생,정지,음소거,음소거 해제)를 표시하기 위한배경 이미지로 이용된다.
CSS클래스는 서로 다른 상태를 나타내는 데 사용된다. 이러한 클래스는 자바스크립트를 이용해 추가되거나 삭제
컨트롤 래퍼 요소에는 절대위치absolute를 사용하고 비디오의 하단을 덮도록 배치
컨트롤의 기본 불투명도를 50%로 설정하지만 마우스를 위에 올리면 불투명도는 100%로 증가
기본값으로 컨트롤의 래퍼요소는 hidden이라는 class로서, disply:none으로 설정되고 이것은 자바스크립트에 의해 제거된다.
미디어요소 API소개
var videoE1 = $('video')[0],
playPauseBtn = $('#playPause'),
vidControls = $('#controls'),
muteBtn =$("muteUnmute'),
timeHolder =$('#timer');

1.콘트롤 속성 제거
videoE1.removeAttribute("controls"); //ie9이하 지원안함

2.콘트롤 속성 보이게
videoE1.addEventListener('canplaythrought',function() {
vidControls.removeClass("hidden");
}, false);


비디오재생과 중지
canplaythrought 이벤트가 발생하면 콜백 함수가 작동한다.


비디오의 오디오 트랙에 대한 음소거및 음소거 해제

비디오 재생이 끝났을 때의 반응

비디오 재생에 따른 시간 업데이트

미디어 요소 API의 추가적인 기능

-이벤트
-속성

오디오는 어떤가?



접근가능한 미디어



http://w3schools.com/html5/html5_ref_av_dom.asp

HTML5 Audio/Video Methods

MethodDescription
addTextTrack()Adds a new text track to the audio/video
canPlayType()Checks if the browser can play the specified audio/video type
load()Re-loads the audio/video element
play()Starts playing the audio/video
pause()Pauses the currently playing audio/video

HTML5 Audio/Video Properties

PropertyDescription
audioTracksReturns a MultipleTrackList object representing available audio tracks
autoplaySets or returns if the audio/video should start playing as soon as its loaded
bufferedReturns a TimeRanges object representing the buffered parts of the audio/video
controllerReturns the MediaController object representing the current media controller of the audio/video
controlsSets or returns if the audio/video should display controls (like play/pause etc.)
crossOriginSets or returns the CORS settings of the audio/video
currentSrcReturns the URL of the current audio/video
currentTimeSets or returns the current playback position in the audio/video (in seconds)
defaultMutedSets or returns if the audio/video is muted by default
defaultPlaybackRateSets or returns the default speed of the audio/video playback
durationReturns the duration of the current audio/video (in seconds)
endedReturns if the playback of the audio/video has ended or not
errorReturns a MediaError object representing the error state of the audio/video
initialTimeReturns the initial play position of the audio/video
loopSets or returns if the audio/video should start over again when finished
mediaGroupSets or returns a the group the audio/video belongs to (used to link multiple audio/video elements)
mutedSets or returns if the audio/video is muted or not
networkStateReturns the current network state of the audio/video
pausedSets or returns if the audio/video is paused or not
playbackRateSets or returns the speed of the audio/video playback
playedReturns a TimeRanges object representing the already played parts of the audio/video
preloadSets or returns if the audio/video should be loaded when the page loads
readyStateReturns the current ready state of the audio/video
seekableReturns a TimeRanges object representing the seekable parts of the audio/video
seekingReturns if the user is currently moving/skipping to a new position in the audio/video
srcSets or returns the current source of the audio/video element
startOffsetTimeReturns a Date object representing the current time offset
textTracksReturns a TextTrackList object representing the available text tracks
videoTracksReturns a VideoTrackList object representing the available video tracks
volumeSets or returns the volume level of the audio

HTML5 Audio/Video Events

EventDescription
abortFires when the loading of an audio/video is aborted
canplayFires when the browser can start playing the audio/video
canplaythroughFires when the browser can start playing the audio/video to the end without stopping for buffering
durationchangeFires when the duration of the audio/video has been changed
emptiedFires when the current playlist is empty
endedFires when the current playlist is ended
errorFires when an error occurred during the loading of an audio/video
loadeddataFires when the browser can start playing the audio/video for the first time
loadedmetadataFires when the browser has received durations, dimensions and text tracks are ready for the audio/video
loadstartFires when the browser starts looking for media data
pauseFires when the audio/video has been paused
playFires when the audio/video has been started or is no longer paused
playingFires when the audio/video is ready to play after having been paused or stopped for buffering
progressFires when the browser is getting media data
ratechangeFires when the playing speed of the audio/video is changed
seekedFires when the user is finished moving/skipping to a new position in the audio/video
seekingFires when the user starts moving/skipping to a new position in the audio/video
stalledFires when the browser is trying to get media data, but data is not avaliable
suspendFires when the browser is intentionally not getting media data
timeupdateFires when the current playback position has changed
volumechangeFires when the volume has been changed
waitingFires when the video stops because it needs to buffer the next frame

...





2014년 4월 1일 화요일

아파치(apache) 실행환경 테스트

http://with-thai.com/2012/06/%EC%95%84%ED%8C%8C%EC%B9%98-%ED%8A%9C%EB%8B%9D%EC%9C%BC%EB%A1%9C-%EC%9B%B9%EC%82%AC%EC%9D%B4%ED%8A%B8%EB%A5%BC-%EB%B9%A0%EB%A6%BF%EB%B9%A0%EB%A6%BF%ED%95%98%EA%B2%8C/


이전에 워드프레스 성능 개선팁이라는 게시물을 포스팅했습니다.
비단 워드프레스 블로그에 국한되는 이야기는 아니며 가장 널리 쓰이는 웹서버인 아파치에서 동시접속자를 튜닝하는 방법을 설명하고자 합니다.
여기서 설명하는 것이 절대적인 진리는 아니며 시스템을 꾸준히 모니터링하면서 알맞은 값을 직접 찾으셔야 합니다.

웹 서버를 며칠간 재시작하지 않고 놔둬서 현재 서비스 상태를 파악하는 게 가장 좋을 것 같습니다.
간단히 아파치 서버와 클라이언트 사이의 동시 소켓 연결 개수를 확인하기 위해 아래와 같이 명령합니다.

$ netstat -nta | grep :80.
*ESTABLISHED | wc -l
이 연결 개수는 아파치 서버가 현재 처리 중인 소켓 연결 개수이며 앞으로 설명할 MaxClients 수를 넘지 않도록 유의해야 합니다.

그런데 아직 서비스를 시작하기 전이라 웹 서버의 부하를 확인하기가 어렵다면 아파치 벤치마킹 도구(ab)를 이용해볼 수도 있습니다.

$ ab -n 3000 -c 200 http://example.com/
위 명령어는 http://example.
com 사이트에 200명의 사용자가 15번씩 총 3000번 요청하는 것입니다.
사이트 주소의 끝에 / (슬래시)를 붙이는 것을 잊지 마세요.
여러 페이지를 계속 접속 시도해 동시접속 부하를 주세요.
그리고 여러 가지 시스템 상황을 모니터링해봅시다.

이렇게 부하를 줘가면서 시스템의 메모리 현황을 측정하겠습니다.
아래 예제에서는 물리 메모리가 2000MB로 확인되었습니다.

$ free -m
total used free shared buffers cached
Mem: 2000 664 1335 0 15 86
-/+ buffers/cache: 562 1437
Swap: 875 344 531
이제 MySQL 메모리 사용량을 측정합니다.

$ ps aux | grep mysql | awk '{print $6}' | awk '{total = total + $1} END {print total/1024}'
9.11328

그리고 아파치의 메모리 사용량도 측정합니다.

$ ps aux | grep apache2 | awk '{print $6}' | awk '{total = total + $1} END {print total/1024}' 1848.07
아파치 프로세스의 개수도 계산합니다.

$ ps aux | grep apache2 | wc -l
183
그럼 아파치 전체 메모리 사용량을 아파치 프로세스 개수로 나누어 계산해서 아파치 프로세스 평균 메모리 사용량은 약 10.
09MB라는 것을 알았습니다.
따라서 이론적인 최대동시연결수는 아래와 같이 계산할 수 있습니다.

(전체 메모리 – MySQL 메모리 사용량) / 아파치 프로세스 평균 메모리 사용량
= (2000 – 9.11) / 10.09
= 197.31
램이 2G인 서버에서 동시연결소켓수가 197.
31이면 이미 최대라는 이야기입니다.
실제 서버에는 bind, ssh, postfix, dovecot 다른 데몬 등이 돌아가고 있을 수 있으므로 이 값은 더 줄어듭니다.

아파치에서 동시접속을 처리하는 방법을 이해해야 합니다.
동시접속 처리방법에는 프로세스를 이용하는 법(prefork 방식)과 스레드를 이용하는 법(worker 방식)이 있습니다.
아파치 서버의 기본 동작은 prefork 방식입니다.


prefork 방식은 위 그림처럼 하나의 연결은 스레드가 하나인 자식 프로세스가 처리합니다.
프로세스를 만드는 비용은 스레드를 만드는 비용보다 더 크고 메모리를 더 많이 차지합니다.
하지만 프로세스간 메모리를 공유하지 않아 서로 독립적이기 때문에 문제가 있는 연결이 다른 연결을 간섭하지 않습니다.


반면에 worker 방식은 위 그림처럼 자식 프로세스 안에 여러 스레드가 있고 이 스레드는 하나의 연결을 처리합니다.
스레드를 만드는 것이 프로세스를 만드는 것보다 속도가 더 빠르고 메모리를 덜 차지하지만 문제가 생긴 스레드는 자식 프로세스 안의 다른 스레드까지 망가뜨릴 위험이 있습니다.
또한 경쟁상태(race condition)도 조심해야합니다.

여기서는 가장 널리 쓰이는 prefork 방식이며 이제 본론으로 들어가 최대동시접속자수를 어떻게 튜닝할지 이야기하겠습니다.

앞서 계산해서 얻은 값을 토대로 튜닝한다면 아파치의 prefork 지시어 설정은 아래와 같이 할 수 있습니다.


여기서 기억해둘 사항은 캐싱을 적극적으로 활용하면 아파치 프로세스가 10MB 정도 차지하지만 캐싱하지 않으면 프로세스당 메모리가 30MB까지도 잡힙니다.
즉, PHP 코딩이 아파치 프로세스의 메모리 사용량에 영향을 주고 최대동시접속연결수도 영향을 줍니다.
그리고 MaxClients 값을 비롯해 StartServers 등의 값을 너무 크게 잡으면 오히려 아파치 프로세스의 점유 메모리가 더 커지는 현상이 있으므로 적당한 값을 지정해야 합니다.

ServerLimit 값은 최대 자식 프로세스의 수인데 MaxClients 값보다 높게 설정하지 않아야 합니다.
구글링하다보면 MaxClients 값을 256 이상 지정하기 위해서 아파치 소스를 다시 컴파일해야 한다는 게시물들이 있는데 그럴 필요가 없습니다.
최대값이 2000이라 이미 충분히 큽니다.
MaxClients 값이 2000을 넘길 필요가 없다면 여러분은 ServerLimit와 MaxClients 값을 동일한 값으로 지정해주면 됩니다.

StartServer 값은 아파치 데몬을 처음 시작할 때 프로세스 개수이며 이 값은 MinSpareServer 또는 MaxSpareServer의 값과 일치시켜주면 됩니다.

MinSpareServers와 MaxSpareServers 값은 요청을 기다리는 몇 개의 자식 프로세스를 여분으로 둘 지 범위를 지정합니다.
아파치 데몬이 프로세스의 개수를 이 범위 안으로 두기 위해 노력하지만 이를 보장하지는 않습니다.
초당 4개 이상의 자식 프로세스를 생성(spawn)하지 않도록 설정해야 합니다.
보통은 MinSpareServers 값은 MaxClients의 10~25% 정도 크기의 값으로 MaxSpareServers 값은 25~50% 크기의 값으로 지정합니다.
그러나 이 값이 커지면 아파치 프로세스의 점유 메모리도 함께 커지는 현상이 있으니 크다고 능사는 아니므로 유념하세요.

아파치 웹 서버는 오픈소스로서 끊임 없이 패치하고 있지만 C로 작성되어 있어 메모리 누수(leak)나 무한루프 등의 서버 부하(load) 발생할 수도 있습니다.
그래서 일정 횟수 동안 클라이언트 요청을 처리하고 프로세스가 죽도록 되어 있습니다.
아파치 매뉴얼에서는 디폴트로 클라이언트 요청을 10,000번 처리하고 죽는다고 합니다.
이 클라이언트 요청을 몇 번 처리하고 프로세스가 죽을지는 MaxRequestPerChild 값의 변경해 지정할 수 있으며 시스템 사양이 좋다면 이 값을 넉넉히 할 수 있으며 프로세스가 절대 죽지 않도록 하려면 0으로 합니다.
3000에서 4000 정도 주면 적당하지 싶습니다.

이외에도 Timeout, KeepAlive, MaxKeepAliveRequests, MaxKeepAliveTimeout 같은 옵션도 성능에 영향을 미칩니다.

Timeout 10
기본적으로 소켓 연결 유지 시간입니다.
클라이언트가 요청하여 아파치와 연결된 이후로 이 시간 동안 아무런 메시지가 없으면 오류로 처리됩니다.
네트워크 회선 상태가 좋지 않으면 이 값을 크게 할 수 있습니다.
국내 사용자만 고려한다면 10초 정도 국외 사용자까지 고려하면 20초가 좋습니다.

KeepAlive를 On 해으면 첫 요청시에 열어 놓은 연결을 KeepAliveTimeout에서 지정한 시간 동안 끊지 않습니다.
그래서 img src=”http://~” 태그로 이미지를 많이 링크하고 있으면 매번 소켓을 열지 않기 때문에 접속 속도가 향상됩니다.
하지만 동시접속자수는 줄어들 수 있습니다.
이 블로그의 경우에는 동시 접속자가 많지 않으므로 빠른 접속 속도를 위해 켰습니다.

KeepAliveTimeout 2
국내 접속자가 많으면 3초 이하 국외 접속자가 많으면 10초까지 지정할 수 있다고 합니다.
10초 이상은 메모리 점유로 동시접속자가 크게 감소할 수 있다고 판단됩니다.

MaxKeepAliveRequests 100
KeepAlive 상태에서 처리할 최대 요청 수로 보통 웹 사이트에서는 100 정도 지정하면 충분합니다.

참고로 개인 블로그가 아닌 정말 접속자가 많은 사이트를 운영할 경우에는 관리상 웹 어플리케이션 서버와 이미지 서버를 분리해 운영하는 것이 맞습니다.
특히, 웹 어플리케이션 서버의 경우에는 KeepAlive Off로 하고 이미지 서버는 연결 유지를 위해 KeepAlive On으로 설정해두기도 합니다.

워드프레스뿐만 아니라 아파치를 쓰는 어떤 웹서비스나 적용 가능한 팁입니다.
이제 쌩쌩 달리는 아파치를 경험하세요.