質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.44%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

nginx

nginixは軽量で高性能なwebサーバーの1つです。BSD-likeライセンスのもとリリースされており、あわせてHTTPサーバ、リバースプロキシ、メールプロキシの機能も備えています。MacOSX、Windows、Linux、上で動作します。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

MariaDB

MariaDBは、MySQL派生のオープンソースなリレーショナルデータベースシステムです。 また、MySQLとほぼ同じデータベースエンジンに対応しています。

意見交換

クローズ

29回答

2268閲覧

データベースの負荷を下げたい

退会済みユーザー

退会済みユーザー

総合スコア0

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

nginx

nginixは軽量で高性能なwebサーバーの1つです。BSD-likeライセンスのもとリリースされており、あわせてHTTPサーバ、リバースプロキシ、メールプロキシの機能も備えています。MacOSX、Windows、Linux、上で動作します。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

MariaDB

MariaDBは、MySQL派生のオープンソースなリレーショナルデータベースシステムです。 また、MySQLとほぼ同じデータベースエンジンに対応しています。

0グッド

0クリップ

投稿2023/03/25 05:59

編集2023/03/25 12:18

0

0

実現したいこと

MySQL(MariaDB)へのinsert負荷を下げたく、
バルクインサートするための手法についてご意見をください。

前提

いわゆるLAMP環境のWebアプリにおいて、アクセスログに近いような機能を前提とします。
リアルタイムである必要はないが、数秒から長くても30秒以内のinsertが必要です。

具体的には、ユーザーのアクセスごとに、とあるログ(単純な文字列)の記録が必要で、ユーザー提供向けのものです。
updateでカウントしたり、後々バッチでまとめるようなものではない内容になります。

ユーザーIDがキーになりますので、パーティションを使って分割しています。
量としては月間1500万レコードほどで、今後さらに増えると思います。

取り出しイメージとしては、主キーで全て取り出すことが前提となるので、
そういった意味では、一時的にはKey-ValueのインメモリDBの方が向いているかと思いますが、
最終的には永続化が必要な要件のものになります。

現在都度insertする仕様につき、DBへのアクセス頻度が高く、
ホスティング側からごくごく稀に一時的に接続が拒否される状況です。

バルクインサートにより大幅に改善しそうだと考えておりますが、
どのような手法がよいか、また別のソリューションがあればご意見を伺いたいです。

尚、そもそも該当機能のサービス自体に問題があるのでは?、というご意見もあるかと思いますが、
あくまで今回はこちらの前提でのご意見をお願いします。

現在の構成

LB (nginx)
┣ Web(CentOS / nginx / PHP-fpm) ┳ DB (MariaDB)
┗ Web(CentOS / nginx / PHP-fpm) ┛

考えたこと

  • A. insert内容を一旦テキストファイル(ファイル名は30秒ごとの名称で生成)に追記していき、バッチ処理で中身をバルクインサートする。

→ ファイルI/Oに懸念あり(+バッチ処理と整合性維持に不安)

  • B. insert内容を一旦Redisやmemcachedに突っ込み、30秒ごとのバッチでMySQLへバルクインサート

→ Key-ValueDBなので、時間やカーソル範囲でselectできない?

  • C. 該当機能だけMySQL利用を諦め、Redisやmemcachedに切り替える

→ 短期的には最適だが、永続化が必要なので向いていない?
(また、できたとしてもディスク容量の懸念がある ※MySQLであれば無制限に容量拡張できるホスティング利用中)

PHPの詳細

  • Ver: 7.4 (8系に移行可能)
  • FW: Codeigniter4
  • ORM: mysqli (Codeigniterのクエリビルダ利用)

バルクインサートについて

目的は都度のinsertを (=都度のDB接続) 改善し、
まとめてinsert (=1回の接続で複数レコードをinsert) することです。
https://qiita.com/buntafujikawa/items/91283160b0a38956655e

ご相談内容は、その際の一時保記録先やその扱いについて、となります。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

回答29

#1

arcxor

総合スコア2857

投稿2023/03/25 06:55

INSERT 処理のリクエスト頻度が不明ですが、30秒も溜めるのは多すぎるように思います。

