ツナワタリマイライフ

日常ネタから技術ネタ、音楽ネタまで何でも書きます。

MySQL5.7でレプリケーションを試す

はじめに

仕事でMariaDBを扱っているのですが、本屋でMySQLまわりもパラパラと見ていると、この本が詳しそうだったので書いました。

詳解MySQL 5.7 止まらぬ進化に乗り遅れないためのテクニカルガイド (NEXT ONE)

詳解MySQL 5.7 止まらぬ進化に乗り遅れないためのテクニカルガイド (NEXT ONE)

まず第1章のMySQLの概要、第2章のレプリケーションを読みました。本書はMySQL5.7の膨大な新機能をセクションごとに解説する本ですが、MySQL自体初学の人間(私とか)でも非常に詳しい説明がなされていて、この本を最初に見ればよかった、という思いです。

今回、第2章で扱われているレプリケーションについて、MySQL5.7の導入とともに実践してみます。

MySQL5.7のinstall

CloudGarageさんお世話になります。やっぱりレプリケーションもできる、3台貸し出しは本当に助かる。

take-she12.hatenablog.com

installは以下の記事通り、CentOS 7.3に対して行いましたので省略。

weblabo.oscasierra.net

# yum remove mariadb-libs
# rm -rf /var/lib/mysql/
# yum localinstall http://dev.mysql.com/get/mysql57-community-release-el7-7.noarch.rpm
# yum -y install mysql-community-server
# systemctl enable mysqld.service
# systemctl start mysqld.service

設定

初期パスワードがログに出ます。

[root@mysql57-2 ~]# grep "temporary password" /var/log/mysqld.log 
2017-11-08T11:49:27.602209Z 1 [Note] A temporary password is generated for root@localhost: By30kodp0g/v

ログイン後に、パスワードをrootに変更したいですが、制限が厳しいのでそれを緩和させてやります。

以下の記事が参考になりました。

qiita.com

[root@mysql57-2 ~]# mysql -uroot -pBy30kodp0g/v
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.20

Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> set password for root@localhost=password('passwordPASSWORD@999');
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> SET GLOBAL validate_password_length=4;
Query OK, 0 rows affected (0.00 sec)

mysql> SET GLOBAL validate_password_policy=LOW;
Query OK, 0 rows affected (0.00 sec)

mysql> set password for root@localhost=password('root');
Query OK, 0 rows affected, 1 warning (0.00 sec)

masterノードの設定

bin_log(バイナリログ)の有効化と、replicationのためのserver_idを設定してやります。serveri_idはmasterとslaveで異なる値を設定しましょう。

[root@mysql57 ~]# tail -n7 /etc/my.cnf
# replication
server-id=1
log-bin=mysql-bin

# pasword policy
validate_password_length=4
validate_password_policy=LOW

ちなみにバイナリログとは、データベース上のすべてのテーブル変更の記録です。show binary logsコマンドで一覧できます。

mysql> show binary logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |       177 |
| mysql-bin.000002 |      1181 |
+------------------+-----------+
2 rows in set (0.00 sec)

このバイナリログをSQLのレベルでレプリケーションに使用する方式をStatementBasedReplication(SBR)と呼びます。(statement=SQL)しかし、この方法だとSQLの種類によってデータベースの変更結果がmasterとslaveで異なる場合がある問題があります。(UUID関数など)

その問題に対処するのが行ベースレプリケーション(RowBasedReplication, RBR)です。SQLの実行結果、変更が生じた行の前後を記録する方式なので、SQL文で結果が異なっても大丈夫です。

次にslaveが接続するよためのuserを作成します。

ログが流れてしまいましたが、

> create user 'repl' identified by 'repl';
> grant replication slave on *.* to 'repl';

でいけると思います。以下を参考にしました。

MySQL :: MySQL 5.6 リファレンスマニュアル :: 17.1.1.3 レプリケーション用ユーザーの作成

DBのdump

面倒なことに、slaveに対してはmasterのdbのdumpを流し込んで、同じレベルにしなければなりません。

slaveがmasterに接続する場合、現在のbinary_log_fileの名前と、log_positionという値が必要であるため、その情報が出力される形式でdumpを取る必要があります。

[root@mysql57 ~]# mysqldump -uroot -proot --master-data=2 -A >mysql.dump 
mysqldump: [Warning] Using a password on the command line interface can be insecure.
[root@mysql57 ~]# 

CLIでpassword打つと怒られちゃいますね。このdumpをscpかなんかでslaveに送って、restoreしてください。

slaveの設定

masterと同じでいいです。configでserver_idだけは異なるものにしてください。

レプリケーションの設定です。

mysql> change master to 
    -> master_host='192.168.0.11',
    -> master_port=3306,
    -> master_log_file='mysql-bin.000002',
    -> master_log_pos=990,
    -> master_heartbeat_period=60;
Query OK, 0 rows affected (0.01 sec)

おっと、ここのlog_fileとlog_posはdbのdumpから確認してください。

[root@mysql57-2 ~]# grep -e '-- CHANGE MASTER TO MASTER_LOG_FILE' dump.sql 
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=990;

replicationをはじめるにはslaveでstart slave statementを実行します。結果は、Slave_IO_Runningがyesであることを確認しましょう。

