LAMPのチューニング勘所【初歩】

# 最初に
様々な情報をかき集めたまとめ的なメモです。

# Linux
## swapの作成
```bash
# ディレクトリ作成
mkdir /swap

# swapファイル作成(例は4Gのswapファイルを作成)
/bin/dd if=/dev/zero of=/swap/swapfile bs=1M count=4096

# swap領域に設定(フォーマット)
/sbin/mkswap /swap/swapfile

# パーティション変更
chmod 600 /swap/swapfile

# swap領域有効化
/sbin/swapon /swap/swapfile

※確認
free
```

```vim:/etc/fstab
# 起動時にswapを割り当てる
/swap/swapfile swap swap defaults 0 0
```

# Apache
## KeepAlive
### KeepAliveとは
一般的に１つのHTMLに対して、
ダウンロードするものはHTMLファイル一つということはあまりない(画像などの外部ファイルなど)
KeepAliveを設定していないと、このひとつひとつにTCP接続の開始と切断を行うことになる。
設定すれば、一つのブラウザからのリクエストを一つのTCP接続で処理できる。

### 設定したほうがいいんじゃ？
一概にそうともいえない。
なぜならリクエスト毎にTCPコネクションの生存時間は同一でない。
しかし設定は固定である。。
つまり実装するのであれば、リクエストの平均的な要求値を算出する必要がある。

### つまるところOnにしたほうがOffにしたほうがいいのか
動的コンテンツ(HTML)と静的コンテンツ(画像、css、jsなど)のリクエストは大きく異る。
動的なものは、リクエストに～数秒かかり、最初の一度のみ。(KeepAliveの必要なし)
静的なものは、リクエストにミリ秒単位しかかからず、リクエスト数も多い。(KeepAliveが有効)
しかしWebページはこのふたつが混在しているため、矛盾が生じている。

よって採用する基準は以下になる。

①動的ページと静的ページのサーバは分離すべきである
②動的ページ用のサーバはKeepAliveをOffにする(というよりする必要が無い)
③静的ページ用のサーバはKeepAliveをOnにする

ただし、
MaxKeepAliveRequests(接続～切断までに受け付けるリクエスト数)は
平均的な要求ファイル数より少し少なめ。

KeepAliveTimeout(リクエストが来なくなってから切断するまでの時間)は
1～2秒程度(TCPコネクションが無駄に掴まれないように)

## mod_deflate
ファイル圧縮による転送量減少を促すモジュール。
転送量は減るが、CPUの処理は増えるため、ボトルネックがCPUの処理能力に移る。

## MPM
### preforkチューニングの簡単な考え方
・MaxClientの算出さえ出来たら、深く考えずにプロセス数系は全部同じ値にしよう
・MaxRequestsPerChildを0(無制限)にするのは、メモリ使用量肥大化につながるのでやめよう
　(1000とかにしておけばいいと思う)

### MaxClient数の算出方法
サーバの物理メモリを消費しつくして、スワップさせないことが一番重要。
httpd1プロセスあたりのメモリ使用量はtopコマンドで確認(RESのところ)

### 算出
サーバの物理メモリ量 > (1プロセスのメモリ量) × (MaxClient数) + (他のプロセスが使うメモリ量)

### 設定例
**※service httpd restartでは反映されない時があるので注意(start,stopでやろう)**

```vim
#起動初期に自動生成されるプロセス数
StartServers 15

#待機(アイドル状態)の最小プロセス
MinSpareServers 15

#待機(アイドル状態)の最大プロセス
MaxSpareServers 15

#サーバーが処理できる子プロセス最大数( ※必ずMaxClientsの上に書くこと)
ServerLimit 15

#リクエストに応答するために作成される 子プロセスの最大個数(クライアント数)
MaxClients 15

# 個々の子プロセスが扱うことのできるリクエストの制限数
MaxRequestsPerChild 1000

#free() が呼ばれない限り、 メモリ確保と開放を管理する主メモリアロケータが保持し続けられるメモリの最大量(※ 0は無制限)
#MaxMemFree 2048
```
### タイムアウト
いくつかわからないが、デフォルトは注意。せいぜい一分くらいにしておこう。