外部の一時ストレージを使うまでもなく、Webアプリ側(PHP)のオンメモリ上で Bulk Insert を実現するのが現実的ではないでしょうか。

お使いのPHPフレームワークやORMも不明ですが、単独で INSERT 処理していたメソッドをプロキシして、PHP側で INSERT 内容をキャッシュし、1000 件のリクエストが溜まるか30秒(秒数は要検討)が経過したら Bulk Insert するのが効率的かと思います。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#2

退会済みユーザー

退会済みユーザー

総合スコア0

投稿2023/03/25 07:43

>KEMONO_PANTSU_Zさん

ご回答ありがとうございます。
B案の下記懸念について、見解をお持ちでしたらお願いいたします。

→ Key-ValueDBなので、時間やカーソル範囲でselectできない?

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#3

退会済みユーザー

退会済みユーザー

総合スコア0

投稿2023/03/25 07:47

>arcxorさん

ご回答ありがとうございます。
なるほどですね、自身のメモリを使う発想がありませんでした。

http://docs.php.net/manual/ja/wrappers.php.php
こちらのことをおっしゃっていると思いますが、
これは単純なアクセスカウンターにも使えるという認識であっていますでしょうか?
例)count.phpを叩く度にカウントが上がって表示するだけのアプリ

知識不足なのですが、
スクリプト終了時に削除(メモリ解放)されてしまうものだと思っておりました。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#4

退会済みユーザー

退会済みユーザー

総合スコア0

投稿2023/03/25 07:49

>「プログラミングやITエンジニアに関係のない質問」という指摘をいただいた方

本質問(意見交換)のどのあたりが関係ない内容にあたるのか、
具体的にお知らせいただけますか?

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#5

dameo

総合スコア964

投稿2023/03/25 07:55

#5
不明点が多すぎるため、プログラミングやITエンジニア以前だと思ったので。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#6

arcxor

総合スコア2857

投稿2023/03/25 08:04

編集2023/03/25 08:20

#4
そのURLは何でしょうか。そのようなものは想定していませんでした。

オンメモリと言っているのは Bulk Insert のためのリクエストデータを一時保持する操作のみです。データが溜まったら実際に Bulk Insert すればよいのではと言っています。やろうとしていることは A, B 案と同様です。

おっと、すみません。そうですね、リクエストごとにメモリを共有できない限り、PHP だけでリクエストデータを一時保持しておくことはできないですね。勘違いしてしまいました。

となると、方針としては B 案が妥当でしょうか。

→ Key-ValueDBなので、時間やカーソル範囲でselectできない?

うーんと、これについては Key-Value ストアを選ぶ必要もないですが、時系列を保つ必要があるのでしょうか。だとしても 1000 件程度溜まったらそれらをすべて INSERT 処理するという方針では駄目なのでしょうか。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#7

yambejp

総合スコア115282

投稿2023/03/25 09:20

月間1500万件って平均しても1秒350件くらいありますよね?不可が高いときは1秒1万件くらいいくんでしょうか?
単一マシンのRDBで処理できる量ではないとおもいますが、クラスタ処理が前提になるのでは?

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#8

dameo

総合スコア964

投稿2023/03/25 09:31

#8
15000000 /30 / 24 / 60 / 60 = 平均約5.8件/秒ですね

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#9

yambejp

総合スコア115282

投稿2023/03/25 09:49

#9

おっと、1秒→1分間でした

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#10

退会済みユーザー

退会済みユーザー

総合スコア0

投稿2023/03/25 11:37

編集2023/03/25 11:49

#6
タイトルにある「データベース」というキーワードの時点で、
「関係はある」と判断すべきだと思いますが。

もちろんそのあたりのご判断はご本人のスキルや主観によるものとは思いますが、
少なくとも不明点が多いからという理由で、
「プログラミングやITエンジニアに関係のない質問」という判断は理解できません。

建設的に質問にお答えいただけるおつもりがあるのでしたら、
不明点(不足)について補足しますので、具体的にご指摘ください。
そうでない場合は、レスを控えていただけると幸いです。

追記:#9 について、ありがとうございました。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#11

退会済みユーザー

退会済みユーザー

総合スコア0

