なんとな~くしあわせ?の日記

「そしてそれゆえ、知識そのものが力である」 (Nam et ipsa scientia potestas est.) 〜 フランシス・ベーコン

EntityとDto

EntityとDto

  • Dtoについてこれまで誤解していたことと、本来の使われ方について書く

EntityとDtoの違い

TL;DR:
  • エンティティはビジネスドメインの一部でありうる。それゆえ、それには振る舞いとドメイン内での異なるユースケースに適用される
  • DTOはある処理や他の文脈への転送のためだけに使われる。例えば、それらには振る舞いがない;つまりとても基本的で大抵標準化されている保存と取得のための関数しか実装されていない*1
長い解説
  • "Data Transfer Object(DTO)" がとても不明瞭に定義されているのに対して、"Entity" は様々な文脈で異なる解釈をされている
  • "Entity"という用語にもっとも関連のある解釈は、私の意見としては以下の3つになる:
    • エンタープライズJavaJPAの文脈において:「データベースの中で保守される永続化データを表すオブジェクト」
    • ドメイン駆動開発の文脈において(Eric Evansの発言):「属性よりもその同一性によって主要に定義されるオブジェクト」
    • クリーンアーキテクチャの文脈において(Robert C. Martinの発言):「エンタープライズ横断的に重要なビジネスルールをカプセル化したオブジェクト」

JEEやJPAコミュニティはエンティティをもっぱらデータベースのテーブルにマッピングするものとして見ている。この見方はDTOの定義に非常に近い。そしてこれがこの混乱の元になっているのかもしれない。ドメイン駆動開発の文脈においては(というのはRobert Martinの見方だが)、エンティティはビジネスドメインの一部でそれゆえに振る舞いを実装すべきなのだということだ。

Data Transfer Objectの本来の意味

  • P of EAA: Data Transfer Object
    • マーティンファウラーのサイトから
    • もともとのDTOは、リモートアクセスの呼び出しコストが高い状況において呼び出しを1つのDTOでまとめておくことで呼び出し回数を減らすことが目的だったようだ

まとめ

  • 今まで経験したJavaのアプリケーション開発では、DTOはテーブルとマッピングさせて使われることが多かったように思う。そしてそれは呼び出しをまとめるという初期の目的は失われている。たぶんEntityのような意味でDTOという名づけをするのは誤用ではないだろうか?
  • ついでに言うとDTOとDAOを作成するプロジェクトはDTOのコピーでバグがよく発生していた。それは単にビジネスロジックを書く部分がダメだっただけかもしれないが

*1:getterやsetterのこと

Apacheの同時接続スレッド数

  • 表題の件を調べることになった、このページには最終的な手順のみ残す

workerで動いてるか、preforkで動いてるか確認

  • Apacheのプロセス管理がなんのモジュールで行われているか確認する
$ apachectl -l
Compiled in modules:
  core.c
  worker.c
  http_core.c
  mod_so.c

この場合workerで確定。worker, preforkが何であるかについてはググってください。

プロセス・スレッド設定を確認する

  • /etc/httpd/conf/httpd.conf を確認する
    • IfModule worker.cで囲われた部分がworkerの設定、IfModule prefork.cにはpreforkの設定が書いてある
ServerLimit 16
StartServers 2
MaxClients 200
MinSpareThreads 25
MaxSpareThreads 75
ThreadsPerChild 25
TL;DR
  • 上の場合ApacheMaxClients 200の設定で動くので、同時接続ユーザは最大200になる
  • 上限をあげたい場合はServerLimitMaxClientsの数値を上げれば良い
詳しい説明
  • 最初に、Apacheが起動した時はいつでもStartServersのパラメーターで定められた2つの子プロセスが起動する
  • そして、そのいずれのプロセスでもThreadsPerChildのパラメーターで定められた25スレッドが起動する、これは2つのプロセスが50の同時接続/クライアントに対してのみ提供されるということを意味する(つまり25x2=50)
  • より多くの同時接続ユーザがきたとすると、その時他の子プロセスが起動する。それはまた新たに25ユーザにページを表示させられる。
  • しかし子プロセスを何個起動させられるかどうかはServerLimitパラメータでその総数が制御されている、どの子プロセスも25スレッド操作できるとすると、実行できるスレッドの総数は16x25=400の同時接続ユーザだ
  • しかしMaxClientsが200以下で定義されていると(これは8つの子プロセスを意味するのだが)、MaxCilientsで上限が設定されていることになるので新しいプロセスを起動できないことになる
  • これはまた、もしもMaxClientsを1000で設定(これは16の子プロセス、400接続を意味する)しても、新しいプロセスを起動させることができない(※ここの英語しつこい)
  • この場合はServerLimitを1000/25、つまりMaxClients/ThreadsPerChild=40で設定することで同時接続1000ユーザに最適化された設定を実現できる

VisualVMが使ってみるとけっこうよかった件

visualvm.github.io

仕事で負荷試験などを行ったのだが、ボトルネックがどこであるか非常にわかりやすい。

ボトルネックの見つけ方

  • ローカル環境 or JMXのポートを開けた環境でアプリケーションを起動する
  • VisualVMで対象のアプリケーションの環境につなぐ
  • サンプラー or プロファイラを起動しておく
  • アプリケーションに対して負荷をかけたりリクエストをやる
  • サンプラー or プロファイラを見て分析する

VisualVMでできること

  • WEBアプリケーションのスレッドごと、コールスタックごとのCPU処理時間算出
  • WEBアプリケーションのSQLクエリの呼び出し回数とコールスタックと処理時間算出
コールスタック
  • コールスタックとは関数の呼び出し履歴をツリー形式で見ることができるようにしたもので、どの関数でどのくらい時間がかかっているかとてもわかりやすい
気付きなど
  • 意外にJavaのロジックで重そうであっても時間がかからない(レコードが10万程度にならないと繰り返し処理で問題が出ることはない)
  • DBの呼び出しをできるだけへらすことがパフォーマンス向上につながる
  • そういう意味ではキャッシュの実装もパフォーマンス向上に有効