ushumpei’s blog

生活で気になったことを随時調べて書いていきます。

redisのレプリケーション

 redisレプリケーションがとても簡単だったのでメモです。勉強も兼ねてdockerを無駄に使っています。環境は以下です。

  • macOS Sierra
  • Docker for Mac Version 1.12.3-beta29.2

 とりあえずredisが入ったAlpine Linuxのイメージを作成します。my-alpineディレクトリを作りその中にDockerfileを以下の内容で作成します;

FROM alpine:latest
MAINTAINER ushumpei
RUN apk --no-cache add redis
CMD ["/bin/sh"]
$ docker build -t my-alpine .
$ docker run -it --rm  my-alpine

 redisがインストールされた状態でAlpine Linuxが起動しました。

単一マシン上で

 先ほどのmy-alpineを使って、同一ホストで複数のredisを起動し、master、slaveのレプリケーション構成を行ってみます;

/ # redis-server --port 3679 &
/ # redis-server --port 3680 --slaveof localhost 3679 &

 本当はちゃんと設定ファイルを書いたほうがいいんだと思います。レプリケーションを確認すると;

/ # redis-cli -p 3679 INFO
...
# Replication
role:master
connected_slaves:1
slave0:ip=::1,port=3680,state=online,offset=519,lag=1
...

/ # redis-cli -p 3680 INFO
...
# Replication
role:slave
master_host:localhost
master_port:3679
...

/ # redis-cli -p 3679 set hoge fuga
OK
/ # redis-cli -p 3680 get hoge
"fuga"

とちゃんとなっているようです。

docker

 docker-composeでmaster: 1台、slave: 2台の構成を作ってみようと思います。新たにディレクトリ(docker-redisにしました)を作成し、その中にdocker-compose.ymlを以下のように作成しました。

version: '2' 

services:
  master:
    image: redis:latest
    restart: always
    ports:
      - 3679:3679
  slave_1:
    image: redis:latest
    restart: always
    ports:
      - 3680:3679
    command: redis-server --slaveof master 6379
  slave_2:
    image: redis:latest
    restart: always
    ports:
      - 3681:3679
    command: redis-server --slaveof master 6379

 slave_1slave_2からはmasterhostmasterで参照できるようになっているようで、分かるまで悩みました(参考: Compose のネットワーク機能)。docker-compose upで起動します。

 動作確認を先ほどのmy-alpineから行います。--netオプションで先ほどのdocker-compose upで起動したコンテナたちのネットワークに参加します。こうすることで、masterなどのホストを参照することができるようになります。

(ネットワーク名はデフォルトではディレクトリ名_defaultになるらしく、docker network lsでも確認できます。ディレクトリのハイフンが無視されています、どういうルールでしょう?)

$ docker run -it --rm --net dockerredis_default my-alpine

/ # redis-cli -h master INFO
...
# Replication
role:master
connected_slaves:2
slave0:ip=172.19.0.4,port=6379,state=online,offset=2367,lag=1
slave1:ip=172.19.0.2,port=6379,state=online,offset=2367,lag=1
...

/ # redis-cli -h slave_1 INFO
...
# Replication
role:slave
master_host:master
master_port:6379
...

/ # redis-cli -h slave_2 INFO
# Replication
role:slave
master_host:master
master_port:6379
...

/ # redis-cli -h master set hoge fuga
OK
/ # redis-cli -h slave_1 get hoge
"fuga"
/ # redis-cli -h slave_2 get hoge
"fuga"

感想

 redisレプリケーションってすごく簡単にできるように思えました。pub/sub使って何か作ってみたいです。

¥eあるいはedit

 mysqlの対話環境でちょっと長い処理を実行したくなった時のメモです。

 mysqlコマンドを実行すると対話環境が起動します。ただ改行を含んだクエリを書こうとすると、どこか間違えた時に書き直すのが非常に面倒です。

 そういった時は¥eまたはeditコマンドを使うと便利です。コマンドを実行するとエディタが起動し直近に実行したクエリが表示されます。編集を行い保存して閉じるとコマンドを抜けて対話環境に戻ります。あとは;を入力してエンターキーを押せば内容が実行されます。毎回エンターキーを押すのも面倒な場合は、¥e;で実行します、この場合はエディタを閉じたら即時実行されます。

 開くエディタは選べるようです。私の環境ではデフォルトはviでした。これは環境変数EDITORで設定できます。(export EDITOR=vimとか設定しときました)

 調べたいクエリがあった時に、

  1. mysql> ¥e;実行
  2. vimが開くので挿入コマンド:a!でコピーしてきたクエリをペーストする
  3. 適宜修正して:wqvimを終了する
  4. 結果を確認し、必要なら1に戻る

 という感じで使っていました。

 ちなみに¥eを実行した時に編集しているファイルは/tmp以下に作成されていることが確認できました、しかしこれはエディタを閉じると削除されるようです。ちゃんと取っておきたいなら保存した方がいいと思います。(viなら:w ~/hogehogeなど)

感想

 rails consoleでもeditコマンドが使えるみたいですirbはダメか、コマンドが違うようです?)。他の対話環境ではどうなんでしょうか?

追記: 2017/01/13 - 今手元にあるrails 5で試してみると、editコマンドは使えないみたいです。動作が確認できていた環境はすでに手を離れてしまったので再確認できません。。。何かわかり次第追記します。