投稿2023/03/25 11:40

編集2023/03/25 11:56

#7
ありがとうございます。

時系列を保つ必要があるのでしょうか。だとしても 1000 件程度溜まったらそれらをすべて INSERT 処理するという方針では駄目なのでしょうか。

時系列は保つ必要がありません。
ご指摘通りだと思いますが、その1000件の溜め方の手法に悩んでおりました。

いただいたご意見はAに近いのかなと思いますが、
その場合、下記が気になっておりました。(ファイルI/O)

A. insert内容を一旦テキストファイル(ファイル名は30秒ごとの名称で生成)に追記していき、バッチ処理で中身をバルクインサートする。
→ ファイルI/Oに懸念あり(+バッチ処理と整合性維持に不安)

すいません、きちんと読解できておりませんでしたので、追記します。

1000 件程度溜まったらそれらをすべて INSERT 処理するという方針では駄目なのでしょうか。

key-valueストア採用の場合、定期的に件数をチェックして、
件数が1000件程度なら全てKeyを一度記録して、MySQLにバルクインサート、
成功したら該当Keyのレコードを全て削除するといったことが想定されるでしょうか?(整合性をとるため)

その辺り理論上はできそうだなとは思うのですが、
RDBと違って、あくまでKeyからvalueをとりだすだけのDBなので、
カレントを指定するような用途には不向きのようにも思えてしまい。。
(他にやり方があるようでしたらすみません)

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#12

退会済みユーザー

退会済みユーザー

総合スコア0

投稿2023/03/25 11:43

編集2023/03/25 11:47

#8
ありがとうございます。

月間1500万件って平均しても1秒350件くらいありますよね?不可が高いときは1秒1万件くらいいくんでしょうか?

計算については他の方からご指摘がありましたが思いますが、
現在のRDB(フルマネージド)でピーク時も耐えられております。
データベース自体は余裕で耐えられていますが、ごくごく稀にDBへの接続回数が原因(サービス側のリミット制約)で拒否されています。

内部はクラスタになっているようです。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#13

dameo

総合スコア964

投稿2023/03/25 11:54

#11
関係ありません。あなたの技量で扱える話題ではないように見えるということです。

  • 速度を問題としているのに、目標だけで実測値がない
  • 環境の開示がほぼない
  • 目標時間があるのにデータの構造や規模感を伝える指標が行数しかない
  • クエリの説明がない
  • なぜバルクインサートに拘ってるのか不明(一度に送れるなら送ればいい程度のもの)
  • トランザクションの有無に記述がない(トランザクションくらいあるのですよね?)
  • 並行して動作しているトランザクションの説明がない
  • 案が箱だけ用意するもので、実現手段の考慮がない
  • あなた自身の技量の説明がない

以上から、本件の「遅い原因」を推測する手段がありません。
他にも疑問符だらけの記載なので、「プログラミングやITエンジニアに関係ない」とさせて頂きました。

話を聞く限りでは、迷うことなく普通に適切な小さいテーブル(できればロギングを外す)を用意して、そこからinsert selectして比較すればいいだけに見えます。しかし、その判断をするのにすら情報が足りません。

繰り返しますが、「プログラミングやITエンジニアに関係ない」です。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#14

退会済みユーザー

退会済みユーザー

総合スコア0

投稿2023/03/25 12:04

編集2023/03/25 12:11

#15

あなたの技量で扱える話題ではない

それは別問題では?
仮にそうだとして、データベースの議題を扱っている以上は、
「プログラミングやITエンジニアに関係ない」は無理があると思いますが。

私が自分のスキルで扱えないITに関する質問をしたら、
それは「プログラミングやITエンジニアに関係ない」ということになる理屈が理解できませんでした。

このサービスはITに関する自分で解決できないことを質問し、
わかる人が回答するサービスだと思いましたが私の勘違いでしたでしょうか。

以上から、本件の「遅い原因」を推測する手段がありません。

遅いとはどこにも書いていませんよ。
質問内容は「DBへの接続回数を下げたい」です。
理由も下記のように書いています。

現在都度insertする仕様につき、DBへのアクセス頻度が高く、
ホスティング側からごくごく稀に一時的に接続が拒否される状況です。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#15

