技術的な話題 に関する投稿を表示しています

MySQL (MariaDB) のスローログを出す設定をする

インデックスつかってる?やばない?みたいなクエリを調べたいので、スローログで出せた気がするなあ、ってメモ。

スローログに関する設定の確認

> show variables like '%slow%';
+---------------------+--------------------------------------------------------------------------------------------------------------+
| Variable_name       | Value                                                                                                        |
+---------------------+--------------------------------------------------------------------------------------------------------------+
| log_slow_filter     | admin,filesort,filesort_on_disk,full_join,full_scan,query_cache,query_cache_miss,tmp_table,tmp_table_on_disk |
| log_slow_queries    | OFF                                                                                                          |
| log_slow_rate_limit | 1                                                                                                            |
| log_slow_verbosity  |                                                                                                              |
| slow_launch_time    | 2                                                                                                            |
| slow_query_log      | OFF                                                                                                          |
| slow_query_log_file | 522d4fac608d-slow.log                                                                                        |
+---------------------+--------------------------------------------------------------------------------------------------------------+
7 rows in set (0.00 sec)
> show variables like '%long%';
+---------------------------------------------------+-----------+
| Variable_name                                     | Value     |
+---------------------------------------------------+-----------+
| deadlock_search_depth_long                        | 15        |
| deadlock_timeout_long                             | 50000000  |
| long_query_time                                   | 10.000000 |
| max_long_data_size                                | 1048576   |
| performance_schema_events_waits_history_long_size | 10000     |
+---------------------------------------------------+-----------+
5 rows in set (0.00 sec)
> show variables like '%log_queries%';
+-------------------------------+-------+
| Variable_name                 | Value |
+-------------------------------+-------+
| log_queries_not_using_indexes | OFF    |
+-------------------------------+-------+
1 row in set (0.00 sec)
> show variables like '%output%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_output    | FILE  |
+---------------+-------+
1 row in set (0.00 sec)

log_slow_queries と slow_query_log がいてオッ?と思ったが slow_query_log を使うのが正しいらしい。

profiling - Mysql: What is the difference between "slow_query_log" vs "log_slow_queries" - Stack Overflow

 

その他の設定値はフィーリングで大丈夫(ダメ)
このあたりで説明は補完できる。

MySQL :: MySQL 5.7 Reference Manual :: 5.1.7 Server System Variables

スローログの設定と動作確認

set global slow_query_log = ON;
set global long_query_time = 1;
set global log_queries_not_using_indexes = ON;
set global log_output = 'TABLE';

log_output を TABLE にすると mysql.slow_log テーブルに出る FILE にするとファイルに出る。

まずは TABLE にした場合

> use hoge;
> select * from users where nanika_id = 1;

> use mysql;
> show tables;
+---------------------------+
| Tables_in_mysql           |
+---------------------------+
| columns_priv              |
| db                        |
| event                     |
| func                      |
| general_log               |
| help_category             |
| help_keyword              |
| help_relation             |
| help_topic                |
| host                      |
| ndb_binlog_index          |
| plugin                    |
| proc                      |
| procs_priv                |
| proxies_priv              |
| servers                   |
| slow_log                  |
| tables_priv               |
| time_zone                 |
| time_zone_leap_second     |
| time_zone_name            |
| time_zone_transition      |
| time_zone_transition_type |
| user                      |
+---------------------------+
24 rows in set (0.00 sec)

> select * from slow_log;
+----------------------------+---------------------------+-----------------+-----------------+-----------+---------------+------+----------------+-----------+-----------+-----------------------------------------+
| start_time                 | user_host                 | query_time      | lock_time       | rows_sent | rows_examined | db   | last_insert_id | insert_id | server_id | sql_text                                |
+----------------------------+---------------------------+-----------------+-----------------+-----------+---------------+------+----------------+-----------+-----------+-----------------------------------------+
| 2018-07-19 05:08:05.999111 | root[root] @ localhost [] | 00:00:00.003893 | 00:00:00.002550 |         0 |             0 | hoge |              0 |         0 |         0 | select * from users where nanika_id = 1 |
+----------------------------+---------------------------+-----------------+-----------------+-----------+---------------+------+----------------+-----------+-----------+-----------------------------------------+
1 row in set (0.00 sec)