mysql> start slave user = 'repl' password = 'repl';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> show slave status;
+----------------------------------+--------------+-------------+-------------+---------------+------------------+---------------------+----------------------------+---------------+-----------------------+------------------+-------------------+-----------------+---------------------+--------------------+------------------------+-------------------------+-----------------------------+------------+------------+--------------+---------------------+-----------------+-----------------+----------------+---------------+--------------------+--------------------+--------------------+-----------------+-------------------+----------------+-----------------------+-------------------------------+---------------+---------------+----------------+----------------+-----------------------------+------------------+--------------------------------------+----------------------------+-----------+---------------------+--------------------------------------------------------+--------------------+-------------+-------------------------+--------------------------+----------------+--------------------+--------------------+-------------------+---------------+----------------------+--------------+--------------------+
| Slave_IO_State                   | Master_Host  | Master_User | Master_Port | Connect_Retry | Master_Log_File  | Read_Master_Log_Pos | Relay_Log_File             | Relay_Log_Pos | Relay_Master_Log_File | Slave_IO_Running | Slave_SQL_Running | Replicate_Do_DB | Replicate_Ignore_DB | Replicate_Do_Table | Replicate_Ignore_Table | Replicate_Wild_Do_Table | Replicate_Wild_Ignore_Table | Last_Errno | Last_Error | Skip_Counter | Exec_Master_Log_Pos | Relay_Log_Space | Until_Condition | Until_Log_File | Until_Log_Pos | Master_SSL_Allowed | Master_SSL_CA_File | Master_SSL_CA_Path | Master_SSL_Cert | Master_SSL_Cipher | Master_SSL_Key | Seconds_Behind_Master | Master_SSL_Verify_Server_Cert | Last_IO_Errno | Last_IO_Error | Last_SQL_Errno | Last_SQL_Error | Replicate_Ignore_Server_Ids | Master_Server_Id | Master_UUID                          | Master_Info_File           | SQL_Delay | SQL_Remaining_Delay | Slave_SQL_Running_State                                | Master_Retry_Count | Master_Bind | Last_IO_Error_Timestamp | Last_SQL_Error_Timestamp | Master_SSL_Crl | Master_SSL_Crlpath | Retrieved_Gtid_Set | Executed_Gtid_Set | Auto_Position | Replicate_Rewrite_DB | Channel_Name | Master_TLS_Version |
+----------------------------------+--------------+-------------+-------------+---------------+------------------+---------------------+----------------------------+---------------+-----------------------+------------------+-------------------+-----------------+---------------------+--------------------+------------------------+-------------------------+-----------------------------+------------+------------+--------------+---------------------+-----------------+-----------------+----------------+---------------+--------------------+--------------------+--------------------+-----------------+-------------------+----------------+-----------------------+-------------------------------+---------------+---------------+----------------+----------------+-----------------------------+------------------+--------------------------------------+----------------------------+-----------+---------------------+--------------------------------------------------------+--------------------+-------------+-------------------------+--------------------------+----------------+--------------------+--------------------+-------------------+---------------+----------------------+--------------+--------------------+
| Waiting for master to send event | 192.168.0.11 | repl        |        3306 |            60 | mysql-bin.000002 |                 990 | mysql57-2-relay-bin.000003 |           320 | mysql-bin.000002      | Yes              | Yes               |                 |                     |                    |                        |                         |                             |          0 |            |            0 |                 990 |             531 | None            |                |             0 | No                 |                    |                    |                 |                   |                |                     0 | No                            |             0 |               |              0 |                |                             |                1 | ca6806d3-c473-11e7-9e52-fa163e4c44c2 | /var/lib/mysql/master.info |         0 |                NULL | Slave has read all relay log; waiting for more updates |              86400 |             |                         |                          |                |                    |                    |                   |             0 |                      |              |                    |
+----------------------------------+--------------+-------------+-------------+---------------+------------------+---------------------+----------------------------+---------------+-----------------------+------------------+-------------------+-----------------+---------------------+--------------------+------------------------+-------------------------+-----------------------------+------------+------------+--------------+---------------------+-----------------+-----------------+----------------+---------------+--------------------+--------------------+--------------------+-----------------+-------------------+----------------+-----------------------+-------------------------------+---------------+---------------+----------------+----------------+-----------------------------+------------------+--------------------------------------+----------------------------+-----------+---------------------+--------------------------------------------------------+--------------------+-------------+-------------------------+--------------------------+----------------+--------------------+--------------------+-------------------+---------------+----------------------+--------------+--------------------+
1 row in set (0.00 sec)

masterで変更を加えた結果が、slaveでも反映されていれば成功です。

master側ではこのようなログがでていました。

2017-11-08T12:10:16.099322Z 12 [Note] Start binlog_dump to master_thread_id(12) slave_server(2), pos(mysql-bin.000002, 990)

slave

2017-11-08T12:09:34.187408Z 2 [Note] Slave SQL thread for channel '' initialized, starting replication in log 'mysql-bin.000002' at position 990, relay log './mysql57-2-relay-bin.000001' position: 4
2017-11-08T12:09:34.188654Z 0 [Note] End of list of non-natively partitioned tables
2017-11-08T12:10:16.096654Z 6 [Note] Slave I/O thread for channel '': connected to master 'repl@192.168.0.11:3306',replication started in log 'mysql-bin.000002' at position 990

slave側ではslave IO threadがmaster threadからのbinary logを受け取り、relay logに書き込みます。それをslave SQL threadがストレージエンジンに書き込むんですね。

おわりに

そこそこ簡単にMySQLレプリケーションが実現できましたが、この感じだとデータに差分がある状態ではレプリケーションができないのかな?と思いました。つまり、稼働中のクラスタに対して、稼働したまま新規slaveを追加するにはどうしたらいいのか、それともできないのか、疑問に思いました。

Galera Clusterの同期の仕組みを公式ドキュメントから読み解く(2)

はじめに

前回に引き続き、galera clusterのtechnical descriptionを読んでいきます。

Technical Description — Galera Cluster Documentation

これ、全部やると全8回になるなぁ。。。どうしようかなぁ。。。(弱気)でもどれも大事そうだからなぁ。。。とりあえずState Transfersは知りたいので、そこまでは1つずつ進んでいくことにします。