dameo

総合スコア964

投稿2023/03/25 12:05

編集2023/03/25 12:05

#15
いや、こういうやり取りになるので、「プログラミングやITエンジニアに関係ない」のですよ。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#16

退会済みユーザー

退会済みユーザー

総合スコア0

投稿2023/03/25 12:08

#16
それはあなたの勘違いと独断と偏見による論点ずらしの結果論です。
通報しましたので対処は運営に任せます。
迷惑なのでこれ以上の回答はお控えください。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#17

dameo

総合スコア964

投稿2023/03/25 12:21

編集2023/03/25 12:22

#17
あなたに聞かれたこと(#5)に答えただけですよ。論点をずらしているのは終始あなたですよね。

不明点をあげたのに「全て」を明快にする前に返信してたら先に進むものも進みません。ただ、この話題を扱える技量があるかどうか疑問のあるあなたがちゃんと理解して実施できるかは不明ですが。。。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#18

fiveHundred

総合スコア9945

投稿2023/03/25 12:42

全くの専門外が横やりで指摘しますが、「プログラミングやITエンジニアに関係ない」に該当するかどうかはともかく、「回答する上で必要な情報を提示しない」ということは、「他の回答者も適切に回答できない」事態を招きますし、最悪「問題を解決する気がない」とされても文句は言えません。
逆に提示すれば、他の人が回答しやすくなったり、適切な回答を得やすくなったりといったメリットがあります。

mahomahoさんはどちらがいいのでしょうか?

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#19

退会済みユーザー

退会済みユーザー

総合スコア0

投稿2023/03/25 13:01

#19
ごもっともだと思いますが、
私は不足があれば追記していますし、回答もしています。

そして不足があれば「修正依頼」という機能がありますので、
そちらから指摘するのがTeratailのルールだと思います。

今回は「プログラミングやITエンジニアに関係ない」という指摘にがありましたので、
修正するために具体的にどこが関係ないのか質問したところが発端となります。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#20

dameo

総合スコア964

投稿2023/03/25 13:09

#20
具体的な指摘をしてたらキリがなさそうだから、「プログラミングやITエンジニアに関係ない」ということなのですよ。再掲しますが、現在全ての項目が不明です。

#14より引用

  • 速度を問題としているのに、目標だけで実測値がない
  • 環境の開示がほぼない
  • 目標時間があるのにデータの構造や規模感を伝える指標が行数しかない
  • クエリの説明がない
  • なぜバルクインサートに拘ってるのか不明(一度に送れるなら送ればいい程度のもの)
  • トランザクションの有無に記述がない(トランザクションくらいあるのですよね?)
  • 並行して動作しているトランザクションの説明がない
  • 案が箱だけ用意するもので、実現手段の考慮がない
  • あなた自身の技量の説明がない

やはりご理解頂けてなかったようですね。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#21

退会済みユーザー

退会済みユーザー

総合スコア0

投稿2023/03/25 13:33

>「調査したこと・試したことが記載されていない質問」とご指摘いただいた方

ありがとうございます。
本件は「Q/A」ではなく「意見交換」と設定して起票しております。

調査したことについては、「考えたこと」に記載しております。
試したことは、実環境という意味であれば、ありません。

実環境で試す前にご意見を伺いたかった、というところです。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#22

dameo

総合スコア964

投稿2023/03/25 15:20

編集2023/03/25 15:24

本当に建設的な話のできない、無責任で手を動かせない=技量のない人ですね。

まず、

  • 速度を問題としているのに、目標だけで実測値がない

データベース負荷に問題=速度を問題としているなら、秒間5.8件の登録が間に合わないということになります(それだけしか情報がないので)。そして、

ホスティング側からごくごく稀に一時的に接続が拒否される

この「ホスティング側」?これ何だか分からないんですよ。環境の説明もないですしね。この一文は普通無視します。

→(仮定)よく分かりませんが、環境説明の罫線がインターネットであると仮定し、クライアント-Webサーバー-DBがそれぞれインターネット越しに繋がっているとし、なぜかDBをホストしているサービスが接続頻度の高さから(?)(どの程度なのかも不明)接続をリセットしてきているとする

  • 環境の開示がほぼない

なんだか下のテキストを書いてるようですが、

LB (nginx)
┣ Web(CentOS / nginx / PHP-fpm) ┳ DB (MariaDB)
┗ Web(CentOS / nginx / PHP-fpm) ┛

これ別にdockerで1台で動かせますよね?クラウドですか?VPSですか?それともベアメタル(物理)ですか?
→(仮定)4台で動かしていると仮定する

ネットワークとかホスティングはどこの話なのでしょう?
→(仮定)罫線はインターネットと仮定し、ホスティングはLBとWebとDBでそれぞれ違うサービスを使っているとする

クライアントは何台で、ホストは何台ですか?
→(仮定)クライアントは∞台で、ホストは4台とする

ファイルシステムは共有してないんですか?
→(仮定)共有していないものとする

まさか共有サーバーじゃないですよね?
→(仮定)違うと仮定する

DBは同じサーバーですか?別のサーバーですか?インターネット越しですか?
→(仮定)違うサーバーでインターネット越しとする

サーバーの性能はどの程度ですか?スペックを明確にしてください。
→(仮定)以下とする

  • LB: Intel(R) Xeon(R) CPU E5-2640 v4 @ 2.40GHz メモリ1GB HDD50GB
  • Web: Intel(R) Xeon(R) CPU E5-2640 v4 @ 2.40GHz メモリ1GB HDD50GB
  • DB: 不明

まるで分からないので、仮定しちゃいました。

  • 目標時間があるのにデータの構造や規模感を伝える指標が行数しかない

秒間5.8件の登録時間だけしかわからず、テーブルの数、インデックス、カーディナリティ、レコード長など基本的な指標がありません。せめて1月分のデータサイズとかを出すと思いますよね?ありませんけど。環境の説明がない=速度に問題があると考えざるを得ないのでこうなります。

→(仮定)速度に問題はないので気にしないが、80バイト x 1500万 x 1.2(適当) = 1.4GBとします。ユーザーと日付にインデックスを付ける、とする。パーティションがユーザーなのはログという性質から言うとあまりよろしくない。

まあ問題があろうとかなろうと説明がいるんですけどね。

  • なぜバルクインサートに拘ってるのか不明(一度に送れるなら送ればいい程度のもの)

バルクインサートは特殊な用途を除き、主に転送を少しでも速くするために使うものです。今回のような要件では別に普通のインサートで構いません。速度的にも問題ないし、接続回数的にも関係ないと思います。
→(仮定)反応ないので質問者はトランザクションとか聞いたこともないとする

トランザクションの有無に記述がない(トランザクションくらいあるのですよね?)

→(仮定)反応ないので質問者はトランザクションとか聞いたこともないとする

これが肝です。接続云々を言ってる割にこの記述がありません。phpで持続的接続を使っていますか?(問題は多いようですが)
→トランザクション使っておらず、持続的接続も(fpm使ってて問題が起きてるのだから、他の仮定から)使ってないとする

  • 並行して動作しているトランザクションの説明がない

問題の発生箇所という点ではインサート以外のトランザクション、もしくは同じデータベースインスタンスの別のテーブルを使用するWebアプリなども影響しますが、それが存在するのかすら分かりません。同じテーブルについても記載がありません。
→(仮定)ログならインサート以外の処理はほぼ存在しないものとする。適当に月単位でダンプしてどこかよそで使えばいいだけ。

案が箱だけ用意するもので、実現手段の考慮がない

KVSを使う?使ってどうするの?など、意味の分からないレベルでの案しかありません。他の情報が明快でない点もあり、推測もできません。
→(仮定)荒唐無稽な案は検討の価値なしとする

あなた自身の技量の説明がない

ここまでやらかしてると、説明が必要です。伝わらない場合に今みたいな無駄な文章を記述する必要がでてきます。
→(仮定)付ける薬もないようなので仮定で結論を急ぐ

結論)
各仮定よりWebサーバーで何らかのタメが必要。

