patorashのブログ

方向性はまだない

pgbenchをとりあえず使ってみた

勉強をしているので、pgbenchを使ってみた。pgbenchはPostgreSQLベンチマークツール。

lets.postgresql.jp

ただし、pgbenchは厳密な意味でのベンチマークツールではありません。TPC(http://www.tpc.org)などで「公式」に認められているような性能測定を行う目的には向いていません。その点はご注意下さい。

とあるので、あくまでも公式ではない点に注意。

yumpostgresql-contribをいれてあるので、pgbenchはもう使える状態になっていた。入ってない場合は入れること。

sudo yum install postgresql-contrib

pgbenchを試す

データベースを作成する

pgbenchを実行するためのデータベースを作成する。postgresユーザになってから作業すると楽。

sudo -i -u postgres

データベースを作る

createdb benchdb

pgbench用にデータベースを初期化する

-iオプションで、初期化される。-sオプションに数字を渡すと、サンプルデータ量が増える。デフォルトで10万件なので、-s 10にすると100万件入る。-fでフィルファクターの値も指定できるらしい。とりあえず最初なので、素のままにする。

pgbench -i benchdb

以下のように、テーブルを再作成してデータを突っ込んで完了。

-bash-4.2$ pgbench -i benchdb
dropping old tables...
creating tables...
generating data...
100000 of 100000 tuples (100%) done (elapsed 0.11 s, remaining 0.00 s)
vacuuming...
creating primary keys...
done.

測定する

以下のコマンドで測定可能。ただし、オプションがない状態だと、ほとんど参考にならない(らしい)。今回はpgbenchがちゃんと動くことを確認するために一旦何もなしで動かす。

pgbench benchdb

結果は以下の通り。

-bash-4.2$ pgbench benchdb
starting vacuum...end.
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 1
query mode: simple
number of clients: 1
number of threads: 1
number of transactions per client: 10
number of transactions actually processed: 10/10
latency average = 3.660 ms
tps = 273.251220 (including connections establishing)
tps = 319.517166 (excluding connections establishing)

TPS(一秒あたりのトランザクション数)の値が、性能を表す。これが高ければ高いほど良い。

項目 項目の説明
scaling factor 1 DBを初期化したときのデータ量。-sの値。デフォルトで1(10万件)
query mode simple クエリモード(simple | extends | prepared)
number of clients 1 同時接続クライアント数
number of threads 1 接続スレッド数
number of transactions per client 10 1クライアント辺りのトランザクション
number of transactions actually processed 10/10 正常終了したトランザクション
latency average 3.660ms 遅延時間
tps(including connections establishing) 273.251220 PostgreSQLに対する接続を確立する時間を含んだTPS
tps(excluding connections establishing) 319.517166 PostgreSQLに対する接続を確立する時間を含まないTPS

オプションを渡すことで様々な条件で検証できる。更新を含むトランザクションを発行するが、更新を含まないようにするオプションもある。参照用DBの場合には有効だ。

また、デフォルトだとpgbenchの条件で作られたテーブル構造でしかテストできないが、テーブル定義と発行したいクエリさえ準備できれば、pgbench経由で検証することが可能らしいので、実際のテーブル定義などを準備して本番に近い形で負荷試験をすることも可能っぽい。ただ、それは準備が相当大変になるだろう…。

どういうふうに検証を進めていけばいいのか?

これが正直わからない。 恐らく、

  1. 想定接続数とトランザクション数を徐々に増やしつつ、トランザクションが全て成功した上で最もTPSが出たところを基本にする。
  2. postgresql.confの項目を1つ修正する。
  3. ベンチマークを取り直す。
  4. TPSが上がったら設定を生かす。そうでなければ違う値にするか元に戻す。

を地道に繰り返すのかなぁ~と思う。

いい方法があれば教えていただきたい。

後日、postgresql.confを修正してからやったものなどを書いてみようと思う。

Amazon Linux2にPostgreSQL11を入れる

Hyper-V環境のAmazon Linux2にPostgreSQLをインストールしようとしたらちょっとハマったのでメモを残す。

Amazon Linux2でyumPostgreSQLを入れようとすると、9.2という古いものが出てくる。

新しいものを入れるには、amazon-linux-extrasを使う。listと打つと、利用可能なものが表示される。postgresqlも9.6や10や11などが準備されている。今回は11を入れた。

[ec2-user@postgres ~]$ amazon-linux-extras install postgresql11
[ec2-user@postgres ~]$ amazon-linux-extras list
  0  ansible2                 available    \
        [ =2.4.2  =2.4.6  =2.8  =stable ]
  2  httpd_modules            available    [ =1.0  =stable ]
  3  memcached1.5             available    \
        [ =1.5.1  =1.5.16  =1.5.17 ]
  5  postgresql9.6            available    \
        [ =9.6.6  =9.6.8  =stable ]
  6  postgresql10             available    [ =10  =stable ]
  8  redis4.0                 available    \
        [ =4.0.5  =4.0.10  =stable ]
  9  R3.4                     available    [ =3.4.3  =stable ]
 10  rust1                    available    \
        [ =1.22.1  =1.26.0  =1.26.1  =1.27.2  =1.31.0  =1.38.0
          =stable ]
 11  vim                      available    [ =8.0  =stable ]
 13  ruby2.4                  available    \
        [ =2.4.2  =2.4.4  =2.4.7  =stable ]
 15  php7.2                   available    \
        [ =7.2.0  =7.2.4  =7.2.5  =7.2.8  =7.2.11  =7.2.13  =7.2.14
          =7.2.16  =7.2.17  =7.2.19  =7.2.21  =7.2.22  =7.2.23
          =7.2.24  =7.2.26  =stable ]
 17  lamp-mariadb10.2-php7.2  available    \
        [ =10.2.10_7.2.0  =10.2.10_7.2.4  =10.2.10_7.2.5
          =10.2.10_7.2.8  =10.2.10_7.2.11  =10.2.10_7.2.13
          =10.2.10_7.2.14  =10.2.10_7.2.16  =10.2.10_7.2.17
          =10.2.10_7.2.19  =10.2.10_7.2.22  =10.2.10_7.2.23
          =10.2.10_7.2.24  =stable ]
 18  libreoffice              available    \
        [ =5.0.6.2_15  =5.3.6.1  =stable ]
 19  gimp                     available    [ =2.8.22 ]
 20  docker=latest            enabled      \
        [ =17.12.1  =18.03.1  =18.06.1  =18.09.9  =stable ]
 21  mate-desktop1.x          available    \
        [ =1.19.0  =1.20.0  =stable ]
 22  GraphicsMagick1.3        available    \
        [ =1.3.29  =1.3.32  =1.3.34  =stable ]
 23  tomcat8.5                available    \
        [ =8.5.31  =8.5.32  =8.5.38  =8.5.40  =8.5.42  =8.5.50
          =stable ]
 24  epel                     available    [ =7.11  =stable ]
 25  testing                  available    [ =1.0  =stable ]
 26  ecs                      available    [ =stable ]
 27  corretto8                available    \
        [ =1.8.0_192  =1.8.0_202  =1.8.0_212  =1.8.0_222  =1.8.0_232
          =1.8.0_242  =stable ]
 28  firecracker              available    [ =0.11  =stable ]
 29  golang1.11               available    \
        [ =1.11.3  =1.11.11  =1.11.13  =stable ]
 30  squid4                   available    [ =4  =stable ]
 31  php7.3                   available    \
        [ =7.3.2  =7.3.3  =7.3.4  =7.3.6  =7.3.8  =7.3.9  =7.3.10
          =7.3.11  =7.3.13  =stable ]
 32  lustre2.10               available    \
        [ =2.10.5  =2.10.8  =stable ]
 33  java-openjdk11           available    [ =11  =stable ]
 34  lynis                    available    [ =stable ]
 35  kernel-ng                available    [ =stable ]
 36  BCC                      available    [ =0.x  =stable ]
 37  mono                     available    [ =5.x  =stable ]
 38  nginx1                   available    [ =stable ]
 39  ruby2.6                  available    [ =2.6  =stable ]
 40  mock                     available    [ =stable ]
 41  postgresql11=latest      enabled      [ =11  =stable ]
 42  php7.4                   available    [ =stable ]
 43  livepatch                available    [ =stable ]
 44  python3.8                available    [ =stable ]
 45  haproxy2                 available    [ =stable ]

postgresql-serverを入れる

先ほどの方法でインストールされるのは、実はPostgreSQLのクライアントだけで、サーバはインストールされない。yumでインストールする。

sudo yum install postgresql-server postgresql-contrib postgresql-devel

initdbする

initdbしようとすると、$PGDATAがないと言われてしまった。ググると、postgresql-setupコマンドというのがあることを見つけた。initdbじゃないのか???

sudo postgresql-setup --initdb

これで確かにinitdbはできたのだが、localeの指定やencodingの指定が上手くいかない。環境変数PGSETUP_INITDB_OPTIONSを使えというメッセージも出てたので、設定してみたのだが、なんかうまくいかず…。

再度ググると、postgresユーザになってからinitdbするのがよさげという情報を得た。ユーザpostgresでログインすると、$PGDATAが設定されるのでそちらのほうが良さそう。勉強用の環境のため、接続はtrustのままでいいので-Aオプションは付けなかった。

[ec2-user@postgres ~]$ sudo su - postgres
Last login: Fri Aug  7 18:33:11 UTC 2020 on pts/0
-bash-4.2$ initdb --locale=C --encoding=UTF8
The files belonging to this database system will be owned by user "postgres".
This user must also own the server process.

The database cluster will be initialized with locale "C".
The default text search configuration will be set to "english".

Data page checksums are disabled.

creating directory /var/lib/pgsql/data ... ok
creating subdirectories ... ok
selecting default max_connections ... 100
selecting default shared_buffers ... 128MB
selecting default timezone ... UTC
selecting dynamic shared memory implementation ... posix
creating configuration files ... ok
running bootstrap script ... ok
performing post-bootstrap initialization ... ok
syncing data to disk ... ok

WARNING: enabling "trust" authentication for local connections
You can change this by editing pg_hba.conf or using the option -A, or
--auth-local and --auth-host, the next time you run initdb.

Success. You can now start the database server using:

    pg_ctl -D /var/lib/pgsql/data -l logfile start
-bash-4.2$ exit
logout

起動させる

systemdを使って起動させる。

sudo systemctl start postgresql

接続する

試しに接続してみる。

[ec2-user@postgres ~]$ psql -U postgres
psql (11.5)
Type "help" for help.

postgres=# \q

接続できたのでここまでとする。

後輩との1on1で話したことをまとめておく

1on1というか、今後どうしていきたいか等を話し合っている。継続的に話し合っていくので、まぁ1on1になっていくのかなとも思う。

「一人前」を定義する

目標がめちゃくちゃザックリとしていて、「一人前になる」というものなので、まずは一人前の定義を二人で行った。彼の考える一人前を聞き出して、「つまりはこういうことだろうか?」という感じで固めていった。詰まったときには、「Aさんはあなたから見て一人前と思えますか?」と聞き、そこから、どういうところが一人前と思えるのかを聞き出したりしていった。

現状を振り返る

大体一人前の定義が固まったところで、現状を振り返った。地図があっても現在地が分からなければ、その場所には向かえない。

本格的にプロダクトの開発に入ってもらったことはまだないので、知識も経験もまだまだであることはわかるが、まぁそれは当然のことなので、別に落ち込むことではない。

果たしてそれは本当にやりたいことか?

最近はサイトの作成をやってもらっていて、ようやくそれなりに書けるようになってきたので、それは楽しいという話をしていた。なので、フロントエンドに興味があるという話になったのだが、果たしてそれは本当にやりたいことだろうか?他のことをあまり勉強していない状態で、そう言い切っていいものか?という話をした。先日ホットエントリー入りしていた記事を見せて、説明した。

shiro-16.hatenablog.com

また、越境した結果その分野が実はその人が一番楽しいと思える分野かもしれないからです。僕自身はサーバサイド/インフラから始まり一通り終えてサーバサイド/インフラがやっぱり楽しいと感じましたが、どこかでサーバサイド/インフラより面白いと感じるものがあったのならそこに留まっていたと思うし、仕事をするなら楽しいと思える事をやりたいじゃないですか。経験年数が浅い人ほどというのをつけたのは歳を取ると越境する体力みたいなのが徐々になくなってくるのかなぁと思うからです(個人の感想)

この記事についていたコメントのこれも引用して話した。

ledsunさん: 現実の問題は領域の間に落ちている(それ以外は既に解決されている)ので越境したエンジニアは強い。狭い領域で尖っているエンジニアはわかりやすく強い(実際強い)。

Railsがなんとなく書けるだけでは足りない。コードレビューできるようになるには、Rubyらしい書き方や、RESTの理解が必要だし、自信を持ってそれを言えるだけのバックボーンがいる。自信がないと、「動いているからヨシ!」になってしまってレビューできない。データベースの特性やSQL、インデックスのこと等もわかっていないと、ActiveRecordで作ったクエリが遅くても「なんで遅いのかよくわからんけど動いてるからヨシ!」になってしまう。

遅いのは画像やJS,CSSのファイルサイズが最適化されていなかったからとか、読込が非同期になってなかったからとか、もしかしたらそういうことかもしれない。そういうのは一通り色んな領域を経験しないと気づけない。

ふんわりと要望を伝える

まずは色々やってほしくて、その上でやりたいことを考えていこうということにした。

  • T型人材を目指してほしいこと
  • T型人材になるにしても、浅く広くをできるようになるには、アーキテクチャの知識、エンジニアとしての思想、技術のベースとなる考え方を吸収しておかなければならないこと
  • Railsやフロントエンドは業務でやるからある程度は自動的に力がついていくはず
  • 一人前になるためには、Rails + αのαを頑張ろう
  • αは、Web全般の知識、運用の知識、脆弱性対策方法、アルゴリズムや設計手法、他の言語などなど…

じゃあαをどうやっていくか?っていうところが、おススメの本を聞いて、読んで、感想をアウトプットするとか、得た知識を業務に使っていくという話をした。 とはいえ、自分自身としても「最終的にはもっと本を読もう」で終わってしまうのがなんかモヤモヤしていて、もっといい方法やアイデアないもんか?と思いながら話を終えた。

終えたけれど、「車の免許は座学だけでテストで100点とっても免許渡せないでしょ?実際に運転して運転技術も身につけないといけない」という、いい感じの例えを使えたので、そこはわかってもらえてアウトプットする気になってもらえたみたいでよかった。

Rails 5.2.3から5.2.4.3に更新したらActiveStorageでエラー発生した

社内のRailsアプリのバージョンアップを行ってテストを実行したところ、システムテストが通らなくなりました。

ArgumentError: unexpected value at params[:whitelist_headers]

というエラーが出たので、ググったところ、RailsにPRが…。

github.com

これはRails6.0系の話なので、5.2系はどうなるんだ?と思っていたら、関連issueがありました。

github.com

コメントに、

You can fix this in your own app by upgrading the aws-sdk-s3 gem to 1.48.0 or greater.

とありました。

Gemfile.lockを確認したところ、aws-sdk-s3のバージョンが1.43.0だったので、早速更新。

gem 'aws-sdk-s3', '>= 1.48.0'

これで、bundle update aws-sdk-s3を実行後、テストを実行したら、問題なく通りました!😊

余談

railsのアップグレードをしたら、yarnでrails関連のjsライブラリのバージョンアップもしておきましょう。

yarn add activestorage rails-ujs turbolinks

zshでpecoを使って色々

fishからzshに移行したのですが、便利に使っていた関数を移植し忘れていたのでzsh版を作ってgistで公開しておきます。

zsh functions

herokuでjemallocのbuildpackの新しいバージョンが出ていた

過去にこのような記事を書いていました。

patorash.hatenablog.com

この記事を見返しながら、他のHerokuアプリケーションにもjemallocのbuildpackを適用しようと思ってたのですが、なんとなくbuildpackのページに移動したところ、メンテナンス停止になっていました😩全然気づいてなかった〜!!

github.com

新しいほうにforkされてるから最新のjemallocを使いたかったらそちらを、と書いてあったので、そちらを使うようにしました。

github.com

こちらにすることで、jemallocのバージョン5.2.1が使えます。以前のは4.2.1だったかと思います。

activerecord-importの削除は難しい

Rails6にしたので、insert_allメソッドが使えるようになったので、意気揚々とgem activerecord-importを削除しようと修正していってたのだけれど、思ったより難しそうだったので、一旦止めることにした。

activerecord-importの削除が難しい理由

recursiveオプションが便利で、それを使っていた

activerecord-importには再起的に関連データをインポートできる仕組みがあって、それを外していくことの影響度が大きくてテストが落ちまくるようになりました…。gemを削除するためだけ調査するには時間がかかりすぎるので棚上げすることにしました。

問題

insert_allメソッドはHashを対象とするので、モデルの配列を渡してもNGでした。そのため、activerecord-importのimportメソッドをinsert_allに変えただけではダメ。また、insert_allには以下のような問題がありました。

  • idにnilが設定されていると落ちる
  • created_at, updated_atが自動的に入らない

解決できるもの

上記の問題は、attributes_without_idメソッドをApplicationRecordに作成することで大体問題なく動いてくれました。

class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true

  # これを定義
  def attributes_without_id
    self.attributes.except('id').tap do |hash|
      hash[:created_at] ||= Time.zone.now
      hash[:updated_at] ||= Time.zone.now
    end
  end
end

これで、activerecord-importのメソッドは以下のように置換できます。

books = FactoryBot.build_list(:book, 100)

# activerecord-importの場合
Book.import(books)

# insert_allの場合
Book.insert_all(books.map(&:attributes_without_id))

# もしくは、attributes_for_listにすれば、モデルのオブジェクトの生成が不要に。
# 新規に使っていくならこちらがベストかな?
books = FactoryBot.attributes_for_list(:book, 100)
Book.insert_all(books)

最後のやつが最も効率よくデータを作られるはず…(試してない)

まとめ

insert_allは速いけれど、関連データがたくさんあるケースだと厳しい…。無理に削除せずに共存していくことにします。