> use hoge;
> explain select * from users where nanika_id = 1;
+------+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id   | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+------+-------------+-------+------+---------------+------+---------+------+------+-------------+
|    1 | SIMPLE      | users | ALL  | NULL          | NULL | NULL    | NULL |    1 | Using where |
+------+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

次に FILE の場合。

$ pwd

/var/lib/mysql


$ tail 522d4fac608d-slow.log

# Time: 180719  5:33:26
# User@Host: root[root] @ localhost []
# Thread_id: 3  Schema: hoge  QC_hit: No
# Query_time: 0.000337  Lock_time: 0.000141  Rows_sent: 0  Rows_examined: 0
SET timestamp=1531978406;
select * from users where nanika_id = 1;

slow_query_log_file で指定した場所に出る /var/log/mysql/... みたいな指定をする必要がありそう。


インデックスを使用していないクエリも出してくれる、便利。

そのほか

set global しただけだと mysql サーバーを終了したときに設定が消えてしまうので、必要に応じて my.cnf に記載。

[mysqld]
slow_query_log=ON
long_query_time=1
log_queries_not_using_indexes=ON
log_output=FILE
slow_query_log_file=hogehoge-slow.log
$ echo 'show variables like "%slow%";' | mysql

Variable_name	Value
log_slow_filter	admin,filesort,filesort_on_disk,full_join,full_scan,query_cache,query_cache_miss,tmp_table,tmp_table_on_disk
log_slow_queries	ON
log_slow_rate_limit	1
log_slow_verbosity
slow_launch_time	2
slow_query_log	ON
slow_query_log_file	hogehoge-slow.log

大丈夫そう。

日本語の折り返しを正規表現で解決する mikan.js を PHP に書き換えた

できたものがこちらです

作った背景

日本語の折り返しが中途半端になってつらい!機械学習で改善するぞ!という話が過去にありました。
google/budou: Budou is an automatic organizer tool for beautiful line breaking in CJK (Chinese Japanese and Korean).

それからしばらくして、いやいや機械学習じゃなくてもいいのでは?というものが出てきました。
mikan.js : 機械学習なしで、日本語の単語の改行を処理するライブラリを書いた

これって別に JS で表示するときにアレコレしなくても、普段のサーバサイドでいい感じにしてもいいのでは??と思い PHP に移植してみた次第です。

移植する流れ

元のコードを眺めて、同じような処理に書き換えていく簡単なおしごと。
幸いにも、そこまで難しいロジックでは無いので、動作をみながら書き換えていきました。

正規表現のあたりだけ、言語の違いでちょっと詰まったので、ドキュメントを見ながら動作を見ながら随時書き換えていくようなコツコツ作業でした。

言語の書き換え、双方の言語について理解が深まるのでオススメです。

git で用済みのブランチをまるっと消す

普段の開発はもちろん、確認用!作業用!などとやったり放っておくと増えていくブランチを一掃する。

基本的には master をチェックアウトしてからやったほうがいい。
別のブランチから見たときに、あるブランチがマージされていないように見えることがあるので、基本的には master ブランチをチェックアウトしてからやったほうがよさそう。
それも組み込めないかなあ、、シェルスクリプトだなー

ローカル用

git branch --merged | grep -v '*' | grep -v 'master' | xargs git branch -D

リモート用

git branch -a --merged | grep remotes | grep -v HEAD | grep -v master | sed -e "s/remotes\/origin\///" | xargs git push --delete origin

マウスホバーでAjaxしてコンテンツを先読みキャッシュ

