備忘録、はじめました。

作業したこと忘れないようにメモっておきます。

erlangでsnowflakeを実装してみた

はじめに

erlang製のsnowflakeほしいなと言う思いで色々探していて、思い描く感じのがなかったので自作してみた話。

リンク: GitHub - tkyshm/esnowflake: Uniq id generator based on Twitter's snowflake in Erlang

実装

snowflakeアルゴリズムに関しては以下を参照していただければわかるはず。

www.slideshare.net

snowflakeのnodeは最大1024台立ち上げることができ、machine_id に0~1023を割り当てることが出来ます。 esnowflakeでは、この設定をworker_min_max_idで設定できるようにし、 1つのesnowflakeで複数のmachine_idを持てるように設計しています。

以下、アプリケーションの設定で起動するworker数を設定できます。

[
    {esnowflake, [{worker_min_max_id, [0, 1]}]}
]

使い方

% IDを生成
> Id = esnowflake:generate_id().
896221795344384

% IDを複数生成
> esnowflake:generate_ids(2).
[896498611015681,896498611015680]

% IDからUnixTime(ミリ秒)取得
> esnowflake:to_unixtime(Id).
1509193995927

% IDからUnixTime(秒)取得
> esnowflake:to_unixtime(Id, seconds).
1509193995

% UnixTime(ミリ秒)からID(最小値)を知りたいとき
> esnowflake:unixtime_to_id(1509193995927).
896221795319808

% UnixTime(秒)からID(最小値)を知りたいとき
> esnowflake:unixtime_to_id(1509193995, seconds).
896217907200000

generate_idのベンチ

# (1個生成を100,000回施行した平均値)
----------------------------------------------------
2017-10-29 16:03:27.671
b_generate_id   100000  4564.13864 ns/op


----------------------------------------------------
2017-10-29 16:03:28.703
b_generate_id   232502 op/sec

%%% esnowflake_SUITE ==> bench.b_generate_id: OK


# (100個生成を10,000回施行した平均値)
----------------------------------------------------
2017-10-29 16:03:29.700
b_generate_ids_100  10000   96834.8342 ns/op


----------------------------------------------------
2017-10-29 16:03:30.702
b_generate_ids_100  686 op/sec

%%% esnowflake_SUITE ==> bench.b_generate_ids: OK

おまけ(elixirからつかう)

  # mix.exsのdeps
  defp deps do
    [
      {:esnowflake, "~> 0.2.0"}
    ]
  end
elixir/sample » iex -S mix
Erlang/OTP 20 [erts-9.0.1] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]

Interactive Elixir (1.5.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> t = :esnowflake.generate_id()
20433515594121216

iex(2)> t = :esnowflake.to_unixtime(id) 
1513852072018

iex(3)> t2 = :esnowflake.to_unixtime(id, :seconds)
1513852072

iex(4)> :esnowflake.unixtime_to_id(t2, :seconds)
20433608900608000

iex(5)> :esnowflake.generate_ids(10) 
[20434393545850889, 20434393545850888, 20434393545850887, 20434393545850886,
 20434393545850885, 20434393545850884, 20434393545850883, 20434393545850882,
 20434393545850881, 20434393545850880]

感想

1台1台にworker数の設定をするのは面倒な気がするので、worker idを動的に割り当てできる方法は考え中です。 何かいい方法を思いついて、時間があれば追加で作ろうかと思ってます。

台数制限があるのにworker数が取得できないのは問題あるので、取得できるようにする予定。

おまけのは元々elixirからも使うのを考えてたのでついでに載せておきました。

参照URL

Twitterのsnowflakeについて

GitHub - kayac/go-katsubushi: ID generator server