PHP 구현 의 일치 성 Hash 알고리즘 상세 설명[분산 알고리즘]

15144 단어 PHP해시 알고리즘
이 글 의 사례 는 PHP 가 실현 하 는 일치 성 Hash 알고리즘 을 서술 하 였 다.여러분 께 참고 하도록 공유 하 겠 습 니 다.구체 적 으로 는 다음 과 같 습 니 다.
일치 성 해시 알고리즘 은 분포 식 시스템 에서 자주 사용 하 는 알고리즘 인 데 왜 이 알고리즘 을 사용 합 니까?
예 를 들 어 분포 식 저장 시스템 은 데 이 터 를 구체 적 인 노드(서버)에 저장 해 야 한다.서버 수량 이 변 하지 않 는 상황 에서 일반적인 hash 를 사용 하여 서버 총 수량 을 모델 링 하 는 방법(예 를 들 어 key%서버 총 수량)을 사용 하면 그 동안 서버 가 다운 되 거나 서버 를 늘 려 야 한다 면 문제 가 발생 한다.같은 key 가 hash 를 거 친 후에 서버 의 총 수량 과 모델 링 결 과 는 이전 결과 와 다 르 기 때문에 이전에 저 장 된 데 이 터 를 잃 어 버 렸 습 니 다.따라서 일치 성 Hash(Consistent Hashing)분포 알고리즘 을 도입 했다.

데 이 터 를 hash 함수(예 를 들 어 md5,sha 1)로 원 링 에 투사 합 니 다.위의 그림 에서 보 듯 이 데 이 터 를 저장 할 때 hash 알고리즘 에 따라 key 의 hash 값 을 계산 하고 이 링 의 위치 에 대응 합 니 다.예 를 들 어 k1 대응 그림 에서 보 여 준 위치 가 같 습 니 다.그리고 시계 방향 으로 서버 노드 B 를 찾 은 다음 에 k1 을 B 노드 에 저장 합 니 다.
만약 에 B 노드 가 지연 되면 B 의 데 이 터 는 C 노드 에 떨 어 질 것 이다.아래 그림 과 같다.

이렇게 하면 C 노드 에 만 영향 을 주 고 다른 노드 A,D 의 데이터 에 영향 을 주지 않 는 다.그러나 문제 가 생 겼 다.그러면 C 노드 의 부하 가 너무 무 거 운 상황 을 초래 할 수 있다.C 노드 가 B 노드 의 데 이 터 를 부담 하기 때문에 C 노드 가 쉽게 지연 되 고 분포 가 고 르 지 않다.
이 문 제 를 해결 하기 위해'가상 노드'라 는 개념 을 도입 했다.즉,빈 고리 에'가상 노드'가 많다 고 상상 하고 진실 한 서버 노드 는 여러 개의 가상 노드 에 대응 하 며 데 이 터 를 저장 할 때 링 의 시계 방향 을 따라 가상 노드 를 찾 으 면 해당 하 는 실제 서버 노드 를 찾 을 수 있다.아래 그림

그림 속 A1,A2,B1,B2,C1,C2,D1,D2 는 모두 가상 노드 이 고 기계 A 는 A1,A2 의 데 이 터 를 부하 로 저장 하 며 기계 B 는 B1,B2 의 데 이 터 를 부하 로 저장 하고 기계 C 는 C1,C2 의 데 이 터 를 부하 로 저장한다.이러한 가상 노드 의 수량 이 매우 많 고 고 르 게 분포 하기 때문에'눈사태'현상 을 일 으 키 지 않 을 것 이다.
일치 성 해시 알고리즘 PHP 구현
다음은 인 터 페 이 스 를 드 리 겠 습 니 다.

/**
 *          
 * Interface ConsistentHash
 */
interface ConsistentHash
{
 //      hash 
 public function cHash($str);
 //              
 public function addServer($server);
 //           
 public function removeServer($server);
 //                      
 public function lookup($key);
}

이 인 터 페 이 스 는 각각 4 가지 방법 을 정의 합 니 다.cHash(문자열 을 hash 값 으로 처리),addServer(서버 한 대 추가),removeServer(서버 한 대 제거),lookup(서버 한 대 를 찾 아 데 이 터 를 저장 합 니 다)
다음은 이 인터페이스의 구체 적 인 실현 을 제시 합 니 다.