なんとなく思いついて、このブログに入れてみて機能の紹介。

link rel=prefetch

HTML の機能として、指定した URL の内容を先読みして、内容をキャッシュしておいてくれるものがあります。
詳しいことは MDN を見るとよいかとー。

rel="preload" によるコンテンツの先読み - HTML: HyperText Markup Language | MDN
Link prefetching FAQ - HTTP | MDN

preload と prefetch って??という場合にはこちらの記事もおすすめです。

Preload を用いたリソースプリローディングの最適化 | blog.jxck.io

なぜ onHover で prefetch ?

ちゃんと計測したことないのでわからないですけど、リンクをセカセカ、サササッ!とクリックすること、あまり無いですよね?読み物系ならとくに。

わずかにホバーする時間があってからクリックするのかなあと思ったので
じゃあそのタイミングで先読みしたら爆速 Web サイトが体験できるんじゃ?と思った次第です。

コード

// prefetch link
let prefetchTimers = {};
let prefetcedLinks = {};
document.querySelectorAll('a').forEach((element) => {
    element.addEventListener('mouseenter', (event) => {
        if (element.href.indexOf('#') !== -1 || element.href.indexOf('javascript:') !== -1) {
            return;
        }
        if (element.target === '_blank') {
            return;
        }
        if (prefetcedLinks[element.href] === true) {
            return;
        }
        prefetchTimers[element] = setTimeout(() => {
            const prefetchTag = document.createElement('link');
            prefetchTag.rel = 'prefetch';
            prefetchTag.href = element.href;
            document.head.appendChild(prefetchTag);
            prefetcedLinks[element.href] = true;
        }, 300);
    });

    element.addEventListener('mouseleave', (event) => {
        if (prefetchTimers[element] !== undefined) {
            clearTimeout(prefetchTimers[element]);
            delete prefetchTimers[element];
        }
    });
});

遷移先別に、ホバー用タイマーと読み込み有無を記録しています。
ホバーから外れるとタイマーを削除し、ホバーが外れずにタイマーが経過すると prefetch が登録されます。

爆速 web サイトは体験できるのか?

prefetch 無し

prefetch あり

1 秒ちょっとかかっていたのが 300ms ほどに収まるようになりました!すごい!

まとめ

prefetch で爆速 web 体験ができるかも。
結局作ってみた満足度が高いことが主になっているので、ガチプロダクトでやってくなら本当に効果あるの?その機能使われている?は別途ちゃんと計測しないとねーーー。
あとは prefetch すればギガ減るよね、というかスマホ対応できないなこれ。スマホ対応ってどうすんだろ。

PHP で時間を固定した未来にしたりしたい

PHP で時間が絡むようなテストをしていてコケたりコケなかったりした。

具体的には、登録してから〇〇時間後にあるメソッドが呼ばれたら、ステータスを xx に変える、みたいなもの。

そんなときに使えるアイデアを3つ。

Carbon を使っている場合

Carbon なら setTestNow を使うと良い。
各テストで、好きなように setTestNow を書く。

Carbon::setTestNow(Carbon::parse('ここに時刻'));

特に時刻の希望がなく、現在時刻を固定したいだけならこれで。

Caron::setTestNow(Carbon::now());

それと tearDown で引数なしで呼べばよい(事故防止)

public function tearDown()
{
    parent::tearDown();
    Carbon::setTestNow();
}

Carbon - A simple PHP API extension for DateTime.

Chronos を使っている場合

Chronos にも Carbon と同様に setTestNow が用意されている。助かる〜。

使い方は Carbon のソレと一緒。

Chronos - 3.6

php-timecop を導入する

特に何も導入してなくて DateTime をもりもりやってたり、もはや date や time が乱立してたらこれしかお手軽な手は無いか。
PHP 拡張として動作して PHP が扱う時間をコントロールするツワモノ。