案1) お手軽にsqlite3を使う

  • 各Webサーバーはsqlite3を使ってトランザクションで書き込んでタメを作る(fpmはプロセス分同じDBに書き込む)
  • 各Webサーバー上でcron起動するプロセスでsqlite3のデータをトランザクションで吸い出してMariaDBに書き込み(異常系を考慮しupsertで書き込む)、sqlite3上のデータを削除してコミットする

案2) phpで持続的接続を使う
php自体の対応がイマイチなのでちょっと危険。自分で調べて。

案3) ファイルに保存する
あんまり大事なデータでなく異常事態では壊れても良ければ。処理は案1と一緒。ロックはファイルロック。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#23

退会済みユーザー

退会済みユーザー

総合スコア0

投稿2023/03/25 16:10

#23
「迷惑なのでこれ以上の回答はお控えください。」とお願いしたのですが、理解いただけませんでしたか?
あなたの回答は非常に不快なので、心の底からこれ以上関わりたくないんですよ。

とはいえ、文句を言いつつ、決めつけと侮辱をし、マウントを取りながらも、
回答いただいたことはありがとうございます。参考にさせていただきます。

あなたに対する反応は本当にこれで以上としますので、何卒、よろしくお願いいたします。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#24

dameo

総合スコア964

投稿2023/03/25 16:16