CERTIFICATION-BASED REPLICATION

証明ベースのレプリケーションはグループコミュニケーションとトランザクション並べ替え技術を使い同期を実現します。

トランザクションは1つのノード、またはレプリカで楽天的に実行し、コミットするときにそれらは一貫性を保つために調整された証明プロセスを実行します。同時発生するトランザクションの中で、順番を成立させるサービスをブロードキャストすることで、全ノードでの整合性を達成します。

WHAT CERTIFICATION-BASED REPLICATION REQUIRES

すべてのデータベースシステムに証明ベースのレプリケーションを実することは不可能です。いくつか必要なデータベースの特徴があります。

  • Transactional Database
  • Atomic Changes
    • レプリケーションエベントはデータベースとATOMICに変更できる必要があります。特に、一連のデータベースに対する操作は、すべて実行し終えたか、まったく実行していない状態か、そのどちらである必要があります。
  • Global Ordering

HOW CERTIFICATION-BASED REPLICATION WORKS

証明ベースのレプリケーションの基本的な考えは、トランザクションがコミットポイントに到達するまでに実行されることであり、コンフリクトが一切ないことが望ましい。これは楽観的な実行と呼ばれる。

clientがCOMMITコマンドを発行するとき、実際のCOMMITが実行される前ではあるが、変更された行のトランザクションと主キーによって行われたすべての変更は、write-setに収集されます。データベースは他のすべてのノードにこのwrite-setを送ります。

write-setは決定論的に受ける証明テストより、プライマリーキーを用います。これはクラスターの各ノードで行われ、write-setを元にノードを増やします。これによってwrite-setを各ノードが適用するかどうかを決定します。

もし証明テストが失敗すれば、ノードはwrite-setを破棄し、クラスターは元のトランザクションロールバックします。テストが成功すれば、トランザクションはコミットし、write-setはクラスターの残りに適用されます。

CERTIFICATION-BASED REPLICATION IN GALERA CLUSTER

galera clusterにおける証明ベースのレプリケーションの実装は、トランザクションのグローバル順序付けに依存します。

galera clusterはそれぞれのトランザクションにシーケンス番号を割り当てます。トランザクションがコミット地点にたどり着くと、ノードはシーケンス番号が最後にトランザクションが成功した番号と反しているかを確認します。それら2つが関係している間は、トランザクションはそれぞれのノードはお互いに影響を与えません。intervalの間のすべてのトランザクションは、問題となるトランザクションとすべての主キー競合を確認します。競合を検出すれば、証明テストに失敗します。

順序は決定的で、すべてのレプリカがトランザクションを同じ順番で受け取ります。すなわち、すべてのノードは同じ決定をトランザクションの結果実施するのです。トランザクションを開始したノードは、トランザクションをコミットしたかどうかをクライアントとなるアプリケーションに通知できます。

おわりに

訳が不自然なところが多いですが。。。write-setと呼ばれる一連のcommitセットの単位で、それにidを付与してクラスタに配布、primary-keyを元にしてコミットの競合がないかを確認(証明)。これが失敗すれば破棄し、成功すれば受け入れる、という風に読めました。

まだまだ続きます!毎朝書いていこうかな。

Galera Clusterの同期の仕組みを公式ドキュメントから読み解く(1)

はじめに

仕事でMariaDBレプリケーションにGalera Clusterを使っています。使い方や、同期されてるかどうかの確認の方法はわかりますが、実際にどんな仕組みで差分を判定し、どんな仕組みで同期をしているかはわかっていません。

そこで公式ドキュメントを読んで理解してみましょう。

Technical Description — Galera Cluster Documentation

かなり物量が多いですね。いくつかピックアップして読んでみましょう。

DATABASE REPLICATION

Database Replication — Galera Cluster Documentation

Database replicationは、database serverである、あるノードから別のノードでデータを頻繁にコピーすることを意味します。すべてのノードが同じレベルの情報を共有する、分散データベースシステムとしてDatabase replicationを考えます。このシステムはよくdatabase clusterとして知られています。

webブラウザやcomputerアプリケーションのような、データベースクライアントはデータベースレプリケーションシステムが見えません。しかし、ネイティブのDBMSの振る舞いに近いことに恩恵を得ています。

MASTER AND SLAVE

多くのデーラベース管理システムはデータベースをレプリケーションします。

もっともよく使うレプリケーションは、オリジナルのデータセットとそのコピーの間の関係をmaster/slaveとして設定するものです。

このシステムでは、masterのデータベースサーバはデータが更新されたことと、ネットワークを通じてslaveにデータを増殖させたことをログに残します。slaveのデータベースサーバはmasterから更新の通知を受け取り、その変更を適用します。

別のレプリケーションは、すべてのノードにmasterの機能を持つmult-masterレプリケーションです。

multi-masterレプリケーションシステムでは、あなたはどのデータベースにも更新を書き込むことができます。これらの更新ははネットワークを通じてすべてのノードに伝搬されます。すべてのデータベースノードはマスターの機能を持つのです。これらには利用可能なログを残さず、システムは更新が成功したかどうかをあなたに示すこともありません。

ASYNCHRONOUS AND SYNCHRONOUS REPLICATION

他のノードへのデータ変更を行う方法に加えて、cluster間のデータ転送方法がいくつかあります。

  • 同期レプリケーション
    • "eager replication"というアプローチ。1つのトランザクション内で、すべてのノードの更新され、同期が完了する。言い換えると、transactionのコミットが発生した時、すべてのノードが同じ値を持つということです。
  • 非同期レプリケーション
    • "lazy replication"というアプローチ。masterのデータベースは非同期でslaveに更新を伝搬させます。masterノードがレプリカを伝搬させたあと、トランザクションはコミットされます。言い換えると、トランザクションがコミットされたとき、かなり短い時間でみると、いくつかのノードは違う値を持つということです。

