Distributed Distributed Session -Zookeeper solve the consistency problem, implement Sentinel mechanism (Master election)

First, chat Session

1.1 What is Session

Session is a client-server communication session technology, such as the browser to log, record the entire browsing session information

1.2, Session realization principle

After the client sends a request to the server, Session created on the server side, returns SessionId to the client browser stored locally, the next time the retransmission request is transmitted sessionid acquires the corresponding acquired from the server in the request header of the session with.

1.3, Session FAQ

(1) Session guarantee there? - stored on the server

(2) close the browser Session fail it? - will not go away

1.4, involving relevant code to understand Session

@SpringBootApplication
@RestController
public class TestSessionController {

	// 创建session 会话
	@RequestMapping("/createSession")
	public String createSession(HttpServletRequest request, String nameValue) {
		HttpSession session = request.getSession();
		System.out.println("存入Session  sessionid:信息" + session.getId() + ",nameValue:" + nameValue);
		session.setAttribute("name", nameValue);
		return "success";
	}

	// 获取session 会话
	@RequestMapping("/getSession")
	public Object getSession(HttpServletRequest request) {
		HttpSession session = request.getSession();
		System.out.println("获取Session sessionid:信息" + session.getId());
		Object value = session.getAttribute("name");
		return value;
	}

	public static void main(String[] args) {
		SpringApplication.run(TestSessionController.class, args);
	}
}

1.5, server clustering Session will produce what issues

Session will lead to inconsistencies . After the server generates a cluster, because session is stored on the server, the client will use the same sessionid get less than the corresponding Session on many different servers.

 

Second, the solution to the problem of distributed consistency Session

2.1, several solutions to understand

(1) nginx or haproxy implementation of IP binding:

Nginx to do with load balancing can add ip_hash this configuration,

Haproxy to do with this load balancing can be configured with the balance source.

So that the same request is sent to the same ip server.

(2) use of database synchronization session

(3) using the Session cluster storage Redis

Using spring-session framework, the underlying principle is that the rewrite httpsession.

(4) Based on the token (the Token) mode

Because the Session itself is a distributed shared connection, so fly

2.2, Redis realize, do not talk nonsense on the code

(1) maven configuration

slightly

(2) .yml profile

Start redis / usr / local / redis / bin / redis-server /usr/local/redis/etc/redis.conf

server:
  port: 8080
redis:
 hostname: 192.168.212.151
 port: 6379
 password: 123456

(3)创建SessionConfig

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;

//这个类用配置redis服务器的连接
//maxInactiveIntervalInSeconds为SpringSession的过期时间(单位:秒)
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800)
public class SessionConfig {

	// 冒号后的值为没有配置文件时,制动装载的默认值
	@Value("${redis.hostname:localhost}")
	String HostName;
	@Value("${redis.port:6379}")
	int Port;

	@Bean
	public JedisConnectionFactory connectionFactory() {
		JedisConnectionFactory connection = new JedisConnectionFactory();
		connection.setPort(Port);
		connection.setHostName(HostName);
		return connection;
	}
}

(4)初始化Session

//初始化Session配置
public class SessionInitializer extends AbstractHttpSessionApplicationInitializer{
    public SessionInitializer() {
        super(SessionConfig.class);
    }
}

2.3、基于令牌(Token)方式实现,上代码

(1)TokenService 

@Service
public class TokenService {
	@Autowired
	private RedisService redisService;

	// 新增 返回token
	public String put(Object object) {
		String token = getToken();
		redisService.setString(token, object);
		return token;
	}

	// 获取信息
	public String get(String token) {
		String reuslt = redisService.getString(token);
		return reuslt;
	}

	public String getToken() {
		return UUID.randomUUID().toString();
	}

}

(2)TokenController

@RestController
public class TokenController {
	@Autowired
	private TokenService tokenService;
	@Value("${server.port}")
	private String serverPort;

	@RequestMapping("/put")
	public String put(String nameValue) {
		String token = tokenService.put(nameValue);
		return token + "-" + serverPort;
	}

