ruby Consistent String#仅基于字符串内容的哈希

ggazkfy8  于 12个月前  发布在  Ruby
关注(0)|答案(5)|浏览(102)

**GOAL:**将服务器处理的每个URLMap为0、1、2或3,尽可能均匀分布。

虽然ruby的String#hash方法的文档中说它将“根据字符串的长度和内容返回一个哈希值”,但这显然不是故事的全部。给定字符串的哈希在解释器的调用中不一致:

$ irb
ruby-1.9.2-p180 :001 > "foo".hash
 => 360517580588231756 
ruby-1.9.2-p180 :002 > ^D

$ irb
ruby-1.9.2-p180 :001 > "foo".hash
 => -2716152678666510148

这意味着特定字符串的哈希值可能在不同的服务器上有所不同。Rails在内部使用String#hash将URL路径Map到四个资产主机之一(如果应用程序的asset_host是so configured),但由于跨机器的不一致性,该功能的效率要低得多;不同的服务器可能将相同的URLMap到不同的资产主机,降低了缓存的有效性,使天空变得乌云密布,过早地冷却了茶杯,玷污了其他优秀程序员的声誉。
你能建议一个替代的哈希函数,可以有效地和快速地在一个典型的应用程序的URL空间中分发哈希,最好是一个产生Fixnum的函数,因为最后,我想把它Map到四个资产主机中的一个?

gijlo24d

gijlo24d1#

在ruby的digest模块中有很多这样的功能:http://ruby-doc.org/stdlib/libdoc/digest/rdoc/index.html
简单示例:

require 'digest/sha1'
Digest::SHA1.hexdigest("some string")
hrirmatl

hrirmatl2#

最简单的(和一致的)方法可能是这样的(而且很快):

"https://www.example.com/abc/def/123?hij=345".sum % 4

这将总是产生一个整数0 - 3,是相当快的,应该是相当好的分布(虽然我还没有实际运行分布测试)。

vlju58qv

vlju58qv3#

有一个小型库xxHash

XXhash.xxh32('qwe') #=> 2396643526
XXhash.xxh64('qwe') #=> 9343136760830690622

也许它会有更多的碰撞,但它比SHA1快10倍:

Benchmark.bm do |x|
  n = 100_000
  str = 'qweqweqwe'
  x.report('xxhash32') { n.times { XXhash.xxh32(str) } }
  x.report('xxhash64') { n.times { XXhash.xxh64(str) } }
  x.report('hexadigest') { n.times { Digest::SHA1.hexdigest(str) } }
end;1

#       user     system      total        real
# xxhash32  0.020000   0.000000   0.020000 (  0.021948)
# xxhash64  0.040000   0.000000   0.040000 (  0.036340)
# hexadigest  0.240000   0.030000   0.270000 (  0.276443)
u4vypkhs

u4vypkhs4#

你可以尝试_i(36)。

"Hash me please :(".to_i(36)
=> 807137
ktecyv1j

ktecyv1j5#

Ruby on Rails:

ActiveSupport::Digest.hexdigest("hello")
 # =>  "2cf24dba5fb0a30e26e83b2ac5b9e29e"

https://github.com/rails/rails/blob/main/activesupport/lib/active_support/digest.rb

相关问题