Advantages of Synchronous Replication

同期レプリケーションのほうが、いくつか利点を持ちます。

  • 高可用性
    • 同期レプリケーションは24時間7日サービスの利用を保証し、高いクラスタ可用性を提供します。
      • ノードがクラッシュしてもデータロスなし
      • データの一貫性維持
      • 複雑で時間のかかるフェールオーバーがない
  • 性能改善
  • クラスタ間の因果関係
    • 同期レプリケーションクラスタ間の関係を(同一であることを)保証します。例えば、SELECTのクエリが他のノードで実行されたとしても、いつも同じ結果を返します。(?)

Disadvantages of Synchronous Replication

eager replication protocolはノードに対して1つの操作を同時に行います。これらは2段階のコミットか、ロックを生じます。n個のノードで構成され、oのプロセスがtのトランザクションを行うとき、mのメッセージを受け取ります。その式は

m = n × o × t

これが意味することは、トランザクションのレスポンス時間と競合とデッドとっくが発生する確率が、ノードの数の増加に伴い指数的に増加するということです。

この理由から、非同期レプリケーションが、データベースの性能、スケーラビリティ、可用性という面でもっとも有効なレプリケーションプロトコルとされています。MySQLPostgreSQLは非同期レプリケーションのみを採用していて、このようにオープンソースのdatabaseに広く適用されています。

SOLVING THE ISSUES IN SYNCHRONOUS REPLICATION

いくつか同期レプリケーションに対して問題を解決するアプローチがあります。ここ数年、研究者が同期レプリケーションに対する別の提案を行ってきました。

理論に加えて、いくつかのプロトタイプ実装が保証を示しました。これらの研究から重要な向上をいくつかもたらしました。

  • Group Communication
    • データベース間のコミュニケーションパターンを定義する高いレベルの抽象化です。レプリケーションの一貫性を保証します。
  • Write-sets
    • これは1つのwrite-setメッセージでデータベースの書き込みを束ねます。この実装は同時に1つのノード対する操作をする整合性を回避します。
  • Database State Machine
    • このプロセスはread-onlyのトランザクションをローカルのデータベースで行います。この実装は最初に実行されたトランザクションを更新し、shallow-copies上で行います。そして証明またはコミットのために、read-setとして他のデータベースに伝搬させます。
  • Tansaction Reordering
    • データベースがコミットし、伝搬させる前に、transactionを並べ替えます。この実装は証明テストをpassしたトランザクション数を増加させます。(?)

Galera Clusterが使っている証明ベースのレプリケーションシステムにはこれらのアプローチが組み込まれています。

おわりに

結構時間がかかってしまったのでこのへんで。データベースのレプリケーションに関する一般的な用語や方法を整理したドキュメントですね。同期レプリケーションの優れている点と劣っている点を記載し、mysql(mariadb)では非同期レプリケーションが使われていることがわかりました。また、劣っている点は後半であげた技術によってカバーされていることもわかりました。

全部はやらないと思いますが、あと数回続くと思います!

CloudGarageのDevAssistProgramに通ったのでさっそくインスタンス作ってみる

はじめに

CloudGarageのDevAssistProgram通りましたー!

CloudGarageさんは定額制のパブリッククラウド。利用料金にビクビクすることがないのでいいですね。

そしてDevAssistProgramです。

cloudgarage.jp

LBが1つと、インスタンス3つもついてきます!なんと1年間無料。承認制です。

わたしはいのうえさんのkubernetesの記事でこのキャンペーンを知りました。

blog.a-know.me

こちらもぜひやってみたい。

注意

審査が通ったあとは、アカウントを作成し、再度アカウント名をメールで送信することでアカウント情報と紐付けされ、キャンペーン対象を無償購入できるようになります。そのため承認がおりても使えるまでは多少タイムラグが生じるのでなるべくはやく返信しましょう。

使ってみる

ではさっそくコントロールパネルからインスタンスを作ってみましょう。

無事審査が通ると以下の画面でキャンペーンプランを購入できます。

f:id:take_she12:20171012182227p:plain

インスタンス作成です。OSはCentOSUbuntuDebianfedoraSuSEといろんな種類が使えますね。Rancherがあるのがめずらしいと思いました。Docker環境がらくらく作れちゃいますね。

f:id:take_she12:20171012182234p:plain

逆にアプリケーションが乗った状態で配られるものもあります。GitlabやRedmineはだいぶインストールが楽になったとはいえ、ソッコー使えるのは結構嬉しいですね。Gitlabはgitlab.comが代替になるとして、個人用のRedmineは欲しいと思ったことあるな。(音楽制作のプロジェクト用に)

f:id:take_she12:20171012182240p:plain

インスタンスを作ると10秒そこらで稼働中になりました。ポートはhttpの80番とsshの22番だけあけておきました。

f:id:take_she12:20171012182249p:plain

実際にログインしてみます。

rootユーザで、インスタンス作成時のパスワードを入力すればログイン完了!

⋊> ~/g/private on master ⨯ ssh root@203.104.226.212                                                                   18:31:39
root@203.104.226.212's password: 
Last failed login: Thu Oct 12 18:26:25 JST 2017 from 171.233.59.3 on ssh:notty
There were 16954 failed login attempts since the last successful login.
Last login: Mon Jun 26 13:22:52 2017
[root@cloudgarage1 ~]# 

22番公開してるからかめちゃくちゃログインアタックかけられてますねw やっぱりport番号は変えないとダメかな。