#24
結局理解できなかったようですね。

お控えくださいというのは、あなたの希望であって、私はあなた以外の人が困っていそうなので、助け舟を出したに過ぎません。決めつけと侮辱とマウントをしたがってるのはあなたであって、私は嫌がられるのを承知で、損な役回りを引き受けてるだけに過ぎません。知識が足りず理解力が低くなるのは仕方ないのですが、それに甘えて意固地になるのはどうかと思いますよ。

あと、反応が大げさ。まあこれで少しは他の皆さんとお近づきになれる前提は増えたでしょう。それでは。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#25

退会済みユーザー

退会済みユーザー

総合スコア0

投稿2023/03/25 19:58

#23

案1) お手軽にsqlite3を使う

Dockerにて実環境と同様の環境を構築し、
同等の負荷をかけたところ、頻繁にロックの影響を受けましたが、
ジャーナリング方式をWALに変更したところ、改善しましたので採用させていただきます。

ありがとうございました。


案2) phpで持続的接続を使う

想定される全ての問題に対処できる自信がないため見送りました。

案3) ファイルに保存する

ファイルI/Oの懸念が払拭できるレベルで対策する能力がないため見送りました。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#26

dameo

総合スコア964

投稿2023/03/25 20:43

これは独り言です。きちんと情報を開示し、前提が明確になり、実際の原因(接続リセットされる原因)が分かり、それに即した具体的な案から十分な検証をして採択する、という当たり前のプロセスもなく、環境も不明、前提も不明、原因も不明なまま、全くコードも出さずに意味不明な対策だけ決まるという前例だけが出来てしまいました。同じような問題を調べた人の参考になろうと皆で知識を出し合い、共有した問題を皆で解決し、何かしらの道標を残すべくこのような場があるというのに、質問者がただただワガママ放題するために皆が振り回されただけという、180度違う結果に終わったということです。残念ですね。

だから「プログラミングやITエンジニアに関係ない」のですよ。ここまで読んだ方お疲れ様。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#27

dameo

総合スコア964

投稿2023/03/26 22:19

編集2023/03/26 22:21

今回の件で調べられる部分があるとしたら、sqlite3の速度くらいなので、調べた結果だけ最後に載せておきます
(誰でも再現可能というだけで大したものじゃない。でもこれが本当に大事)。

動作環境

  • UnixライクなOS
  • docker と docker-compose(新しくないやつ)が動く
  • 実行ユーザーがdockerグループに入っていてsudoがいらない
  • bashが動く
  • 動かなかったらすみません

出来ること

  • nginxとphp8(fpm)という2つのコンテナを動かせる
  • http://localhost:8080/hoge.php にアクセスすると、phpコンテナ内の/home/www-data/test.db上のhogeテーブルに1レコードインサートできる
  • /home/www-data/のmulti_for_php.shを実行すると、指定された並列数で1000回上記URLを叩く(その際journal_modeが指定できる)
  • 環境構築スクリプトが付いている(デバッグなし)、構築と同時に測定も実施する