git logの折り返し

 gitのlogdiff表示時の、文字列の折り返しの切り替え方をメモします。

 自分の環境(mac 10.12terminalgit version 2.8.4 (Apple Git-73))ではデフォルトで折り返しがされていたのですが、以下の指定で折り返しが無効になりました。

折り返し無効

$ git config --global core.pager "less -S"

折り返し有効

$ git config --global core.pager "less -r"

 (デフォルトで有効だったので、折り返し有効のコマンドは未確認です。。。)

 git log --graph --decorateなどでログを見たい場合は、折り返さない方が見やすい気がします。

 ちなみにcore.pagergit loggit diffで表示するときの出力コマンドを指定しているそうで、lessSオプションをつけて折り返しの制御が行われているようです。catとかも指定できるようです。moreは私の環境では文字化けしました。

アロー関数(Arrow function)の書き方色々

 アロー関数は引数や戻り値の種類によって色々な書き方ができます。分割代入を使うことで柔軟な関数をシンプルに宣言できてとても気持ちいです。

 基本的な書き方から、やや直感的ではない書き方まで、メモしていこうと思います。

ざっくり

 アロー関数の記述方法は、引数に関しては、引数なし、引数1、引数N、引数オブジェクトリテラルによる分割代入、の4種類があります。関数の処理部分に関しては波括弧、括弧なし、丸括弧の3種類があります。

  • 引数1、括弧なし
  • 引数N、丸括弧
  • 引数オブジェクトリテラルによる分割代入、丸括弧
  • 引数なし、波括弧

 を並べてみます。

引数1、括弧なし

 引数が1のときは、引数の括弧は省略できて、右側が評価され戻り値が返ります。Promiseのcatchとかすっきりします。

const factorial = n => (n > 0) ? n * factorial(n-1) : 1;

引数N、丸括弧

 引数N個は単純にfunctionのときと同じように並べるだけです。戻り値にオブジェクトリテラルを返したいときに丸括弧を使うとすっきりです。

let projection = (a, b) => ({ 
  x: (2 * a) / (1 + a * a + b * b),
  y: (2 * b) / (1 + a * a + b * b),
  z: (-1 + a * a + b * b) / (1 + a * a + b * b),
});

引数オブジェクトリテラルによる分割代入、丸括弧

 上の例と近いです。ただ引数個数が頻繁に変わる可能性がある場合この記法がいいようです。ですが、個人的に好きなので何でもかんでもこれで書きたいです。Reactの純粋な関数スタイルのコンポーネントを書いたりするとき便利です。

const Deco = ({ deco, children }) => (
  <div>
    {deco + children + deco}
  </div>
);

 呼び出すときは引数で代入しているプロパティをもったオブジェクトを渡せば大丈夫です。引数いっぱいなのは嫌だけど、オブジェクトまるまる渡したら何されるかわからない、といった不安を綺麗に取り去ってくれます。

引数なし、波括弧

 グローバルなオブジェクトに対して何かしたいときに使う、気がします。波括弧なので複数行書くことができます。

const values = () => {
  const inputs = [...document.querySelectorAll('input')];
  const values = inputs.map(input => input.value)
  return values;
};

感想

 戻り値に関して補足です。1行で済む場合は括弧なしか丸括弧、複数行必要なときは波括弧でいいと思います。

 引数オブジェクトリテラルによる分割代入は、修正による影響を少なくできるし、オプションのようなものを渡すことが簡単にできるのでかなり好きです。

 説明の中で複数行とか言っていますが、宣言とか式とか、ちゃんとした言葉をいい加減覚えなければいけないなと思います。

Reactコンポーネントを純粋な関数で書こう

 Reactコンポーネントの書き方は色々あり、es6を使う場合の選択肢は以下の2つがあると思います;

  • クラス
  • 純粋な関数

クラス

 classの構文を使う場合、React.Componentクラスを継承してコンポーネントを定義します。

class App extends React.Component {
  render() {
    return (
      <div className="app-component">
        {this.props.hello}
      </div>
    );
  }
}

純粋な関数

純粋な関数としてコンポーネントを定義する場合、JSX記法で書いたDOMを返すような関数を記述します。なかなか直感的に書くことができます、親コンポーネントから渡されるpropsも引数として宣言します。

const App = ({ text }) => (
  <div className="app-component">
    {text}
  </div>
);

違いは?

 ざっくり言うと状態(state)を持つか持たないかのようです。クラス構文であればstateを持ったコンポーネントを作ることができますが、純粋な関数のコンポーネントではできません。純粋な関数のコンポーネントは引数(props)のみ使用し、実際それはコード上で関数の引数として表現されます。(2つの例でのtextの扱いの違いのような感じです)

 また純粋な関数のコンポーネントではrefが使えないそうです。その理由は説明によるとbacking instanceを持っていないから、だそうです。 静的コンポーネント、というイメージでしょうか。申し訳ないですが詳しくはこちらを参照くださいStateless functions

例:コンストラクタ内でstateを定義する。

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      ...
    };
  }
  ...
  render() {
    ...
  }
}

感想

 reduxチュートリアルで初めてStateless functionで書かれたReactコンポーネントを見ましたが、状態管理をreduxに任せる立場からするとそれは当然なんだろうな、と今になって思いました。

 ReactのStatelessなコンポーネントを作ることは、新しいhtmlのタグを定義することに近い気がしました。