[root@cloudgarage1 ~]# cat /etc/redhat-release 
CentOS Linux release 7.3.1611 (Core) 

OSはちゃんとCentOS7.3です。

おわりに

(このインスタンスはちゃんと破棄しました)

インストール直後のセキュリティまわりの設定はあとでするとして、個人でLBつきの3台使えるのは開発者にとって非常にうれしいことです。上記のkubernetesだったり、redmine個人用に作ったりもしてみたいですが、まずは直近仕事で使うMariaDBのGalera Clusterを試します。

というわけでCloudGarageの宣伝&導入記事でした。(別に頼まれてません!)

「エンジニアのための文章術再入門講座」を読んでドキュメント作成スキルの振り返りをする

はじめに

良いドキュメントを書くことはエンジニアのたしなみ。ということで定期的に自身のドキュメントスキルの見直しを行っています。

エンジニアのための文章術再入門講座

エンジニアのための文章術再入門講座

ドキュメントといえば結城先生の数学文章作法もおすすめ。

で、この"エンジニアのための文章術再入門講座"なんですが、各章ごとにエッセンスを紹介して、そのあと具体例を用いて悪い文章を良い文章に直す、というスタイルで進んでいきます。ただ、この例がかなり自分にとってはしっくりこず、本当にこんなドキュメントわざわざ書くやつおるんかいな、と思うシーンがほとんどで、僕はエンジニアのはずなのにおかしいなぁと思ってしまいました。

とはいえ、書いてある観点そのものは正しいと思うので、その点にしぼって振り返りをしてみます。

エンジニアにとってのドキュメント

その前に、エンジニアにとってなぜドキュメントスキルが必要か、ということを再認識しておきましょう。

本書でも一章で、ドキュメントはエンジニアのスキルを表すということが言及されていますが、信頼できる文章を書くことで技術的にも期待されるという面は確かにあると思います。

私は本書の例にあるようにお客様にシステムを提案するドキュメントを書くことも、経営層に投資対象を選択してもらうためのドキュメントを書くこともありません。

今の私が仕事でドキュメントを書くシーンは

  • ツールやコードのREADME、MergeRequestでの仕様説明
  • チームメンバーや後輩への業務指示
  • チーム内で遵守すべき共通ルール
  • ナレッジ(技術的知見)の共有
  • 業務上不明点の相談、報告
  • 業務進捗報告
  • イベント参加報告

ぐらいでしょうか。どれもたいしたことないように思えますが、なるべく一発で相手に伝わるドキュメントを書くスキルは重要だと以前より考え、ブログでのアウトプットを続けているのもその一環です。(時間に余裕が無い時スピード重視で雑なままつきとばしてしまうことが最近あって、反省。。。)

チーム内でもドキュメントに対するこだわりは強いのですが、実力はまだついていないようで、まだ他者に褒められるまではいたってないので今後も精進。。。

ドキュメントを書く時の心がけ

本書第2章で語られている以下の2点は正しいと思います。

ルール① 目的にフォーカスする ルール② 相手にフォーカスする

結城先生も「読者のことを考える」だけをひたすら言い続けた本を書いたわけですが、その読者がどういう知識レベルで、どういう目的で読むかを考えることが第一に大切なことだと思います。

プレゼンのときに「対象は誰で」「知識レベルはどれぐらいで」「何を持って帰ってもらうことが目的なの」ということを考えますが、それと同じですね。

論点を絞る

本書第3章では、伝えたいことを1つがテーマです。本筋に余計なことが書かれていると気が散りますよね。

余談ですが、余談ですがで本筋を見出しまくったココイチ好きすぎな記事を昨日読んで、なるほどカレーが食べたくなっちゃうなーと思いました。余談ですが。

www.mikinote.com

本書まとめでは「論点を絞る」ことに関するチェックポイントが5つもあってなかなか絞りきれないと感じました。

論理的記述力

4章、主張をしたら根拠を述べる。

まぁ、そうねって感じですね。

ちなみにまとめで5つのチェックポイントがあるわけですが、5つめの受け身表現や稚拙表現を使わない、がカテゴライズされてるのが謎です。この主張自体は正しいのですが、論理性による文章の信頼性担保のついでに、受け身表現も信頼度減るよ、稚拙表現(これはこれでまた曖昧な表現ですが)も信頼度減るよ、だからやめようね、のついで感があります。

構造化力

5章、同じグループをまとめたり、同じ階層ではレベルを揃えるとのこと。これはとても重要ですね。

箇条書きでよくやりがちなのは、粒度が揃っていなかったり、論理展開を並べてしまったりする場合があります。

# 私とカレーについて
* カレーが好き
* キーマカレーが好き
* 週末はよくカレー作りをする

おいおいカレーとキーマカレーは粒度が違うやないかい、カレーの好みと、カレーをどう好きかもまた粒度が違うやないかいってなりますよね。

# 私とカレー
* カレーはおいしい
* カレーを作ってみようと思った
* カレーエンジニアに

まぁそんな流れでカレーエンジニア(ってなんだよ)になったのかなーってのはなんとなくわかるけど、思考の流れや論理展開を箇条書きにするのも好ましくないと思います。伝わるけどね。

平易表現力

本書第6章です。

難しい用語、専門的な用語、自分やチームの人しかわからない言葉は、言い換えて表現する ただし、文章に前修飾すると分かり難いので、脚注やカッコを使う

"一言で言う「結論」"で「ただし」と足されているところがしっくりきませんが、使う用語は読者が理解できるものしようというのは正しいと思います。

これは冒頭で述べた「読者の知識レベルを考える」でカバーできる範囲だと思います。

正確表現力

7章です。

