您的位置:首页 > 其它

[分布式会话]zuul通过Ribbon配置负载均衡策略实现粘性会话(sticky session)

2018-12-18 22:31 1351 查看

分布式Session处理方式

分布式Session一般分为以下几种处理方式:

  • 黏性会话(sticky session):通过使每个用户每访问的服务端实例为同一个来确保session的正常使用
  • 会话拷贝(session replication):通过各个服务端实例之间的session复制,来确保每个服务端实例均具有session中的信息,以达到session的一致性
  • 会话第三方管理:通过redis等第三方的工具来存储session信息,使所有服务器实例均能访问到相同的session

黏性Session

实现粘性会话的方式主要在于确保每个用户在通过Session有效期内,访问的服务器实例为同一台,以此来保证Session信息保持

在分布式系统中,通常所有用户都会通过统一的入口(即网关Gateway)来访问系统,因此我们只需要在网关处确保用户请求的转发目的地是同一个就可以完成。而这通过实现负载均衡的策略来实现。

在使用SpringCloud进行开发的过程中,如果使用的网关服务zuul使用Ribbon实现负载均衡,则可以使用如下的方式实现一个策略来保证:

/**
* 对访问者地址进行hash计算,使同一访问者访问同一实例
* 参考自
* @see  com.netflix.loadbalancer.RoundRobinRule
* @author YWS
* @data 2018/11/08
*/
public class StickyLoadBalancerRule extends AbstractLoadBalancerRule {

private static final Logger logger = LoggerFactory.getLogger(StickyLoadBalancerRule.class);

public StickyLoadBalancerRule() {}

public StickyLoadBalancerRule(ILoadBalancer lb) {
this();
this.setLoadBalancer(lb);
}

@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {}

@Override
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}

public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
logger.warn("no load balancer");
return null;
} else {
Server server = null;
int count = 0;

while (true) {
if (server == null && count++ < 10) {
List<Server> reachableServers = lb.getReachableServers();
List<Server> allServers = lb.getAllServers();
int upCount = reachableServers.size();
int serverCount = allServers.size();
if (upCount != 0 && serverCount != 0) {
int nextServerIndex = this.addrHash(serverCount, count);
List<Server> tArr = new ArrayList(allServers);
tArr.sort(Comparator.comparing(Server::getHost));
server = tArr.get(nextServerIndex);
if (server != null && server.isAlive() && server.isReadyToServe()) {
return server;
} else {
server = null;
}
continue;
}

logger.warn("No up servers available from load balancer: {}", lb);
return null;
}

if (count >= 10) {
logger.warn("No available alive servers after 10 tries from load balancer: {}", lb);
}

return server;
}
}
}

public int addrHash(int serverCount, int offset) {
String remoteAddr = this.getRemoteAddr();
return Math.abs(remoteAddr.hashCode() + offset) % serverCount;
}

public String getRemoteAddr() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String forwardedFor = request.getHeader("X-FORWARDED-FOR");
String remoteAddr = StringUtils.isEmpty(forwardedFor) ? request.getRemoteAddr() : forwardedFor;
return remoteAddr;
}
}

扩展文章

[分布式会话]springboot中实现session replication

GitHub

github.yws179

阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