3. ip_hash算法:
①. 公式:
hashcode(客户端Ip) % size
②. 类似nginx负载均衡配置:
upstream lb {
server xxxxxx1;
server xxxxxx2;
ip_hash;
}
(1). 算法公共类:
app\Consul\ServiceSelector.php:
namespace App\Consul;
class ServiceSelector {
...
public static function selectByIPHash(string $ip, array $serviceList) : array
{
$index = crc32($ip) % count($serviceList);
$key = array_keys($serviceList)[$index];
return $serviceList[$key];
}
}
注:
①. crc32算法(循环冗余校验):只要内容是一致的,获取的校验码就是一致的.
(2). 调用方法:
app\Http\MyClient.php:
use App\Consul\ServiceSelector;
...
/**
* @RequestMapping(router="getOneService", method={RequestMethod::GET})
*/
public function getOneService(): array
{
// 静态方法调用
return ServiceSelector::selectByIPHash(ip(), $this->getHealthService());
}
(3). 全局函数:
app\Helper\Functions.php:
function request() {
return Swoft\Context\Context::get()->getRequest();
}
function ip(){
$req=request();
if ($req->server('http_x_forwarded_for')) {
return $req->server('http_x_forwarded_for');
} elseif ($req->server('http_client_ip')) {
return $req->server('http_client_ip');
} else {
return $req->server('remote_addr');
}
}
(4). 总结:
①. 只要是这个IP,就永远返回这个服务.可以解决保持session一致的问题.
②. 但是服务列表的总数发生变化呢?
4. 简单的轮训算法:
一个一个轮着来,最简单做法,是弄个变量保存到bean中(有权重就不一样了).
(1). 追加方式轮训:
namespace App\Consul;
use Swoft\Bean\Annotation\Mapping\Bean;
/**
* @Bean()
*/
class ServiceSelector {
...
private static $nodeIndex = 0;
public static function selectByRoundRobin(array $serviceList) {
if(self::$nodeIndex>=count($serviceList)){
self::$nodeIndex = 0;
}
$getKey=array_keys($serviceList)[self::$nodeIndex];
self::$nodeIndex++;
return $serviceList[$getKey];
}
}
(2). 取余方式轮训:
namespace App\Consul;
use Swoft\Bean\Annotation\Mapping\Bean;
/**
* @Bean()
*/
class ServiceSelector {
...
private static $nodeIndex = 0;
public static function selectByRoundRobin(array $serviceList) {
$getKey=array_keys($serviceList)[self::$nodeIndex];
self::$nodeIndex = (self::$nodeIndex + 1) % count($serviceList);
return $serviceList[$getKey];
}
}