自分が知っていることを省略しない、あくまで相手の知識や理解をベースに書く 主語や主体は明確に書く 曖昧な表現や無意味な表現をしない

3点目の曖昧な表現や無意味な表現がとってもブーメランになってる気がしますが、暗黙的な理解を省略してしまうことはあると思うので、前提が相手にはわかるかな?という視点は大切かと思います。

あとここに関連するか微妙ですが、略語を使わないということも大事ですね。(略語も省略といえばそうなので) 少なくとも1回目は正式名称で述べ、以降略するとか。ついついチーム内への提案ドキュメントにcapistranocapiと書いてしまって最近指摘されました。capiって言うもん。ごめんなさい。

A remote server automation and deployment tool written in Ruby.

capiはいいぞ。

短文表現力

8章

無駄な文章をそぎ落とす 図解や記号化を行い、文章を画像として扱う 短くするための言い換えを使う

!? って感じのまとめですが、できるだけ短くしようね、ということは納得します。

論理展開を→を使って省略するということが主張のようですが、まぁ好みの問題かなと思います。

体現止めにしてブロックにしてそれを矢印で遷移させるのはプレゼンの領域でしょう。

感情・心理利用力

相手の感情に訴えるなど、心理面のアプローチをドキュメントに埋め込む 複数案から選ばせることで、こちらの意図した方向に誘導するなどの技術を駆使する

上記の結論を添削するなら、本書はドキュメントに関する指摘をしているので"ドキュメントに"埋め込む は冗長。

意図した方向に誘導する"など" という曖昧な表現は排除すべきですね。

で、ここにきて感情論かよ、って思いそうになりますが、これは「相手の気持ちを考える」ということなので、とても良いことです。つまり提案を受ける側の選びやすい形にしてあげる、と捉えることができます。

まぁなんか相手を褒めるとかも書いてありますが、うん、まぁ、そうね、普段のコミュニケーションとしては大事です。

この章、言ってることは間違ってはいないのですが、ドキュメントの技術的な校正を考えるなら除外すべき章だと思いました。もう少し大きな枠組みで、チームで働くときに気をつけるべきメンバーへの働きかけ方、という範囲で述べられることかなと思いました。

フレームワーク

相手と目的によってフレームワークを用いましょうという話。そういうものがあるなら使えると思いました。ここはテクニックではないですね。

おわりに

あらためて振り返りましたが、ドキュメントの目的を考える、読者の知識レベルを考えるという2点はやはり欠かせません。

その上で本書を読んであらためて気をつけたいことは

  • 論点を絞ること
  • 構造化し、箇条書きは粒度を揃えること
  • 表記ゆれ、誤字、省略を避けること

を守れば良いドキュメントは書けると思いました。

最後に思い出したようにひとつ。僕がドキュメントへのこだわりが強いのは以下の記事であるように引き継ぎが大嫌いだからなんですね。正確には無茶振りな引き継ぎでつらい目にあったからなんですが。過去のこういう記事を書いていました。

take-she12.hatenablog.com

良いドキュメントはエンジニアのたしなみ。今後もソースコードと同じぐらいドキュメント作成能力も鍛えていきましょう。

ようやくSRE本を読み終わりました

はじめに

読み終わりました。

SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム

SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム

英語の原著が出た時点でkindleで購入していたにも関わらず読み通せなくて、その後英語版は無料公開されました。

Google - Site Reliability Engineering

ほどなくして翻訳版が出て、読まないわけにはいくまいと購入。2ヶ月ほどずっとリュックやバッグにいれて持ち歩いていました。重かった。。。

SRE、信頼性エンジニアはGoogleで古くからあり、日本でもメルカリをはじめ、現在は様々な企業でSREポジションが存在します。(言葉だけ広がって流行っているとも、見える。)

GoogleのSREにはなれなくても、SREのような考え方を大事にする場所で働きたいと思います。せっかく読み通したので振り返りをしておきましょう!

まず、Google SREのコアな考え方は9章の第2部までに集中しています。まずはここをおさらい。

原則

エラーバジェット

Google SREの中でも大切な考え方の1つ。単純に、サービスが保証する信頼性目標(SLO: Service Level Objectives)を超えているのであれば新機能のリリースができ、下回っている場合は新たなリリースができないことを開発・運用双方で合意しています。

これによって新たなリリースという障害リスクを抑制することと、信頼性向上のための施策を行うことができます。

SLO、SLA、名前はあれどそれを明確に顧客と約束したり、計測して結果を振り返ったりすることは非常に難しい。そして計測しなければこのエラーバジェットによるリリース制約はできません。

SLOの指標

では何を指標にし、どう収集すればいいのでしょうか。

これは多すぎてもいけないし、見当違いのものでもよくなく、これを決めるのはかなり経験が必要ではないかと思いました。

また、「最初から完璧でなくてもよい」とある通り、継続的な見直し、修正が基本的な考え方なんでしょう。

トイル

これもSRE本での重要な考え方の1つ。本書によれば、

プロダクションサービスを動作させることに関係する作業で、手作業で繰り返し行われ、自動化することが可能であり、戦術的で長期的な価値を持たず、作業量がサービスの成長に比例するといった傾向を持つものです。(p51)

ここでもっとも重要なことは"作業量がサービスの成長に比例する"ということでしょう。単純な手作業だとしてもサービスの成長=機能追加の数が増えるだけで、その作業は指数的に増えるかもしれません。

本書34章まとめで、SREの進化を航空業界に例える例がありますが、まさに「サービスが数百、数万のオーダーで成長しても、"同じ人数"で信頼性を維持することが、SREでもっとも重要な考え方の1つだと思います。そのためにトイルは絶対撲滅しなければなりません。

SREの業務

