• zookeeper curator学习(配合spring boot模拟leader选举)


    基础知识:http://www.cnblogs.com/LiZhiW/p/4930486.html

    项目路径:https://gitee.com/zhangjunqing/spring-boot  查找下面四个项目就可以了

    zookeeper版本为zookeeper-3.4.9(需要查找合适的curator版本)

                                三个spring bootweb项目:

                                               官方案例leader:

    思路:新建三个spring boot web项目,在这三个web项目中定义一个过滤器来在初始化时抢夺leader权限,如果发现强夺到leader权限,则可以提供服务,如果没有抢夺到请求则提示无法提供服务,当leader死掉时,curator会重新选举新的leader(这里只是提供选举的一个使用思路,本身这个选举也是举个列子)。

    1 pom文件依赖如下:

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>com.springboot</groupId>
      <artifactId>springboot-zookeeper-leaderTest01</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <packaging>jar</packaging>
    
      <name>springoot</name>
      <url>http://maven.apache.org</url>
      
      <!-- 使用spring boot必须有这依赖 -->
      <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>1.5.7.RELEASE</version>
            <relativePath /> <!-- lookup parent from repository -->
        </parent>
    
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      </properties>
    
      <dependencies>
           <!-- spring boot依赖jar包 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            
            
            <!-- 以下是 curator依赖jar包 -->
            <dependency>
                <groupId>org.apache.curator</groupId>
                <artifactId>curator-recipes</artifactId>
                <version>2.7.0</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.curator</groupId>
                <artifactId>curator-test</artifactId>
                <version>2.7.0</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.curator</groupId>
                <artifactId>curator-x-discovery</artifactId>
                <version>2.7.0</version>
            </dependency>
            
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-core</artifactId>
                <version>2.9.2</version>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>2.9.2</version>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-annotations</artifactId>
                <version>2.9.2</version>
            </dependency>
            
                    
      </dependencies>
      
      <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    </project>

    2:spring boot启动类如下:

    package com.springboot;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.web.servlet.ServletComponentScan;
    
    @ServletComponentScan(basePackages= {"com.springboot.filter"})//此处用于扫描过滤器
    @SpringBootApplication  //注意此类的包地址应该是最大的包,这样他就可以自动扫描其下包的所有类.否则也可以(scanBasePackages={"com.springboot.controller"})指定要扫描的包
    public class App {
        public static void main(String[] args) throws Exception {
            SpringApplication.run(App.class, args);
        }
    }

    3:controller层如下:

    package com.springboot.controller;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @RequestMapping("/hello")
    public class HelloController {
        
        
        //如果能提供服务,请求返回值就在此处
        @GetMapping("/say")
        public @ResponseBody String sayHello() {
            return "is servicing now";
        }
        
        
    }

    3:进行leader选举根据其是否是leader身份来判断是否提供服务

    package com.springboot.filter;
    
    import java.io.IOException;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    
    import org.apache.curator.framework.CuratorFramework;
    import org.apache.curator.framework.CuratorFrameworkFactory;
    import org.apache.curator.framework.recipes.leader.LeaderSelector;
    import org.apache.curator.retry.ExponentialBackoffRetry;
    
    @WebFilter(filterName = "myFilter", urlPatterns = "/*")
    public class MyFilter implements Filter {
        
        //zookeeper集群地址
        public static final String ZOOKEEPERSTRING = "192.168.99.129:2181,192.168.99.153:2181,192.168.99.171:2181";
        
        //zookeeper链接client
        CuratorFramework    client = null;
        
        //选举类
        LeaderSelector leaderSelector;
        String dataPath = "/tomcat/leader";
        
        public void init(FilterConfig filterConfig) throws ServletException {
                //初始化连接
                client = CuratorFrameworkFactory.newClient(ZOOKEEPERSTRING, new ExponentialBackoffRetry(1000, 3));
                
                //启动一个客户端
                client.start();
                
                
                //实例化一个选举器//特别注意LeaderListener,如果takeLeadership方法执行完毕,则会自动释放leaders身份,故我们使用countDownLatch来阻塞此方法使其不主动放弃leaders身份
                //同时这也给我们一个思路,我们可以通过在外部修改countDownLatch的值来控制leader是否主动放弃其身份
                leaderSelector = new LeaderSelector(client, dataPath, new LeaderListener());//放弃leader权限后还可以参加选举
                leaderSelector.autoRequeue();
                
                //开始服务
                leaderSelector.start();
                
        }
        
        public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException {
            HttpServletRequest req = (HttpServletRequest)request;
            
            //判断是否现在是leader
            if(leaderSelector.hasLeadership()) {
                chain.doFilter(request, response);
            }else {
                response.getWriter().write("is not servicing");
            }
            //chain.doFilter(request, response);
        }
        
        public void destroy() {
            // TODO Auto-generated method stub
            
        }
        
    }

     4:leader身份监听器:

    package com.springboot.filter;
    
    import java.util.concurrent.CountDownLatch;
    
    import org.apache.curator.framework.CuratorFramework;
    import org.apache.curator.framework.recipes.leader.LeaderSelectorListenerAdapter;
    
    public class LeaderListener extends LeaderSelectorListenerAdapter{
        private CountDownLatch countDownLatch = new CountDownLatch(1);
    
        //当这个方法执行完毕以后,leader会自动放弃身份,我们在这个项目当中使用countDownLatch阻塞不主动放弃身份
        //这里给我们提供思路,我们可以在外部动态修改countDownLatch值来使其主动放弃leader身份
        public void takeLeadership(CuratorFramework client) throws Exception {
            System.out.println("一直阻塞当中,一直提供服务");
            
            /**
             * 使用countdownLath,使leader永远不放弃自己的地位
             */
            countDownLatch.await();;
        }
    
    
    }

    5:进行测试

         一:  在不同端口启动项目3个此项目,发现8080现为leader提供服务

     

    二:强制关闭8080的web服务,一会后观察 leader成功跳到8081,提供服务

    三:启动8080,关闭8081,8082  一段时间后8080又重新拿回leader身份

    特别注意:

         在zookeeper重新选择leader的过程中需要等待一段时间,这段时间没法对外提供服务,

  • 相关阅读:
    Data Mining | 二分类模型评估-ROC/AUC/K-S/GINI
    Data Mining | 二分类模型评估-混淆矩阵
    Data Mining | 数据挖掘技术基础与进阶
    Data Mining | 数据挖掘概要和方法论
    python | 模块与第三方库的安装
    SAS | 数据EDA及代码
    SAS | 数据读入思路及代码
    python | 自定义函数
    SAS | 使用SAS数据
    SAS | 逻辑库和SAS数据集
  • 原文地址:https://www.cnblogs.com/zhangjunqing/p/7821377.html
Copyright © 2020-2023  润新知