/**
 *          
 * author chenqionghe
 * Class MyConsistentHash
 */
class MyConsistentHash implements ConsistentHash
{
 public $serverList = array(); //      
 public $virtualPos = array(); //       
 public $virtualPosNum = 5;  //      5    
 /**
  *        32      hash 
  * @param $str
  * @return int
  */
 public function cHash($str)
 {
  $str = md5($str);
  return sprintf('%u', crc32($str));
 }
 /**
  *                       
  * @param $key   
  * @return mixed      IP  
  */
 public function lookup($key)
 {
  $point = $this->cHash($key);//   hash 
  $finalServer = current($this->virtualPos);//                
  foreach($this->virtualPos as $pos=>$server)
  {
   if($point <= $pos)
   {
    $finalServer = $server;
    break;
   }
  }
  reset($this->virtualPos);//           
  return $finalServer;
 }
 /**
  *               
  * @param $server    IP  
  * @return bool
  */
 public function addServer($server)
 {
  if(!isset($this->serverList[$server]))
  {
   for($i=0; $i<$this->virtualPosNum; $i++)
   {
    $pos = $this->cHash($server . '-' . $i);
    $this->virtualPos[$pos] = $server;
    $this->serverList[$server][] = $pos;
   }
   ksort($this->virtualPos,SORT_NUMERIC);
  }
  return TRUE;
 }
 /**
  *        (        ,              )
  * @param $key
  * @return bool
  */
 public function removeServer($key)
 {
  if(isset($this->serverList[$key]))
  {
   //       
   foreach($this->serverList[$key] as $pos)
   {
    unset($this->virtualPos[$pos]);
   }
   //       
   unset($this->serverList[$key]);
  }
  return TRUE;
 }
}

그리고 이 알고리즘 을 테스트 해 보 겠 습 니 다.