SREの業務はおおよそ以下の4つに分類できます。

  • ソフトウェアエンジニアリング
  • システムエンジニアリング
    • システムの設定変更、システムに関するドキュメント作成。1回の作業で改善が持続するようなもの。
  • トイル
    • サービスを稼働させることに直結している作業で、繰り返されたり、手作業だったりするもの
  • オーバーヘッド
    • サービスを稼働させることに直結していない管理的な作業。採用、人事、ミーティング、バグ整理、レビュー、自己評価、トレーニング

なるほどこの4分割は、現状の自分の業務でも納得できます。(もっとも、これらに含まれない本当にやりたくない仕事もたまにあるが)

トイルを減らし、エンジニアリングの割合を増やすこと、これがSREがいる組織と、従来のDev & Opsが分かれている組織との違いですね。

モニタリング

レイテンシ、トラフィック、エラー、サチュレーションが4大シグナル。モニタリングの設計をした経験がないので、今後やる場面になったときにもう一度読み返したい。

自動化と自律性

7章、Googleにおける自動化の進化ですが、ちょっと内容かわかりづらいんですよね。

自動化の進化は以下のような経過を辿る。

  1. 自動化以前
  2. 外部でメンテナンスされるシステム固有の自動化
  3. 外部でメンテナンスされる汎用の自動化
  4. 内部でメンテナンスされる汎用の自動化
  5. システムが自動化を必要としない

最終的には5、つまりシステムが自律的に問題を解決する(自動化した何らかの解決手段を必要としない)ことを理想としています。現実的に身の回りでは2か、頑張って3ぐらいですね。。。

例えば、今の職場では共通のSSL-VPN接続端末があって、そこを経由して検証環境につなぐのですが、最初は各クライアントで使うための自動接続スクリプトを作ったんですね。(2) それを共通基盤として使うようになって、(3) 切断を検知して(よく切れる)自動再接続するようにしました。(4) この順序は正しいですね。

リリースエンジニアリング

いわゆるCI/CDと言われている領域に近い話ですね。

哲学として高速性、密封ビルド(一貫性と再現性の保証)があげられています。

これは継続的ビルドとデプロイメントで紹介されているビルドの速度と、パッケージ化ですね。ubuntu系のdebrhel系のrpmのようなパッケージシステムによって一貫性と再現性を保証します。

アプリケーションやインフラのソースコード管理、そしてビルド、デプロイの自動化は最近では当たり前のようにされるようになったと思いますが、設定管理はどうでしょうか。通常、ソースコード管理で管理しない、いわゆるconfigのようなところです。

本書でもバイナリ(と呼ぶ、アプリケーションをパッケージとしてビルドしたもの)と設定は別管理をするが、フラグを使ってひも付ける例があげられていました。例えばansibleのような構成管理のタグとrpmのバージョニングを合わせて管理するのがベストといえそうです。

実践編

ここからは実践編で、理論というよりはポエムとなります。googleの社内ツールの話は理解が難しかったのであまり深く読んでません。オンコール対応も(SREとしては重要な話ですが)現職ではそのポジションにないので飛ばしました。

中でも面白かった章を紹介します。

トラブルシューティング

トラブルシューティングって、みなさんどうやって習得しましたか。ぼくはいきなり障害番号投げつけられて「これ見て」からはじめました。ひどいよね。

今思えば当たり前のことですが、

  • 一般的なトラブルシューティング手法の理解(すなわち、特定のシステム知識とは関係ない)
  • システムに関するしっかりとした知識

この2種類あるが、それよりは、本来そのシステムのあるべき姿を知っていることが大事だと言います。本当にそうだと思います。

システムの本来の動きも知らない、一般的なトラブルシューティング手法も知らない、特定のシステム固有の話も知らない状態で振るなんて悪手でしかないので絶対に自分より下にはそんな思いをさせたくない。この章を2年前に読みたかった。

問題のレポート、トリアージ(システムがその環境下でできる限りうまく動作するようにすること、すなわち暫定対処や復旧のこと)、検証、診断、テスト/対処という流れでトラブル対応していくことになります。最初はこの流れすら知らなかった。のちに仮説/検証のサイクルで詰めていくことが大事と自ら学んだ。悪くない経験とはいえ、遠回りしてしまった。

この章はトラブルシューティング初心者にはかなりおすすめですね。

ポストモーテム

ポストモーテムも、SREとしてかなり重要なことですね。

しばしばインシデントはドキュメント化されるというよりは、報告が義務付けられるので、何らかの形で残ってはいるのですが、それを「次への学び」に活かすという視点での活用は今の職場にはないところです。

ポストモーテムで批判を行ってはいけないことは繰り返し述べられています。

「今月のポストモーテム」や「ポストモーテムニュースグループ」「ポストモーテム読書会」はすごいいいですよね。個人的にはやってみたいな、今のチームでできないか考えてみたいと思います。ちょうど勉強会やってるし。

データの完全性

特にバックアップとアーカイブの違いについてが面白かったです。アーカイブは完全に保管するものの、リカバリ2時間がかかってもさほど問題はないでしょう。逆にバックアップはリカバリが素早くできないのであれば意味がありません。ユーザから見て対象のデータが長期にわたって使えないのであればバックアップがあっても無意味です。それが「データの完全性は手段であり、目標とするのはデータの可用性である(p363)」ということでしょう。

そしてやはり重要な学びは"多層防御"でしょう。複数のレイヤーで可用性を確保しておかねばなりません。

そして必ずリカバリの検証をすること。「バックアップできてるはず」「リカバリできるはず」ではいけません。"願望は戦略にあらず(p387)"の通りです。

管理

4章ではSREの後継の育成や、割り込みと対処、SREチームと他の開発チームとのコミュニケーションなど、より人間的な面での実践アプローチが語られています。これも今後機会があったときに読み返したいです。