テスト用途だけじゃなくて、例えばあるページが未来ではどのように見えるかの動作確認用とか、プロダクション用途としても使える。(使ったことがある)

remi や brew pecl で配布されているので導入もお手軽。

GitHub - hnw/php-timecop: A PHP extension providing "time travel" capabilities inspired by ruby timecop gem

(余談だけど mac 上でやろうとしたら homebrew の php が core にくっついて拡張の類がなくなったので pecl から入れる必要があった)

ざっくりとはこんな感じ strtotime でもいい。

var_dump(date('Y-m-d H:i:s'));
sleep(3);
var_dump(date('Y-m-d H:i:s'));

timecop_freeze(new DateTime('2018-01-01 12:00:00'));

var_dump(date('Y-m-d H:i:s'));
sleep(3);
var_dump(date('Y-m-d H:i:s'));

timecop_return();

var_dump(date('Y-m-d H:i:s'));
sleep(3);
var_dump(date('Y-m-d H:i:s'));
string(19) "2018-06-14 12:05:05"
string(19) "2018-06-14 12:05:08"
string(19) "2018-01-01 12:00:00"
string(19) "2018-01-01 12:00:00"
string(19) "2018-06-14 12:05:11"
string(19) "2018-06-14 12:05:14"

そのほか

そもそもの設計として、外からオブジェクトをインジェクション出来るようにするほうが何かと便利っぽい。
とはいえ無理な状況ってあると思うので、そういうときにここで挙げたアイデア使えるんじゃないかな。timecopとかすごい。

authorization と authentication の話。そして Laravel の Gate の紹介をちらっと。

要するに、認証と認可は別物だよって話。

 

ざっくりとまとめると。

認証 Authentication
あなたは誰ですか
私は X というユーザです、パスワードはこれです
確認しました X で間違いないです

 

認可 Authorization
X です、管理画面を開きたいです
あなたは管理画面への"鍵"をもっていません、拒否します

 

もうちょい例。
世帯主じゃなくても、家の鍵を持っていれば家に入れる。=認可
世帯主かどうかは公的文書(住民票とか)で確認する。=認証

 

で、じゃあ Web ではどうやんねん、というと、
(例によってよく使うものだけ紹介)

CakePHP ならこのあたりにまとまってる。

認証 - 3.6

 

Laravel だと分かれてる。使う仕組みが違うので別項目になってるって。

Authentication - Laravel - The PHP Framework For Web Artisans
Authorization - Laravel - The PHP Framework For Web Artisans


Laravel の Gate の説明をちゃんと見てみたの初めてだけど Gate かっちょいいな、権限管理とか、できるできないみたいな話がわりかし簡単にかけそう。

できるできないはこういう風に AuthServiceProvider->boot に書いたり。

Gate::define('update-post' function ($user $post) {
    return $user->id == $post->user_id;
});

こういう形で クラス名 @ メソッド名 として外だししたり。

Gate::define('update-post' 'PostPolicy@update');
class PostPolicy
{
    public function update(User $user Post $post)
    {
        return $user->id == $post->user_id;
    }
}

でもって、定義した Gate は、コントローラーだったりモデルだったりで、こうやって使えるらしい。

if (Gate::forUser($user)->allows('update-post' $post)) {
    // The user can update the post...
}

あとは、ポリシーを定義することができて(↑にある PostPolicy@update という書き方で使えるものとは異なる)
Eloquant に対して view/create/update/delete がそれぞれ権限ありますか?というのをお手軽に内部でつないでくれるらしい。

たぶん実際のユースケース的にはいろいろ分割しやすいこの書き方がいいんじゃなかろうか。

AuthServiceProvider はこういう感じで