$hashServer = new MyConsistentHash();
$hashServer->addServer('192.168.1.1');
$hashServer->addServer('192.168.1.2');
$hashServer->addServer('192.168.1.3');
$hashServer->addServer('192.168.1.4');
$hashServer->addServer('192.168.1.5');
$hashServer->addServer('192.168.1.6');
$hashServer->addServer('192.168.1.7');
$hashServer->addServer('192.168.1.8');
$hashServer->addServer('192.168.1.9');
$hashServer->addServer('192.168.1.10');
echo "       192.168.1.1~192.168.1.10<br />";
echo "   key1   server :".$hashServer->lookup('key1') . '<br />';
echo "   key2   server :".$hashServer->lookup('key2') . '<br />';
echo "   key3   server :".$hashServer->lookup('key3') . '<br />';
echo "   key4   server :".$hashServer->lookup('key4') . '<br />';
echo "   key5   server :".$hashServer->lookup('key5') . '<br />';
echo "   key6   server :".$hashServer->lookup('key6') . '<br />';
echo "   key7   server :".$hashServer->lookup('key7') . '<br />';
echo "   key8   server :".$hashServer->lookup('key8') . '<br />';
echo "   key9   server :".$hashServer->lookup('key9') . '<br />';
echo "   key10   server :".$hashServer->lookup('key10') . '<br />';
echo '<hr />';
echo "       192.168.1.2<br />";
$hashServer->removeServer('192.168.1.2');
echo "   key1   server :".$hashServer->lookup('key1') . '<br />';
echo "   key2   server :".$hashServer->lookup('key2') . '<br />';
echo "   key3   server :".$hashServer->lookup('key3') . '<br />';
echo "   key4   server :".$hashServer->lookup('key4') . '<br />';
echo "   key5   server :".$hashServer->lookup('key5') . '<br />';
echo "   key6   server :".$hashServer->lookup('key6') . '<br />';
echo "   key7   server :".$hashServer->lookup('key7') . '<br />';
echo "   key8   server :".$hashServer->lookup('key8') . '<br />';
echo "   key9   server :".$hashServer->lookup('key9') . '<br />';
echo "   key10   server :".$hashServer->lookup('key10') . '<br />';
echo '<hr />';
echo "       192.168.1.6<br />";
$hashServer->removeServer('192.168.1.6');
echo "   key1   server :".$hashServer->lookup('key1') . '<br />';
echo "   key2   server :".$hashServer->lookup('key2') . '<br />';
echo "   key3   server :".$hashServer->lookup('key3') . '<br />';
echo "   key4   server :".$hashServer->lookup('key4') . '<br />';
echo "   key5   server :".$hashServer->lookup('key5') . '<br />';
echo "   key6   server :".$hashServer->lookup('key6') . '<br />';
echo "   key7   server :".$hashServer->lookup('key7') . '<br />';
echo "   key8   server :".$hashServer->lookup('key8') . '<br />';
echo "   key9   server :".$hashServer->lookup('key9') . '<br />';
echo "   key10   server :".$hashServer->lookup('key10') . '<br />';
echo '<hr />';
echo "       192.168.1.8<br />";
$hashServer->removeServer('192.168.1.8');
echo "   key1   server :".$hashServer->lookup('key1') . '<br />';
echo "   key2   server :".$hashServer->lookup('key2') . '<br />';
echo "   key3   server :".$hashServer->lookup('key3') . '<br />';
echo "   key4   server :".$hashServer->lookup('key4') . '<br />';
echo "   key5   server :".$hashServer->lookup('key5') . '<br />';
echo "   key6   server :".$hashServer->lookup('key6') . '<br />';
echo "   key7   server :".$hashServer->lookup('key7') . '<br />';
echo "   key8   server :".$hashServer->lookup('key8') . '<br />';
echo "   key9   server :".$hashServer->lookup('key9') . '<br />';
echo "   key10   server :".$hashServer->lookup('key10') . '<br />';
echo '<hr />';
echo "       192.168.1.2<br />";
$hashServer->removeServer('192.168.1.2');
echo "   key1   server :".$hashServer->lookup('key1') . '<br />';
echo "   key2   server :".$hashServer->lookup('key2') . '<br />';
echo "   key3   server :".$hashServer->lookup('key3') . '<br />';
echo "   key4   server :".$hashServer->lookup('key4') . '<br />';
echo "   key5   server :".$hashServer->lookup('key5') . '<br />';
echo "   key6   server :".$hashServer->lookup('key6') . '<br />';
echo "   key7   server :".$hashServer->lookup('key7') . '<br />';
echo "   key8   server :".$hashServer->lookup('key8') . '<br />';
echo "   key9   server :".$hashServer->lookup('key9') . '<br />';
echo "   key10   server :".$hashServer->lookup('key10') . '<br />';
echo '<hr />';
echo "       192.168.1.11<br />";
$hashServer->addServer('192.168.1.11');
echo "   key1   server :".$hashServer->lookup('key1') . '<br />';
echo "   key2   server :".$hashServer->lookup('key2') . '<br />';
echo "   key3   server :".$hashServer->lookup('key3') . '<br />';
echo "   key4   server :".$hashServer->lookup('key4') . '<br />';
echo "   key5   server :".$hashServer->lookup('key5') . '<br />';
echo "   key6   server :".$hashServer->lookup('key6') . '<br />';
echo "   key7   server :".$hashServer->lookup('key7') . '<br />';
echo "   key8   server :".$hashServer->lookup('key8') . '<br />';
echo "   key9   server :".$hashServer->lookup('key9') . '<br />';
echo "   key10   server :".$hashServer->lookup('key10') . '<br />';
echo '<hr />';