	@RequestMapping("/get")
	public String get(String token) {
		String value = tokenService.get(token);
		return value + "-" + serverPort;
	}

}

三、Zookeeper实现哨兵机制

3.1、master选举使用场景及结构

现在很多时候我们的服务需要7*24小时工作,假如一台机器挂了,我们希望能有其它机器顶替它继续工作。此类问题现在多采用master-salve模式,也就是常说的主从模式,正常情况下主机提供服务,备机负责监听主机状态,当主机异常时,可以自动切换到备机继续提供服务,这个切换过程中选出下一个主机的过程就是master选举

 

3.2、ZK实现Master选举(哨兵机制)原理

 多个服务器在启动的时候,会在ZK上创建相同的临时节点,谁如果能够创建成功,谁就为主(因为节点唯一性),如果主服务器宕机之后,会话连接也会失效,其他服务器又开始选举。(谁能创建节点成功谁就为主

 

 

 

3.3、ZK实现Master选举代码实现

(1)Maven依赖信息

<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.0.RELEASE</version>
	</parent>
	<dependencies>
		<dependency>
			<groupId>com.101tec</groupId>
			<artifactId>zkclient</artifactId>
			<version>0.10</version>
			<exclusions>
				<exclusion>
					<artifactId>slf4j-api</artifactId>
					<groupId>org.slf4j</groupId>
				</exclusion>
				<exclusion>
					<artifactId>log4j</artifactId>
					<groupId>log4j</groupId>
				</exclusion>
				<exclusion>
					<artifactId>slf4j-log4j12</artifactId>
					<groupId>org.slf4j</groupId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
	</dependencies>

(2)IndexController

@RestController
public class IndexController {
	// 获取服务信息
	@RequestMapping("/getServerInfo")
	public String getServerInfo() {
		return ElectionMaster.isSurvival ? "当前服务器为主节点" : "当前服务器为从节点";
	}
//main启动类 略
}

(3)MyApplicationRunner

//启动完成后实现的方法

  • 1.项目启动的时候会在ZK上创建一个相同的临时节点
  • 2.谁能够创建成功谁就为主服务器
  • 3.使用服务监听节点是否被删除,如果接收到节点被删除,就重新开始选举(重新开始创建节点)
@Component
public class MyApplicationRunner implements ApplicationRunner {

	// 创建zk连接
	ZkClient zkClient = new ZkClient("127.0.0.1:2181");
//1.项目启动的时候会在ZK上创建一个相同的临时节点
	private String path = "/election";
	@Value("${server.port}")
	private String serverPort;
//启动后执行的方法
	public void run(ApplicationArguments args) throws Exception {
		System.out.println("项目启动完成...");
//2.谁能够创建成功谁就为主服务器
		createEphemeral();
		// 创建事件监听
//3.使用服务监听节点是否被删除,如果接收到节点被删除,就重新开始选举
		zkClient.subscribeDataChanges(path, new IZkDataListener() {

			// 节点被删除,返回通知
			public void handleDataDeleted(String dataPath) throws Exception {
				// 主节点已经挂了,重新选举
				System.out.println("主节点已经挂了,重新开始选举");
				createEphemeral();
			}

			public void handleDataChange(String dataPath, Object data) throws Exception {

			}
		});

	}

	private void createEphemeral() {
		try {
			zkClient.createEphemeral(path, serverPort);
            //选举成功
			ElectionMaster.isSurvival = true;
			System.out.println("serverPort:" + serverPort + ",选举成功....");
		} catch (Exception e) {
            //选举失败
			ElectionMaster.isSurvival = false;
		}
	}

}

(4)ElectionMaster

@Component
public class ElectionMaster {

	// 服务器info信息 是否存活
	public static boolean isSurvival;

}

 

 

 

 

 

发布了52 篇原创文章 · 获赞 116 · 访问量 5万+

Guess you like

Origin blog.csdn.net/RuiKe1400360107/article/details/103827559