おわりに

何とか通読したものの、「ウォーこれはこういうことだったのかーこの考え方は大事にしよー!」ってものと、あまりピンとこなかったものがありました。自分自身の経験に合わせて再度読み返すときっと新しい気づきがあるでしょう。システムの信頼性に関することなら、何かしらのヒントがこの本にあるはずなので、壁にぶちあたったときに手を伸ばせるように手元に置いておきたい本です。

私個人としてもSREというポジションになりたいと思っているので、読み通したかった本がちゃんと読めて、こうやってブログで振り返れてよかったです。

直近の業務で活かすことといえば、インシデントを一手に受けているので、トラブルシューティングの一般化を後輩に伝えていくこと、勉強会を主催しているのでポストモーテム読書会はやりたいということと、モニタリングについて自分自身で設計したことがないので何かしらでやってみたいです。

さて、次は同じくUberのSREが執筆した「プロダクションレディマイクロサービス」も買ったので、読んでブログ書きたいと思います。

プロダクションレディマイクロサービス ―運用に強い本番対応システムの実装と標準化

プロダクションレディマイクロサービス ―運用に強い本番対応システムの実装と標準化

GCPのコンピューティングサービスの料金をざっくり確認する

はじめに

カレー好きなエンジニア、たけしです。ついついGCPでがっつりカレーパーティに申し込んでしまったのですがGCPを使ったことがありません!

topgate.connpass.com

やばくない?何だこのイベント!これを機に俺もGCP好きのカレーエンジニアになるぞオォォォとなりました。

真面目な理由としては、今後仕事でクラウドを"使う側"に立つ可能性があり、AWSだけではなく、GCPやAzureで何ができるか、何が違うのかは把握する必要があると思っていること。コンテナオーケストレーションのKubernetesを使ってみたいことがあります。

で、まずは料金からです。

料金体系

公式の日本語サイトが充実しています。

cloud.google.com

料金計算ツールもあるので合わせて見ていきましょう。

cloud.google.com

App Engine(GAE)

アプリケーションを載せることができる、PaaSです。

cloud.google.com

言語はNode.js、JavaRubyC#、Go、PythonPHPに対応。トラフィック分割やアプリケーションのバージョニングなど、リリースに関する仕組みは気になりますね。

Herokuに似たようなサービスです。

気になるお値段は?

  • インスタンスのクラスによって、0.05〜0.30 USD / hour のようです。
  • 起動時には15分間の起動時間が加算されます。つまり最低課金料金が15分間ということですね。
  • Google Cloud Databaseは無料枠あり。1日1GBのデータ保存まで。

料金計算ツールを使ってみました。

Outgoing Network Traffic: 1 GB
Cloud Storage: 10 GB
$0.13

1ヶ月です。適当にネットワークとcloud storageを入れてみましたが、app-engineのインスタンスには課金は発生しないようですね。search apiなど他のサービスを呼んだり、トラヒックを使うと課金されていくようです。

Compute Engine(GCE)

cloud.google.com

EC2と同等のものですね。

なんとf1-microだと料金はかからない!あとは基本的にはフレーバーのレベルによって変わるみたいです。

f1-microで1ヶ月使った場合

730 total hours per month
VM class: regular
Instance type: f1-micro
Region: Iowa
Sustained Use Discount: 30%  
?
Effective Hourly Rate: $0.0053
Estimated Component Cost: $3.88 per 1 month

わずか3.88ドル。永続ストレージ30GBをつけても

Storage: 30 GB
$1.20

合計5ドルです。めちゃくちゃ安いですね。

Container Engine(GKE)

Google Container Engine ドキュメント  |  Container Engine  |  Google Cloud Platform

ECSと同等のサービス。

クラスタ内のノード数が5までなら無料なんですね!クラスタのノードにはGCEを利用するようで、GCEの料金がそのまま加算されます。

6ノード以上だと、アイオワでは1ヶ月

6 ノード以上    標準クラスタ  $109.50

結構かかりますね。

Container Registry

cloud.google.com

DocukerHubのような、Container Registryサービスは、StorageとNetworkの料金のみしかかからないようです。

Google Container Registry では Docker イメージが使用した Google Cloud Storage とネットワーク出力に対してのみ料金が発生します。詳しくは、料金ガイドをご覧ください。

Cloud Functions

cloud.google.com

lambdaに代表される、Function as a Serviceですね。

こちらも無料枠が用意されてます。試すだけならできそうですね!

  • 呼び出し
無料試用枠 無料枠を超えた料金(単価) 課金単位
200 万回 $0.40 呼び出し 100 万回あたり
  • コンピューティング時間
無料試用枠 無料枠を超えた料金(単価) 課金単位
400,000 GB 秒 $0.0000025 GB 秒単位
200,000 GHz 秒 $0.0000100 GHz 秒単位
  • 送信データ(下り)
無料試用枠 無料枠を超えた料金(単価) 課金単位
5GB $0.12 GB 単位
  • 受信データ(上り)
無料試用枠 無料枠を超えた料金(単価) 課金単位
無制限 無料 GB 単位
  • 同じリージョン内の Google API への送信データ
無料試用枠 無料枠を超えた料金(単価) 課金単位
無制限 無料 GB 単位

結構安い気がする。何個ノード?を立てるかは関係ないのか。

おわりに

ざっくりComputeサービスの料金を見てみました。StorageやNetworkの料金が関係してくるので一概には言えませんが、個人が簡単に試してすぐ消す分にはCloud Funtion、f1-microでのGCE/CKEはそんなに大金かけずに使えそうです。

次回はTerraformを使って実際にインスタンスを作ってみたいと思います。