代理
正向代理
通过正向代理服务地址 由正向代理服务器访问外部网络 由内部到外部访问
反向代理
将外部网络请求通过反向代理 中转给局域网的服务器 由外部到内部中转
upstream
-
server ip:端口或者unix套接字 修饰符
修饰符
weight 权重 默认为1 权重就越大 负载的概率越大
backup 备份 非备份机down或者忙的时候 请求备份机
down 停止使用
max_fails 最大失败次数 默认为1 超过最大次数时 返回proxy_next_upstream定义的错误
fail_timeout 最大失败次数后 暂停的时间 -
ip_hash 按照ip一致性hash分配
-
keepalive 设置每个worker进程与后端服务器(upstream中的server)保持连接的最大数量
一个连接池缓存的最大数目
这些保持的连接会被放入缓存 淘汰算法lru 淘汰最老的
upstream backend{
ip_hash;
##连接池缓存连接最大数目
keepalive=2000;
server 127.0.0.1:81 down;
server 127.0.0.1:82 weight=2;
server 127.0.0.1:83 max_fails=0 fail_timeout=1s;
server 127.0.0.1:84 backup;
}
proxy
-
proxy_connect_timeout
默认时间为60s 与upstream的server连接超时时间 -
proxy_buffers
proxy_buffers 4 64k;
缓冲区数目和每个缓冲区的大小 -
proxy_set_header X-Real-IP $remote_addr;
设置响应的头部
在php里$_SERVER[‘HTTP_X_REAL_IP’] -
proxy_next_upstream
什么时候 被转接到下一个upstream的server
proxy_next_upstream http_502 http_504 http_404 error timeout invalid_header non_idempotent; -
proxy_pass 连接方式 ip:端口 域名 或者套接字都可以的
###结尾有/ 表示绝对路径 没有相对路径
location /baidu {
proxy_pass http://www.baidu.com/ #有斜杠
}
###访问http://www.baidu.com
location /baidu{
proxy_pass http://www.baidu.com
}
###访问http://www.baidu.com/baidu
proxy_pass 192.168.1.78:80
#unix套接字连接方式
proxy_pass unix:/dev/shm/php-cgi.sock;
#连接upstream方式
proxy_pass http://backend;
location /{
proxy_connect_timeout 75s;
proxy_buffers 4 64k;
proxy_next_upstream error timeout invalid_header non_idempotent;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://myproject;
}
分配策略
- 一致性hash
上面的ip_hash 就是按照ip进行一致性hash分配
做过优化 解决 hash虚拟节点分布不均的问题
平均散列到1到2147483647之间
namespace helper\assign;
defined('IN')||exit;
class hashAssign
{
//节点(包含虚拟节点)
protected $_positionToTarget = array();
//主机节点
protected $_targetToPositions = array();
//排序
protected $_positionToTargetSorted = false;
protected $targetNum=1;
protected $replicas=1;
protected $HashList=array();
public function init($init=array())
{
$this->targetNum = isset($init[0])?$init[0]:10;
$this->replicas = isset($init[1])?$init[1]:100;
if(($this->replicas%$this->targetNum)!=0){
throw new \Exception('虚拟节点数必须是物理节点数的整数倍');
}
$chu=intval($this->replicas/$this->targetNum);
$this->HashList=$this->getHashList($this->replicas);
for ($i = 0; $i < $this->replicas; $i ++) {
$target=intval($i/$chu);
$position = $this->HashList[$i];
$this->_positionToTarget[$position] = $target;
$this->_targetToPositions[$target][$i] = $position;
}
$this->_positionToTargetSorted = false;
}
public function move($atarget=0,$starget=1,$replicasStart=10,$replicasEnd=100)
{
if (!isset($this->_targetToPositions[$starget])) {
throw new \Exception('物理节点 '.$starget.' 不存在.');
}
if (isset($this->_targetToPositions[$atarget])) {
throw new \Exception('物理节点 '.$atarget.' 已经存在.');
}
$this->_targetToPositions[$atarget] = array();
for($i = $replicasStart; $i <= $replicasEnd; $i++) {
$position = $this->HashList[$i];
if(!isset($this->_targetToPositions[$starget][$i])){
throw new \Exception('虚拟节点 '.$starget.'-'.$i.' 不存在.');
}
unset($this->_targetToPositions[$starget][$i]);
$this->_positionToTarget[$position] = $atarget;
$this->_targetToPositions[$atarget][$i] = $position;
}
$this->_positionToTargetSorted = false;
}
private function hash($hash)
{
return abs(crc32($hash));
}
private function getHashList($replicas=10)
{
$HashList=array();
$max=2147483647;
$num=intval($max/$replicas)+1;
for($i=0;$i<$replicas-1;$i++){
$HashList[$i]=$num*($i+1);
}
$HashList[]=2147483647;
return $HashList;
}
public function lookup($resource)
{
$targets = $this->lookupList($resource, 1);
if (empty($targets)){
throw new \Exception('No targets exist');
}
return $targets[0];
}
public function lookupList($resource,$requestedCount=1)
{
if(empty($this->_positionToTarget)){return array();}
$resourcePosition = $this->hash($resource);
$this->_sortPositionTargets();
return $this->find($this->_positionToTarget, $resourcePosition, $requestedCount);
}
protected function _sortPositionTargets()
{
if (!$this->_positionToTargetSorted) {
ksort($this->_positionToTarget, SORT_REGULAR);
$this->_positionToTargetSorted = true;
}
}
private function find($node,$resourcePosition,$requestedCount)
{
$results = array();
$collect = false;
foreach ($node as $key => $value) {
if (! $collect && $key > $resourcePosition) {
$collect = true;
}
if ($collect && ! in_array($value, $results)) {
$results[] = $value;
}
if (count($results) == $requestedCount) {
return $results;
}
}
foreach ($node as $key => $value) {
if (! in_array($value, $results)) {
$results[] = $value;
}
if (count($results) == $requestedCount) {
return $results;
}
}
return $results;
}
}
- 加权轮询策略
namespace helper\assign;
defined('IN')||exit;
class weightAssign
{
public $default_sign='default';
public function setHost($hosts)
{
return $this->host=$hosts;
}
public function getHostIndex($sign='')
{
$weight_sum = 0;
foreach ($this->host as $v) {
if (! isset($v['sign'])) {
$v['sign'] = $this->default_sign;
}
if ($v['sign'] != $sign) {
continue;
}
if (! isset($v['weight'])) {
$v['weight'] = 1;
}
$weight_sum += $v['weight'];
}
$roll = mt_rand(1, $weight_sum);
$tmp = 0;
foreach ($this->host as $k => $v) {
if (! isset($v['sign'])) {
$v['sign'] = $this->default_sign;
}
if ($v['sign'] != $sign) {
continue;
}
if (! isset($v['weight'])) {
$v['weight'] = 1;
}
$tmp += $v['weight'];
if ($tmp >= $roll) {
return $k;
}
}
}
}