```vim
Timeout 60
```

### キャッシュ
**※WPとApacheキャッシュモジュールは相性が悪いので、やらないほうが良い！**

①キャッシュディレクトリ作成

```bash
mkdir /var/cache/httpd
mkdir /var/cache/httpd/mod_disk_cache
chmod -R 777 /var/cache/httpd
```

②Apacheモジュール(mod_expires、mod_cache)設定

```vim
# モジュールの有効化
LoadModule expires_module modules/mod_expires.so
LoadModule cache_module modules/mod_cache.so
LoadModule disk_cache_module modules/mod_disk_cache.so

# クライアントマシンキャッシュ
# ※PHPはデフォではExpireヘッダは付加されないのでmod_expiresが必要
<ifModule mod_expires.c>
    # キャッシュ有効化
    ExpiresActive On
    # 全てのMIMEタイプのキャッシュ時間設定
    ExpiresDefault "access plus 10 hour"
    # MIMEタイプ毎のキャッシュ時間設定(使用する場合はコメントアウト外す)
    # ExpiresByType text/html "access 10 hour"
</IfModule>

# キャッシュ設定
<IfModule mod_cache.c>
    <IfModule mod_disk_cache.c>
        # キャッシュ保存先
        CacheRoot /var/cache/httpd/mod_disk_cache
        # キャッシュ有効化(指定以下の階層をキャッシュ)
        CacheEnable disk /
        # クライアントからの「キャッシュ返すな」を無視
        CacheIgnoreCacheControl On
        # 「Last-Modified(最終修正時刻)」ヘッダの無いドキュメントもキャッシュ
        CacheIgnoreNoLastMod On
        # 「Cache-Control: no-store」ヘッダのレスポンスをキャッシュできるか試みる
        CacheStoreNoStore On
        # Cookie(Set-Cookieヘッダ)はキャッシュしないようにする
        CacheIgnoreHeaders Set-Cookie
        # キャッシュディレクトリで使用する文字数
        CacheDirLength 3
        # キャッシュするサブディレクトリの深さ
        CacheDirLevels 5
        # ドキュメントをキャッシュするか、また最大容量は(byte)
        CacheMaxFileSize 2000000
        # ドキュメントに有効期限、最終修正時刻が指定されていない場合のデフォルトキャッシュ時間(秒)
        CacheDefaultExpire 36000
        # ドキュメントをキャッシュする最大時間(秒)
        CacheMaxExpire 36000
        # 特定のURL以下はキャッシュしない(以下はWPの場合)
        CacheDisable /wp-admin
        CacheDisable /wp-content
        CacheDisable /wp-includes
    </IfModule>
</IfModule>
```

③定期的にキャッシュを調整するようにcrontabを設定

```bash
crontab -e
```

```vim
# mod_cacheのキャッシュを調整
00 10 * * * /usr/sbin/htcacheclean -r -l 100M -p /var/cache/httpd/mod_disk_cache
```

# MySQL(5.5以降)
メモリ設定の場合に考えるのは、
グローバルバッファ(MySQLで単一)とスレッドバッファ(コネクション単位で確保)である。

つまり、
メモリ使用量 = グローバルバッファ + (スレッドバッファ × コネクション数)

## グローバルバッファ
innodb_buffer_pool_sizeはどれくらい降る？
理想は、innodbテーブルの全データ量がベスト。

```mysql:調べ方
SELECT CONCAT(CEILING(RIBPS/POWER(1024,pw)),SUBSTR(' KMGT',pw+1,1))
Recommended_InnoDB_Buffer_Pool_Size FROM
(
SELECT RIBPS,FLOOR(LOG(RIBPS)/LOG(1024)) pw
FROM
(
SELECT SUM(data_length+index_length)*1.1*growth RIBPS
FROM information_schema.tables AAA,
(SELECT 1.25 growth) BBB
WHERE ENGINE='InnoDB'
) AA
) A;
```
※ここで出た値の110%が理想値