class AuthServiceProvider extends ServiceProvider
{
    protected $policies = [
        Post::class => PostPolicy::class,
    ];
...

ポリシークラスのほうはこんな感じ。

namespace App\Policies;

use App\User;
use App\Post;

class PostPolicy
{
    public function update(User $user Post $post)
    {
        return $user->id === $post->user_id;
    }
}

さっきの update とまったく同じなんだけど、こうすることで AuthServiceProvider が勝手に Post を監視してくれて PostPolicy に書かれている通り update 時のチェックを実行して true なら update ができる、というようなことをやってくれるんだそうだ。

便利~~~~。

 

例えば wordpress 的なものをイメージして、簡単にやってみると。

  • 投稿
    • 管理者でログインしていれば投稿の作成、編集、閲覧、公開設定にすることが可能
    • 編集者でログインしていれば投稿の作成、編集、閲覧、が可能。公開設定にはできない
    • ログインしていなければ投稿の閲覧が可能
  • コメント
    • 管理者でログインしていればコメントの作成、削除、公開されたコメントの閲覧、管理者向けコメントの閲覧が可能
    • それ以外は作成と、公開されたコメントの閲覧のみ可能

みたいなのも Gate をつかったらぱっぱっぱ~~~ってかけそうだって思った。
投稿ポリシーとコメントポリシーを、それぞれ書いてある通りに定義すればいいだけだし、仕様を形にするのが簡単そうだ。

んん~~~、使いどころがあれば使いたいなあ。

PhpStorm でコーディングしてるときに連番を作りたいなーと思ったけど、それ seq でええやんって解決した

SQLを発行したり、テストデータを作ったり、絶妙なタイミングで連番の出番がある気がする。
ので、そうなったときに、一旦適当な php か html ファイルを開いて Emmet の機能を使ってしまうのが簡単だなあ、と思った。

a[class=$$$$$$]*100

まで入力して Tab を押すとどばーって展開される。上限は 100 っぽい。

ここからあとは 検索 → マルチカーソルでの選択 → タグの部分を削除 ということをすると連番だけいい感じに作れる。よい。

PhpStorm …というか多分 IntelliJ 系ならできるんじゃなかろうか? PhpStorm しか使ってなくて他わからん。

 

…。

と思ったんですけど、冷静に考えて seq と pbcopy でいいんじゃなかろうか。

seq -f '%06g' 1 100 | pbcopy

以下の内容がクリップボードに入ってるので、そのまま貼り付けられる。
000001
000002
......
000100

おわり。


余談だけど作業環境が Mac に切り替わったので Windows の話はわからん。
gocopy なるものがあるらしいのでそれとかどうだろう。デフォルトだと clip ってコマンドが使えるらしい。

atotto/clipboard: clipboard for golang

MySQL で ERROR 1265 (01000): Data truncated for column ‘xxxxx’ at row 1 みたいなエラーが出たとき

ぼくは UPDATE 文を実行しようとしただけなんだ。

> update xxxxx set yyyyy = "aaaaa";
ERROR 1265 (01000): Data truncated for column 'yyyyy' at row 1

enum 型のカラムに列挙されてない値を入れようとしたら出たものです。

 

というわけで ALTER して取りうる値の種類を増やすと、クエリが通りました。

ALTER TABLE テーブル名 MODIFY COLUMN カラム名 ENUM(取りうる値);

CHANGE COLUMN でもいいですが、書き方が微妙に違います。
古いカラム名、新しいカラム名、という書き方になります。

MySQL :: MySQL 5.6 リファレンスマニュアル :: 13.1.7 ALTER TABLE 構文

 

ちなみにこのエラー、他にもカラムの幅が足りないとこに入れようとしても出るようです。

mysql - Data truncated for column? - Stack Overflow

git の差分で何かをした(今回は phpunit をしたい)

テストをもりもり追加したけど、それだけいい感じに動かしたいなあってやつ。

キモはこのコマンド。

git diff --name-only 比較元ブランチ 比較対象ブランチ

--name-only をつけると変更のあったファイル名だけが出力される。

ちなみにブランチと書いたものの、コミットが示せればいい。
HEAD とか HEAD~2 とか。
あるいは abc123 みたいにハッシュとか。

そしたらこいつをパイプしながらゴニョゴニョすればおけ。

 

ここ最近、手元で使ってみてるのはこれ。

$ git diff --name-only HEAD $(git branch -a | peco | tr -d '*' | tr -d ' ') | grep -i "test.php" | xargs -I '{}' composer test '{}' | grep ')'
> phpunit --testsuite unit 'tests/Hoge/HogeTest.php'
.                                                                   1 / 1 (100%)
OK (1 test, 7 assertions)
> phpunit --testsuite unit 'tests/Hoge/HugaTest.php'
.......S.S...S.                                                   15 / 15 (100%)
> phpunit --testsuite unit 'tests/Hoge/FooTest.php'
.                                                                   1 / 1 (100%)
OK (1 test, 1 assertion)
> phpunit --testsuite unit 'tests/Hoge/BarTest.php'
........                                                            8 / 8 (100%)
OK (8 tests, 15 assertions)

peco が必要。
peco/peco: Simplistic interactive filtering tool

実行すると、ブランチを指定できて(リモート可)、ワーキングディレクトリとの差分があったテストだけ実行できる。 master ばかりではなくて、たまには違うブランチもやりたいよね。


と、思ったけど、ソースだけ変えた場合って出てこないよね…。
うまいこと差分に対してテストできるような仕組みできないかなー

ast 作れるし、いい感じに解析して、影響のありそうなテストだけいい感じに動かしてくれる君みたいなの。

WordPress 環境で nginx の proxy_cache を有効にする

おぼえがき。

Module ngx_http_proxy_module

キャッシュの名前、その保存先、サイズを設定する。

// /etc/nginx/nginx.conf
http {
    ...

    # cache
    proxy_cache_path /tmp/nginx/cache keys_zone=cache1:10m;
}

サイズについては公式ドキュメントにこう書いてあります。

One megabyte zone can store about 8 thousand keys.

10m という指定だとざっくり 8 万個のキーが保存できそうです。

どういうときにキャッシュするかを設定する

いくつかポイントがあるが、とりあえず今回の設定内容を出します。

// /etc/nginx/conf.d/server.conf
server {
    ...

    # cache
    set $mobile "";
    if ($http_user_agent ~* '(Mobile|Android)') {
        set $mobile "SP";
    }

    set $do_not_cache "";
    if ($http_cookie ~* "comment_author_|wordpress_(?!test_cookie)|wp-postpass_" ) {
        set $do_not_cache 1;
    }

    proxy_no_cache          $do_not_cache;
    proxy_cache_bypass      $do_not_cache;
    proxy_cache             cache1;
    proxy_cache_key         "$mobile//$scheme://$host$request_uri$is_args$args";
    proxy_cache_valid       200 301 302 30d;
    proxy_cache_valid       any 10m;

    add_header X-Cache-Status $upstream_cache_status;

    ...
}

モバイル判定

WordPress のテーマとして、レスポンシブではなくサーバサイドでモバイルとの何か差分を作っている場合、キャッシュも分けないといけません。

WordPress では is_mobile() という関数が用意されていて、これをつかってモバイル判定ができるので、これに合わせて nginx も設定するとよさそうです。

vars.php in tags/4.9.5/src/wp-includes – WordPress Trac

今回はおおむね iPhone と Android だけという区別でいくので Mobile|Android という指定にしました。

set で変数を設定し proxy_cache_key にその変数を入れることで、キャッシュする内容をモバイルとそれ以外とで分けることができます。

キャッシュをしないとき

管理画面にログインしていたり、コメントフォームに投稿した名前が記録されていたりなど、ユーザのもっているクッキーに応じて、テーマ上で値が出し分けされる場合、その内容をキャッシュしてはいけません。
(ログインしていないのに管理バーが出ちゃうよ!)

comment_author_|wordpress_(?!test_cookie)|wp-postpass_ として示されるクッキーがあるかを判定すると良いみたいです。

ここもモバイル判定と同様に変数に入れます。

この変数は proxy_no_cache と proxy_cache_bypass で使います。
proxy_no_cache はレスポンスをキャッシュに保存しない設定で proxy_cache_bypass はリクエストに対してキャッシュを使ってレスポンスを送らない設定です。
どちらも 0 ではないときに有効になります。

キャッシュの有効期限

proxy_cache_valid を使うことで有効な時間を設定できます。

ステータスコードをスペース区切りで書き、その後ろに有効期限を記載します。使える単位は ms/s/m/h/d/M/y です。

Configuration file measurement units

ここでは、ステータスコードが 200 または 301 または 302 のときに 30 日の間保持するようにしています。

また any という記載はそれ以外のステータスコードすべてに対して適用されます。ここでは 10 分にしています。

キャッシュが使われたか確認する

$upstream_cache_status という変数を見ると、キャッシュを使ったかどうかがわかります。

Module ngx_http_upstream_module

値として、おおむね HIT か MISS 、期限切れの場合は EXPIRED 、キャッシュしない場合は BYPASS がそれぞれ HTTP ヘッダーに出ているはずです。それ以外はちょっとわかんないです。

nginx の再起動

設定した内容に問題ないかを確認し nginx の再起動やりロードをしないと設定が反映されません。

service nginx configtest
service nginx condrestart

このときに proxy_cache_path に設定したパスが存在しないと自動で作られることはないので、自分で作っておく必要があります。

キャッシュの削除

このままでは WordPress で新しい投稿をしてもキャッシュはが有効な間は、新しい投稿についてはキャッシュ上のコンテンツからたどることはできません。
ここでは 30 日が有効期限なので、月 1 回しか更新することができなくなってしまいます。

手動でキャッシュを消す

proxy_cache_path に設定したパスにキャッシュファイルがもりもり作られるので、そのファイル群を消せばキャッシュはなかったことになります。

rm -rf なんかでどばーっと消すと良いでしょう。

毎回手動でキャッシュを消すのも面倒なので、 WordPress から消せるようにします。

WordPress で投稿を保存した時に自動でキャッシュを消す

// functions.php
function clean_nginx_cache($postId) {
    exec('rm -rf /tmp/nginx/cache/*');
    file_get_contents(get_permalink($postId));
}
add_action('save_post', 'clean_nginx_cache');

手動でやるものを WordPress のアクションフックに設定して自動化したものです。
投稿を保存した時に自動でキャッシュを消し、なんならその投稿のキャッシュを作成することができます。

プラグイン API/アクションフック一覧/save post - WordPress Codex 日本語版

 

プラグインもありそうなので、そういうのを使ってもよいと思います。

“nginx cache” の検索結果 — WordPress プラグイン

nginx の設定でなんとかする

今回の環境では利用できなかったのですが(モジュールがないっぽい…?) proxy_cache_purge を使うと nginx 上でキャッシュ削除の設定ができるようになります。

Module ngx_http_proxy_module

おわりに

nginx + WordPress の環境で proxy_cache を有効にした際の覚書です。

有効にした結果ですが、レスポンスに 500ms 掛かっていたページが 50 - 100ms ほどに収まるようになりました。あまりプラグインなども入れていない簡素なテーマを使っているところなのですが WordPress って結構時間かかるんだなあ…。

今回のものはわりとシンプルなテーマ、プラグインの状況だったので設定することや考えることが少なかったのですが、マルチサイトやプラグインによる大幅な機能変更がついてくると、もっといろいろなことを考えないとうまくキャッシュすることが出来なくなりそうな予感がしています。

特に他人の情報が見えちゃうよ!とかはキャッシュあるあるかつ激ヤバ案件なので、そういった時には入念にテストも重ねて回避したいですね~。

1 2 3 4 5 6 7 8 9 10 11