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からも使うのを考えてたのでついでに載せておきました。