※参考
http://takahashikzn.root42.jp/entry/2015/02/08/212840


innodb_log_file_sizeは大きければ大きいほど、パフォーマンスが向上する(最大でも4G)
innodb_buffer_pool_sizeを変えたら、ここも変える必要がある。
とはいえ、多くても64MBあればいいらしい。

## コネクション
max_connectionsで設定。

```mysql:確認方法
SHOW STATUS LIKE '%connect%';
```

※Max_used_connectionsが、起動から今までの最大同時接続数
※Threads_connectedが、現在の接続数


interactive_timeout、wait_timeoutは
クライアントからの反応がない場合のコネクションタイムアウト時間。

2つの差は、接続が対話型かそうでないかの差なので、目的に応じて同じ値を割り振れば良いと考えれば楽。
(接続型はアプリケーションによって決まるので、どちらか片方を設定というのはやめたほうがいい)

オンラインゲームやバッチのような、コネクション繋ぎっぱなしのほうが良い場合は話が別だが、
Webの場合はそこまで時間は必要ない。処理待ちのプロセスが残るくらいなら、程よく切断しよう。
※最大は31536000

## スレッドバッファ
ストレージエンジン共通のスレッドバッファ。
当たり前だが、大きな値にすればするほど、コネクション数で首を絞める・・のだが、
基本的に大きな値を振らなくてもある程度パフォーマンスを出せるようだ。

read_buffer_size、read_rnd_buffer_size、sort_buffer_size、tmp_table_sizeあたり。
下記例を定数として良いだろう。(コネクション数とは相談すること)

tmp_table_sizeはmax_heap_table_sizeに引きづられるので、同じ値にしよう。

## クエリキャッシュ
クエリ結果をメモリにキャッシュさせ、同じクエリの場合はｍキャッシュ上のデータを取得する。
ディスクI/Oを軽減させることが可能。

例を定数として、持たせるくらいで良いだろう。
query_cache_sizeはグローバルバッファのようなので、多めに持たせておくと良い。

## その他
max_heap_table_size：MEMORYテーブルの最大サイズ、このサイズを超えたらディスク上に作成される。

## まとめ
```vim
[mysql]
# 文字コード設定
character-set-server=utf8

[mysqld]
# 文字コード設定
character-set-server=utf8
skip-character-set-client-handshake

# グローバルバッファ(スレッドバッファ抽出後に残りから割り振る)
innodb_buffer_pool_size=520M
innodb_log_file_size=64M
query_cache_size = 64M

interactive_timeout=120
wait_timeout = 120

# スレッドバッファ(計：15*n=345MB)
max_connections=15
read_buffer_size=1M
read_rnd_buffer_size=2M
sort_buffer_size=4M
tmp_table_size=16MB

# クエリキャッシュ
query_cache_limit = 16M
query_cache_type = 1

# IP逆引き無効
skip-name-resolve
```

※innodb_log_file_sizeを変えた場合の再起動方法

```bash
mysql> SET GLOBAL innodb_fast_shutdown=0;

service mysqld stop

rm -f /var/lib/mysql/ib_logfile*

service mysqld start
```

※MySQLチューナーが便利らしい

```bash:インスコ
wget -O MySQLTuner.zip https://github.com/major/MySQLTuner-perl/archive/master.zip
unzip MySQLTuner.zip
cd MySQLTuner-perl-master
```

```bash:実行
 ./mysqltuner.pl --user root --pass mypassword
```

※クエリの各実行時間を調べる

```bash
mysql > set profiling = 1;
mysql > SQL実行
mysql > show profile;
```

# PHP
## memory_limit
PHPのメモリ最大使用量 = MaxClients × memory_limit

基本的にmemory_limitが大きすぎるのはアウト。
だが、小さすぎても、処理しきれずにエラーになるため、程よく割り振る。

```shell-session
memory_limit=64M
```