UUID
ちょっと見てたのでまとめ。
- Universally Unique Identifier - Wikipedia
- RFC 4122 (rfc4122) - A Universally Unique IDentifier (UUID) URN Namespace
UUID とは、Universally Unique Identifier の略で、分散システム上でどこかが統制を取らずとも、一意に特定可能な識別子。全部で 16 bytes (128 bits) の数字で表され、ABNF は以下のとおり。
UUID = time-low "-" time-mid "-" time-high-and-version "-" clock-seq-and-reserved clock-seq-low "-" node time-low = 4hexOctet time-mid = 2hexOctet time-high-and-version = 2hexOctet clock-seq-and-reserved = hexOctet clock-seq-low = hexOctet node = 6hexOctet hexOctet = hexDigit hexDigit hexDigit = "0" / "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" / "a" / "b" / "c" / "d" / "e" / "f" / "A" / "B" / "C" / "D" / "E" / "F"
RFC 4122 のなかでは、UUID の生成に関して、バージョン番号1、3、4、5 で識別される4つのアルゴリズムを規定。
- Version1
- MACアドレスとタイムスタンプが含まれるので、コンピュータの識別や生成時刻の特定が可能。ある種のセキュリティに注意すべきアプリケーションでは適さない。
- Version3
- Version4
- ランダムな数から生成。
- Version5
- Version3 と似ているが、ハッシュ方式に SHA-1 を使用。その分安全。
で、Ruby での実装をみてみる。
wikipedia:en:uuid によると、以下の3つ。
- Ruby-UUID: 最新バージョンは 2007.12.30 に CodeRepos に移行した 0.1
- UUID: 最新バージョンは 2008.8.27 公開の 2.0.1
- UUIDTools: 最新バージョンは 2008.12.4 公開の 1.0.7
Rubyforge で探すと uuid4r や guid とかも見つかる。
- Guid: Guid is a Ruby library for portable GUID/UUID generation. At the moment it can be used on Windows (except first release of Win95 and older) and on Unix.
- UUID4R: This is a wrapper of OSSP uuid C library, and can generate and parse UUID.
メンテナンス状況とかをみると、UUID と UUIDTools がアクティブっぽい。
さらにソースをみてみる。
uuidtools-1.0.7 は、実直にバージョン1、3、4、5 を実装している。
使い方は、それぞれこんな感じで、to_s すると 16 bytes の文字列が得られる。
UUID.timestamp_create => #<UUID:0x2adfdc UUID:64a5189c-25b3-11da-a97b-00c04fd430c8> UUID.md5_create(UUID_DNS_NAMESPACE, "www.widgets.com") => #<UUID:0x287576 UUID:3d813cbb-47fb-32ba-91df-831e1593ac29> UUID.random_create => #<UUID:0x19013a UUID:984265dc-4200-4f02-ae70-fe4f48964159> UUID.sha1_create(UUID_DNS_NAMESPACE, "www.widgets.com") => #<UUID:0x2a0116 UUID:21f7f8de-8051-5b89-8680-0195ef798b6a>
一方の uuid-2.0.1 は、バージョン1 のみの実装。ある意味、男前。
uuid = UUID.new 10.times do p uuid.generate end
ちなみに、前のバージョンである、uuid-1.0.4 の使い方は微妙に違っていた。 :(
10.times do p UUID.new end
機能の差は歴然なので、ベンチマークをとってみる。比較対象は、いずれもバージョン1 のアルゴリズムで、UUID を1万回生成してみる。
% gem list --local uuid *** LOCAL GEMS *** uuid (2.0.1, 1.0.4) uuidtools (1.0.7) % ruby186 uuid_bench.rb uuidtools-1.0.7 10000 benchmark target: uuidtools-1.0.7 user system total real UUID.timestamp_create.to_s: 0.720000 0.010000 0.730000 ( 0.775910) % ruby186 uuid_bench.rb uuid-1.0.4 10000 benchmark target: uuid-1.0.4 user system total real UUID.new: 0.150000 0.000000 0.150000 ( 0.156139) % ruby186 uuid_bench.rb uuid-2.0.1 10000 benchmark target: uuid-2.0.1 user system total real @uuid.generate: 0.140000 0.010000 0.150000 ( 0.150422) UUID.generate: 0.160000 0.000000 0.160000 ( 0.164215) UUID.new.generate: 1.030000 1.260000 2.290000 ( 13.347787)
API は (機能が少ない分) わかりやすいので、セキュリティの問題がなければ、uuid-x.x.x で十分かも?
# 最後の UUID.new.generate はふつうやらないと思うけど、一応やってみた。 :-p
以下、ベンチマークに使用したプログラム。
require 'benchmark' require 'rubygems' puts "Usage: ruby uuid_bench.rb target_uuid repeat_count" if ARGV.size < 2 name, version = ARGV[0].split("-") count = ARGV[1].to_i # switch version gem "#{name}", "= #{version}" require "#{name}" puts "benchmark target: #{name}-#{version}" def iterate(count, &block) count.times do yield block end end # main Benchmark.bm(30) do |x| case name when "uuid" uuid = UUID.new if uuid.kind_of? String # uuid-1.x.x x.report("UUID.new:") {iterate(count) {UUID.new}} elsif uuid.kind_of? UUID # uuid-2.x.x x.report("@uuid.generate:") {iterate(count) {uuid.generate}} x.report("UUID.generate:") {iterate(count) {UUID.generate}} x.report('UUID.new.generate:') {iterate(count) {UUID.new.generate}} end when "uuidtools" x.report('UUID.timestamp_create.to_s:') {iterate(count) {UUID.timestamp_create.to_s}} end end