실행 결 과 는 다음 과 같다.
서버 10 대 증가 192.168.1.1~192.168.1.10
키 1 을 server 에 저장 하기:192.168.1.2
키 2 를 server 에 저장 하기:192.168.1.1
key 3 를 server 에 저장 하기:192.168.1.6
키 4 를 server 에 저장 하기:192.168.1.8
키 5 를 server 에 저장 하기:192.168.1.9
키 6 을 server 에 저장 하기:192.168.1.10
키 7 을 server 에 저장 하기:192.168.1.7
키 8 을 server 에 저장 하기:192.168.1.4
server 에 key 9 저장 하기:192.168.1.7
key 10 을 server 에 저장:192.168.1.4
서버 192.168.1.2 제거
키 1 을 server 에 저장 하기:192.168.1.7
키 2 를 server 에 저장 하기:192.168.1.1
key 3 를 server 에 저장 하기:192.168.1.6
키 4 를 server 에 저장 하기:192.168.1.8
키 5 를 server 에 저장 하기:192.168.1.9
키 6 을 server 에 저장 하기:192.168.1.10
키 7 을 server 에 저장 하기:192.168.1.7
키 8 을 server 에 저장 하기:192.168.1.4
server 에 key 9 저장 하기:192.168.1.7
key 10 을 server 에 저장:192.168.1.4
서버 192.168.1.6 제거
키 1 을 server 에 저장 하기:192.168.1.7
키 2 를 server 에 저장 하기:192.168.1.1
server 에 key 3 저장:192.168.1.3
키 4 를 server 에 저장 하기:192.168.1.8
키 5 를 server 에 저장 하기:192.168.1.9
키 6 을 server 에 저장 하기:192.168.1.10
키 7 을 server 에 저장 하기:192.168.1.7
키 8 을 server 에 저장 하기:192.168.1.4
server 에 key 9 저장 하기:192.168.1.7
key 10 을 server 에 저장:192.168.1.4
서버 192.168.1.8 제거
키 1 을 server 에 저장 하기:192.168.1.7
키 2 를 server 에 저장 하기:192.168.1.1
server 에 key 3 저장:192.168.1.3
키 4 를 server 에 저장 하기:192.168.1.10
키 5 를 server 에 저장 하기:192.168.1.9
키 6 을 server 에 저장 하기:192.168.1.10
키 7 을 server 에 저장 하기:192.168.1.7
키 8 을 server 에 저장 하기:192.168.1.4
server 에 key 9 저장 하기:192.168.1.7
key 10 을 server 에 저장:192.168.1.4
서버 192.168.1.2 제거
키 1 을 server 에 저장 하기:192.168.1.7
키 2 를 server 에 저장 하기:192.168.1.1
server 에 key 3 저장:192.168.1.3
키 4 를 server 에 저장 하기:192.168.1.10
키 5 를 server 에 저장 하기:192.168.1.9
키 6 을 server 에 저장 하기:192.168.1.10
키 7 을 server 에 저장 하기:192.168.1.7
키 8 을 server 에 저장 하기:192.168.1.4
server 에 key 9 저장 하기:192.168.1.7
key 10 을 server 에 저장:192.168.1.4
서버 한 대 추가 192.168.11
키 1 을 server 에 저장 하기:192.168.1.7
키 2 를 server 에 저장 하기:192.168.1.1
server 에 key 3 저장:192.168.11
키 4 를 server 에 저장 하기:192.168.1.10
키 5 를 server 에 저장 하기:192.168.1.9
키 6 을 server 에 저장 하기:192.168.1.10
키 7 을 server 에 저장 하기:192.168.1.7
키 8 을 server 에 저장 하기:192.168.1.4
server 에 key 9 저장 하기:192.168.1.7
key 10 을 server 에 저장:192.168.1.4
이 를 통 해 알 수 있 듯 이 일치 성 하 시 를 사용 한 후에 서버 를 증가 시 키 는 지 서버 를 감소 시 키 는 지 데이터 의 완전 성,균일 성 을 최대한 확보 했다.
PS:여기 서 hash 관련 온라인 도 구 를 2 가지 더 제공 하여 참고 하 시기 바 랍 니 다.
온라인 해시/해시 알고리즘 암호 화 도구:
http://tools.jb51.net/password/hash_encrypt
온라인 MD5/hash/SHA-1/SHA-2/SHA-256/SHA-512/SHA-3/RIPEMD-160 암호 화 도구:
http://tools.jb51.net/password/hash_md5_sha
더 많은 PHP 관련 내용 에 관심 이 있 는 독자 들 은 본 사이트 의 주 제 를 볼 수 있다.
본 논문 에서 말 한 것 이 여러분 의 PHP 프로 그래 밍 에 도움 이 되 기 를 바 랍 니 다.

좋은 웹페이지 즐겨찾기