環境構築スクリプト

空のディレクトリで実行すると、構築と同時に測定も実施
測定内容は、multi_for_php.shを1~5並列、journal_mode=delete/walの2パターンの全組み合わせで実施するだけ。

AMD Ryzen 5 1400/4GB/Ubuntu 20.04 amd64(Win10上のVirtualBox)

リクエストx並列数delete[秒]wal[秒]
1000 x 110.30511.553
1000 x 219.12814.810
1000 x 329.36420.078
1000 x 441.75926.181
1000 x 547.10230.614

bash

1cat >docker-compose.yml <<EOF 2version: "3.1" 3services: 4 php: 5 build: . 6 volumes: 7 - ./html:/var/www/html 8 - ./php.ini:/usr/local/etc/php/php.ini 9 - ./www-data:/home/www-data 10 nginx: 11 image: nginx 12 restart: always 13 ports: 14 - 8080:80 15 volumes: 16 - ./html:/var/www/html 17 - ./php-fpm.conf:/etc/nginx/conf.d/default.conf 18EOF 19cat >Dockerfile <<EOF 20FROM php:8-fpm 21RUN apt-get update && docker-php-ext-install pdo_mysql 22RUN pecl install xdebug \\ 23 && docker-php-ext-enable xdebug 24EOF 25cat >php-fpm.conf <<EOF 26server { 27 listen 80; 28 server_name localhost; 29 root /var/www/html; 30 client_max_body_size 20M; 31 index index.php; 32 location / { 33 try_files \$uri \$uri/ /index.php?\$args; 34 } 35 rewrite /wp-admin$ \$scheme://\$host\$uri/ permanent; 36 location ~ [^/]\.php(/|$) { 37 fastcgi_split_path_info ^(.+?\\.php)(/.*)$; 38 if (!-f \$document_root\$fastcgi_script_name) { 39 return 404; 40 } 41 include fastcgi_params; 42 fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name; 43 fastcgi_param PATH_INFO \$fastcgi_path_info; 44 fastcgi_param PATH_TRANSLATED \$document_root\$fastcgi_path_info; 45 fastcgi_pass php:9000; 46 fastcgi_index index.php; 47 fastcgi_keep_conn on; 48 } 49} 50EOF 51cat >php.ini <<EOF 52[PHP] 53upload_max_filesize=20M 54post_max_size=20M 55#[xdebug] 56#xdebug.mode=debug 57#xdebug.start_with_request=yes 58## ホストIPを指定すること 59#xdebug.client_host=10.0.2.15 60#xdebug.client_port=9003 61#xdebug.log=/tmp/xdebug.log 62#zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20220829/xdebug.so 63EOF 64mkdir html 65cd html 66cat >hoge.php <<EOF 67<?php 68function test() { 69 try { 70 \$start_time = microtime(true); 71 \$sqlite = new SQLite3('/home/www-data/test.db'); 72 \$sqlite->busyTimeout(30000); 73 \$sqlite->exec('begin'); 74 \$sqlite->exec('insert into hoge default values'); 75 \$sqlite->exec('commit'); 76 \$end_time = microtime(true); 77 echo (\$end_time - \$start_time) . "\\n"; 78 } 79 catch(Exception \$e) { 80 echo "->Failed\\n"; 81 echo \$e->getMessage()."\\n".\$e->getTraceAsString()."\\n"; 82 } 83 finally { 84 \$sqlite->close(); 85 } 86} 87if (php_sapi_name() !== 'cli') { 88 echo "<pre>"; 89} 90test(); 91EOF 92cd .. 93mkdir www-data 94chmod a+w www-data 95cd www-data 96cat >hoge.sql.sh <<EOF 97php sqlite3.php exec "pragma journal_mode=wal;" 2>/dev/null 98php sqlite3.php exec "create table hoge(id integer primary key autoincrement, create_at text default (strftime('%Y/%m/%d %H:%M:%f', 'now')))" 2>/dev/null 99EOF 100cat >sqlite3.php <<EOF 101<?php 102function test(\$type, \$sql) { 103 try { 104 \$sqlite = new SQLite3('/home/www-data/test.db'); 105 \$sqlite->busyTimeout(30000); 106 if (\$type == "exec") { 107 \$sqlite->exec(\$sql); 108 } else { 109 \$results = \$sqlite->query(\$sql); 110 while (\$row = \$results->fetchArray(SQLITE3_NUM)) { 111 echo implode("\\t", \$row); 112 echo PHP_EOL; 113 } 114 } 115 } 116 catch(Exception \$e) { 117 echo "->Failed\\n"; 118 echo \$e->getMessage()."\\n".\$e->getTraceAsString()."\\n"; 119 } 120 finally { 121 \$sqlite->close(); 122 } 123} 124if (php_sapi_name() !== 'cli') { 125 echo "<pre>sapi not supported."; 126} else { 127 test(\$argv[1], \$argv[2]); 128} 129EOF 130cat >client.php <<EOF 131<?php 132\$get_curl = curl_init(); 133curl_setopt(\$get_curl, CURLOPT_URL, 'http://nginx/hoge.php'); 134for (\$i = 0; \$i < 1000; ++\$i) { 135 \$get_response = curl_exec(\$get_curl); 136 if (\$get_response === false) { 137 echo curl_error(\$get_curl); 138 break; 139 } 140} 141curl_close(\$get_curl); 142EOF 143cat >multi_for_php.sh <<EOF 144count=\$1 145journal_mode=\$2 146name=\$(basename \$0) 147pid=\$\$ 148calc() { 149 awk "BEGIN {print \$*;}" 150} 151php sqlite3.php exec "delete from hoge" 2>/dev/null 152php sqlite3.php exec "vacuum" 2>/dev/null 153php sqlite3.php exec "pragma journal_mode=\$journal_mode;" 2>/dev/null 154for i in \$(seq \$count); do 155 (time php client.php) 1>/dev/null 2>\$name.\$pid.\$i.log & 156done 157wait 158cat \$name.\$pid.*.log 159rm \$name.\$pid.*.log 160if [ "\$(php sqlite3.php query 'select count(*) from hoge' 2>/dev/null)" != "\$(calc 1000 \\* \$count)" ]; then 161 1>&2 echo "ERROR: insert failed!" 162fi 163EOF 164cd .. 165docker-compose up -d 166sleep 10 167docker-compose exec -T -u 33 php bash -c 'cd /home/www-data;bash hoge.sql.sh' 168for t in delete wal;do 169 docker-compose exec -T -u 33 php bash -c 'cd /home/www-data;for i in $(seq 5);do time bash multi_for_php.sh $i '$t' >/dev/null;done' 170done 171docker-compose down

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#28

tekka

総合スコア514

投稿2023/03/28 12:11

Bと被りますが、ディスクへの書き出しとの間に、メッセージキューなどのバッファを挟むべきと思います。
例えばfluentdの場合、同じ端末上のサービス間のデータ転送はメモリ転送になるのですが
いったんfluentdのメモリ領域に蓄積し、キューの先頭からMySQLなどディスクに書き出していくことで
ディスクIOを均し、書きこぼしを無くすことができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#29

dameo

総合スコア964

投稿2023/03/28 12:49

#28
これも要件次第なのですが、何かのリクエストを受けログ書き込みが必要なものだった場合、正常なレスポンスを返したら確実にMariaDBまで届くことを前提とするシステムとするかどうかが問題なのですよ。

仮にそうした前提のあるシステムでレスポンスを返した直後にタメてる部分がコケた場合、その障害から復帰した際に復旧できないといけません。メモリ上にキューイングしただけのシステムである場合、そのデータはただ消えてしまい、MariaDBに届くことはないでしょう。クライアント側には正常応答しているので、それはデータ欠損という致命的な不具合になります。つまり前提がそうであれば、ジャーナルであれなんであれ、どこかで永続化されている必要がある=ディスクに書き込まれるまでクライアントにレスポンスを返せないということになります。

まあ、そうした要件は書いていないので、消えてもいいという前提は付けるべきではないと思いますよ。質問はそれ以前の内容ですけど。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

最新の回答から1ヶ月経過したため この意見交換はクローズされました

意見をやりとりしたい話題がある場合は質問してみましょう!

質問する

関連した質問