Dubbo

Dubbo在项目中的作用

分布式服务架构

  1. 当服务越来越多时,服务URL配置管理变得非常困难,F5硬件负载均衡器的单点压力也越来越大。此时需要一个服务注册中心,动态的注册和发现服务,使服务的位置透明。
    并通过在消费方获取服务提供方地址列表,实现软负载均衡和Failover,降低对F5硬件负载均衡器的依赖,也能减少部分成本。

  2. 当进一步发展,服务间依赖关系变得错踪复杂,甚至分不清哪个应用要在哪个应用之前启动,架构师都不能完整的描述应用的架构关系。
    这时,需要自动画出应用间的依赖关系图,以帮助架构师理清理关系。

  3. 接着,服务的调用量越来越大,服务的容量问题就暴露出来,这个服务需要多少机器支撑?什么时候该加机器?
    为了解决这些问题,第一步,要将服务现在每天的调用量,响应时间,都统计出来,作为容量规划的参考指标。
    其次,要可以动态调整权重,在线上,将某台机器的权重一直加大,并在加大的过程中记录响应时间的变化,直到响应时间到达阀值,记录此时的访问量,再以此访问量乘以机器数反推总容量。

架构

角色

  1. Provider: 暴露服务的服务提供方。
  2. Consumer: 调用远程服务的服务消费方。
  3. Registry: 服务注册与发现的注册中心。
  4. Monitor: 统计服务的调用次调和调用时间的监控中心。
  5. Container: 服务运行容器。

调用关系

  1. 服务容器负责启动,加载,运行服务提供者。
  2. 服务提供者在启动时,向注册中心注册自己提供的服务。
  3. 服务消费者在启动时,向注册中心订阅自己所需的服务。
  4. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
  5. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  6. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

Paxos

作者介绍

1982,Lamport 提出了一种计算机容错理论,并于1900年论证。
这是一种
基于消传递且具有高度容错特性的一致性算法,是目前公认的解决分布式一致性问题最有效的算法之一。

时间时钟、面包店算法、拜占庭将军及paxos算法的创建性容错

paxos的目的

提高分布式系统容错性的一致性算法

核心

一致性算法

算法三个角色:

Proposer
Acceptor
Learner

规则

paxos 描述:

参与者之间可以进行通信,可以记录一些信息,来确定最终的值
消息内容不会被篡改

知行学社的分布式系统与Paxos算法 对paxos算法核心思想的描述

  • 在抢占式访问权的基础上引入多acceptor

  • 保证一个epoch,只有一个proposer运行,proposer按照epoch递增的顺序依次运行。

  • 新的epoch的proposer采用后者认同前者的思路运行。

  • 在肯定旧epoch无法生成确定性取值时,新的epoch 会提交自己的取值。不会冲突。

  • 一旦旧epoch形成确定性取值,新epoch肯定可以获取到此取值,并且会认同此取值,不会破坏。

git工作与学习

tag的作用与学习

  • git tag ‘name’ -m ‘desc’ 创建

  • git tag -d ‘name’ 删除

  • git tag -l 查看

  • git push –tags 提交

  • git push origin :refs/tags/tags_name

git 在使用项目中的实践模型

  1. master
  2. release-6.1
  3. develop
  4. hotfix-xxx
  5. release-release-6.1-xx

批量删除tag

git tag |grep -v ‘v7.2.25-log_report_v9-20200909’ | xargs -I {} git tag -d {}

redis致命错误的出现

#错误描述
我们将文件缓存到redis,但是在线上出现了一个问题,就是A企业群中发的文件,在B企业群中看文件时却看到了A企业群中的图片。

#经排查,结果如下:

##案例代码如下:

    import com.google.common.collect.Lists;
    import org.apache.commons.lang3.StringUtils;
    import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;

    import java.util.Arrays;
    import java.util.Collections;
    import java.util.List;
    import java.util.concurrent.*;

    /**
     * Created by Aaron on 15/11/12.
     */
    public class FileRedisFactory {
        private static Logger log = LoggerFactory.getLogger(FileRedisFactory.class);
        public ThreadPoolExecutor threadPoolExecutor;
        // 格式为 : 127.0.0.1:6379#0;127.0.0.2:6379#1    IP:PORT#index
        private String hosts;
        private String password;
        private int size;
        private List<JedisPool> pools=Lists.newArrayList();//连接池

        public FileRedisFactory(String hosts, String password) {
            this.hosts = hosts;
            this.password = password;
            this.init(hosts, password);
        }

        public FileRedisFactory(String hosts) {
            this.hosts = hosts;
            this.init(hosts, null);
        }


        private synchronized void init(String hosts, String password) {
            if (StringUtils.isNotEmpty(hosts)) {
                String[] hostsArray = hosts.split(";");
                List<String> hostList = Arrays.asList(hostsArray);
                Collections.sort(hostList);
                System.out.println(hostList);
                for (String host : hostList) {
                    try {
                        String[] uriDb=host.split("#");
                        String[] host_port = uriDb[0].split(":");
                        String ip = host_port[0];
                        String port = host_port[1];
                        int index=uriDb.length>0?Integer.valueOf(uriDb[1]):0;
                        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();

                        poolConfig.setMaxTotal(16);
                        poolConfig.setMaxIdle(16);
                        if (StringUtils.isNotEmpty(password)) {
                            pools.add(new JedisPool(poolConfig, ip, Integer.valueOf(port), 2000, password, index));
                        } else {
                            pools.add(new JedisPool(poolConfig, ip, Integer.valueOf(port), 2000, null, index));
                        }
                    } catch (Exception e) {
                        pools = Lists.newArrayList();
                        e.printStackTrace();
                        log.error("[ShardedRedisFactory] [initByShard] [error] [hosts:" + hosts + "] [password:" + password + "]", e);
                    }
                }
                size = pools.size();
            }
            this.threadPoolExecutor = new ThreadPoolExecutor(10,20,3, TimeUnit.MINUTES,new LinkedBlockingDeque<>(),new ThreadPoolExecutor.DiscardPolicy());

            // 构造池
            log.info("[ShardedRedisFactory] [initByShard] [success] [hosts:{}] [password:{}] [masterName:{}] [pool:{}]", hosts, password);
        }

        private JedisPool getJedisPool(int c) {
            int index = c % size;
            return pools.get(index);
        }

        private static int getIndexFromPath(String path) {
            String first=path.split("\\.")[0];
            return  first.charAt(first.length() - 1);
        }

        /**
         * @param filePath file path
         * @return
         */
        public byte[] get(String filePath) {
            if (cacheIsAvailable()) return null;
            JedisPool jedisPool = getJedisPool(getIndexFromPath(filePath));
            Jedis jedis = null;
            try {
                jedis = jedisPool.getResource();
                return jedis.get(filePath.getBytes());
            } catch (Exception e) {
                log.error(e.getMessage());
                return null;
            } finally {
                if (jedis != null)
                    jedisPool.returnResource(jedis);
            }
        }

        public void asynSet(String filePath, byte[] datas){
            if (cacheIsAvailable()) return;
            threadPoolExecutor.execute(()->{
                    JedisPool jedisPool = getJedisPool(getIndexFromPath(filePath));
                    Jedis jedis = null;
                    try {
                        jedis = jedisPool.getResource();
                        jedis.set(filePath.getBytes(), datas);
                    } catch (Exception e) {
                        log.error(e.getMessage());
                    } finally {
                        if (jedis != null)
                            jedisPool.returnResource(jedis);
                    }
            });
        }
        private boolean cacheIsAvailable() {
            if(pools.size()==0){
                return true;
            }
            return false;
        }

    }

##测试代码如下

        public static void main(String[] args) {
            FileRedisFactory fileRedisFactory = new FileRedisFactory("172.31.xxx.xxx:6379#0;172.31.xx.xxx:6379#1;172.31.xxx.xxx:6379#2;172.31.xxx.xxx:6379#3");
            System.out.println(fileRedisFactory);
            Map<String,String> map=new HashMap<>();

            for(int i=0;i<20;i++){
                map.put(""+i,""+i);
            }

            for (int j = 0; j <50 ; j++) {
                Thread thread=new Thread(){
                    @Override
                    public void run() {
                        while(true){
                            Set<String> s=map.keySet();

                            s.forEach(i->{
                                fileRedisFactory.set(i + "", (i + "").getBytes());
                            });
                        }
                    }
                };
                thread.start();
            }
            for (int k = 0; k <50 ; k++) {
                Thread thread=new Thread(){
                    @Override
                    public void run() {
                        while(true){
                            Set<String> s=map.keySet();
                            s.forEach(i->{
                                byte[] first=fileRedisFactory.get(i+"");
                                if(first==null){
                                    System.out.println(i+""+first);
                                    return;
                                }
                                try{
                                String temp=(new String(first));
                                if(!temp.equals(i+"")){
                                    System.out.println(i+"======"+temp);
                                    System.exit(-1);
                                }}catch(Exception e){
                                    e.printStackTrace();
                                }
                            });
                        }
                    }
                };
                thread.start();
            }
        }

若你和连接到redis服务器之间的网络不是很稳定
在运行时,我们会发现,有奇怪的现像出现:

    1======2
    3======8

这时,我们就在对redis操作时,异常的地方修改成如下代码:

    catch (Exception e) {
          log.error(e.getMessage());
          e.printStackTrace();
          return null;
    } 

就会看到报TimeOut的Exception

我们将:
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.6.2</version>
        </dependency>

替换成:
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.7.3</version>
        </dependency>

这时我们去Google上查询的同时也看了一下新的代码,
我们原来用的:

    jedisPool.returnResource(jedis);

 已经变成了:


   /**
    * @deprecated starting from Jedis 3.0 this method won't exist. Resouce cleanup should be done
    *             using @see {@link redis.clients.jedis.Jedis#close()}
    */
   @Deprecated
   public void returnResource(final Jedis resource) {
     if (resource != null) {
       try {
         resource.resetState();
         returnResourceObject(resource);
       } catch (Exception e) {
         returnBrokenResource(resource);
         throw new JedisException("Could not return the resource to the pool", e);
       }
     }
   }

同时我们也查到了一个文章JedisPool异常Jedis链接处理

#修改后的代码:

import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.*;

/**
 * Created by Aaron on 15/11/12.
 */
public class FileRedisFactory {
    private static Logger log = LoggerFactory.getLogger(FileRedisFactory.class);
    public ThreadPoolExecutor threadPoolExecutor;
    // 格式为 : 127.0.0.1:6379#0;127.0.0.2:6379#1    IP:PORT#index
    private String hosts;
    private String password;
    private int size;
    private List<JedisPool> pools=Lists.newArrayList();//连接池

    public FileRedisFactory(String hosts, String password) {
        this.hosts = hosts;
        this.password = password;
        this.init(hosts, password);
    }

    public FileRedisFactory(String hosts) {
        this.hosts = hosts;
        this.init(hosts, null);
    }


    private synchronized void init(String hosts, String password) {
        if (StringUtils.isNotEmpty(hosts)) {
            String[] hostsArray = hosts.split(";");
            List<String> hostList = Arrays.asList(hostsArray);
            Collections.sort(hostList);
            System.out.println(hostList);
            for (String host : hostList) {
                try {
                    String[] uriDb=host.split("#");
                    String[] host_port = uriDb[0].split(":");
                    String ip = host_port[0];
                    String port = host_port[1];
                    int index=uriDb.length>0?Integer.valueOf(uriDb[1]):0;
                    GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();

                    poolConfig.setMaxTotal(16);
                    poolConfig.setMaxIdle(16);
                    if (StringUtils.isNotEmpty(password)) {
                        pools.add(new JedisPool(poolConfig, ip, Integer.valueOf(port), 2000, password, index));
                    } else {
                        pools.add(new JedisPool(poolConfig, ip, Integer.valueOf(port), 2000, null, index));
                    }
                } catch (Exception e) {
                    pools = Lists.newArrayList();
                    log.error("[ShardedRedisFactory] [initByShard] [error] [hosts:" + hosts + "] [password:" + password + "]", e);
                }
            }
            size = pools.size();
        }

        this.threadPoolExecutor = new ThreadPoolExecutor(10,20,3, TimeUnit.MINUTES,new LinkedBlockingDeque<>(50),new ThreadPoolExecutor.DiscardPolicy());

        // 构造池
        log.info("[ShardedRedisFactory] [initByShard] [success] [hosts:{}] [password:{}] [masterName:{}] [pool:{}]", hosts, password);
    }

    private JedisPool getJedisPool(int c) {
        int index = c % size;
        return pools.get(index);
    }

    private static int getIndexFromPath(String path) {
        String first=path.split("\\.")[0];
        return  first.charAt(first.length() - 1);
    }

    /**
     * @param filePath file path
     * @return
     */
    public byte[] get(String filePath) {
        if (cacheIsAvailable()) return null;
        JedisPool jedisPool = getJedisPool(getIndexFromPath(filePath));
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.get(filePath.getBytes());
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        } finally {
            if (jedis != null)
                jedis.close();
        }
    }

    public String set(String filePath, byte[] datas) {
        if (cacheIsAvailable()) return null;
        JedisPool jedisPool = getJedisPool(getIndexFromPath(filePath));
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.set(filePath.getBytes(), datas);
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        } finally {
            if (jedis != null)
                jedis.close();
        }
    }

    public void asynSet(String filePath, byte[] datas,long expx){
        if (cacheIsAvailable()) return;
        threadPoolExecutor.execute(()->{
                JedisPool jedisPool = getJedisPool(getIndexFromPath(filePath));
                Jedis jedis = null;
                try {
                    jedis = jedisPool.getResource();
                    jedis.set(filePath.getBytes(), datas,"NX".getBytes(),"EX".getBytes(),expx);
                } catch (Exception e) {
                    log.error(e.getMessage());
                } finally {
                    if (jedis != null)
                        jedis.close();
                }
        });
    }
    private boolean cacheIsAvailable() {
        if(pools.size()==0){
            return true;
        }
        return false;
    }

}

#总结:

  1. 在使用做新功能时,方便时要添加开关或合理的回滚方案,方便快速的回滚减少事故的影响
  2. 排查错误,一查到底

JMeter

##JMeter是用来做什么的

是一个Apache的一个开源程序,一个100%的针对压力模块和功能压力测试纯Java应用,最初是专门为Web应用程序而设计 的,但是目前已经扩展到别的功能 测试。

  • 能做什么?

    用来测试动态 和 静态资源(Webservices(SOAP/REST),Web dynamic languages -PHP,JAva,ASP.NET,Files,etc.Jav)

##如何本地进行服务压力测试

  • 在lib下建一个文件夹,如tests,将所有自己用到的jar,放到这个文件夹中。

  • 将自己的测试jar放到 lib/ext下面

  • 将自己的程序依赖的jar文件夹,配置到配置文件
    user.classpath=../lib/tests

##如何分发到不同的机器进行压力测试

参考官方文档http://jmeter.apache.org/usermanual/jmeter_distributed_testing_step_by_step.pdf

##聚合分析

Label:每个 JMeter 的 element(例如 HTTP Request)都有一个 Name 属性,这里显示的就是 Name 属性的值

#Samples:表示你这次测试中一共发出了多少个请求,如果模拟10个用户,每个用户迭代10次,那么这里显示100

Average:平均响应时间——默认情况下是单个 Request 的平均响应时间,当使用了 Transaction Controller 时,也可以以Transaction 为单位显示平均响应时间

Median:中位数,也就是 50% 用户的响应时间

90% Line:90% 用户的响应时间

Note:关于 50% 和 90% 并发用户数的含义,请参考下文

http://www.cnblogs.com/jackei/archive/2006/11/11/557972.html

Min:最小响应时间

Max:最大响应时间

Error%:本次测试中出现错误的请求的数量/请求的总数

Throughput:吞吐量——默认情况下表示每秒完成的请求数(Request per Second),当使用了 Transaction Controller 时,也可以表示类似 LoadRunner 的 Transaction per Second 数

KB/Sec:每秒从服务器端接收到的数据量,相当于LoadRunner中的Throughput/Sec

###问题

####Jmeter-server启动失败:Cannot start. Unable to get local host IP address. is a loopback address

    在Windows下启动Jmeter非常顺利,转到Linux下居然启动失败。
    想起之前 遇到“/etc/hosts文件设置不对导致Jboss启动失败”, 立马把焦点指向/etc/hosts。

    果然还是这个问题,贴/etc/hosts示例:

    127.0.0.1       localhost.localdomain localhost
    10.20.10.31   higkoo.rdev.company.net higkoo

    执行命令`hostname`查看当前机器名如果当前机器名与/etc/hosts不一致 ,可手动先执行成一次`hostname yourhostname`或直接加到jmeter-server文件中(注意机器名中不要含域信息,譬如:myname.rdev.company.com。这样设置仍然启动失败)。

    由/etc/hosts文件导致启动失败的错误有:
    1
    Created remote object: UnicastServerRef [liveRef: [endpoint:[10.20.10.31:62090](local),objID:[2c639f6d:12794fca52a:-7fff, 712947915258586677]]]
    Server failed to start: java.rmi.RemoteException: Cannot start. higkoo is a loopback address.
    2
    Created remote object: UnicastServerRef [liveRef: [endpoint:[10.20.10.31:38796](local),objID:[-b0d822e:12794fee8b1:-7fff, 8314597152635832475]]]
    Server failed to start: java.rmi.RemoteException: Cannot start. Unable to get local host IP address.

zookeeper学习及项目实践

ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services. 。

它设计一种新的数据结构——Znode,然后在该数据结构的基础上定义了一些原语,也就是一些关于该数据结构的一些操作。有了这些数据结构和原语还不够,因为我们的ZooKeeper是工作在一个分布式的环境下,我们的服务是通过消息以网络的形式发送给我们的分布式应用程序,所以还需要一个通知机制——Watcher机制。那么总结一下,ZooKeeper所提供的服务主要是通过:数据结构+原语+watcher机制,三个部分来实现的。

使用场景下会使用zookeeper

  1. 项目中在监控mongodb的oplog来进行同步数据库的变更给别的部门.若想做的多机互备,就需要使用到分布式锁,由一台机器进行对oplog的变化进行同步
  2. 项目在定时发送提醒,多台服务器进行周期扫库操作,也同样用到了1中的分布式锁
  3. 假设我们有20个搜索引擎的服务器(每个负责总索引中的一部分的搜索任务)和一个总服务器(负责向这20个搜索引擎的服务器发出搜索请求并合并结果集),一个备用的总服务器(负责当总服务器宕机时替换总服务器),一个web的cgi(向总服务器发出搜索请求)。搜索引擎的服务器中的15个服务器提供搜索服务,5个服务器正在生成索引。这20个搜索引擎的服务器经常要让正在提供搜索服务的服务器停止提供服务开始生成索引,或生成索引的服务器已经把索引生成完成可以提供搜索服务了。使用Zookeeper可以保证总服务器自动感知有多少提供搜索引擎的服务器并向这些服务器发出搜索请求,当总服务器宕机时自动启用备用的总服务器.—分布式系统协调 ZooKeeper

zookeeper来源是什么?

ZooKeeper是一种为分布式应用所设计的高可用、高性能且一致的开源协调服务,它提供了一项基本服务:分布式锁服务。由于ZooKeeper的开源特性,后来我们的开发者在分布式锁的基础上,摸索了出了其他的使用方法:配置维护、组服务、分布式消息队列、分布式通知/协调等。

协议

  1. 每个Server在内存中存储了一份数据;
  2. Zookeeper启动时,将从实例中选举一个leader(Leader选举算法采用了Paxos协议;Paxos核心思想:当多数Server写成功,则任务数据写成功。故 Server数目一般为奇数);
  3. Leader负责处理数据更新等操作(Zab协议);
  4. 一个更新操作成功,当且仅当大多数Server在内存中成功修改数据。

结构组成

  1. Leader 负责进行投票的发起和决议,更新系统状态
  2. Learner–>跟随者Follower 用于接收客户请求并向客户端返回结果,在选择中参与投票
  3. Learner–>观察者Observer 可以接收客户端连接,将写请求转发给Leader节点,但其不参悟投票过程,只同步Leader的状态.其目的是为了扩展系统,提高读取速度
  4. client 请求发起方

具体用在哪里

  1. 配置管理,一处修改,监听者进行更新
  2. 命名服务
  3. 分布式锁 即 Leader Election
  4. 集群管理
  5. 队列管理

Zookeeper文件系统

每个子目录项如 NameService 都被称作为znode,和文件系统一样,我们能够自由的增加、删除znode,在一个znode下增加、删除子znode,唯一的不同在于znode是可以存储数据的。
有四种类型的znode:

  1. PERSISTENT-持久化目录节点:客户端与zookeeper断开连接后,该节点依旧存在
  2. PERSISTENT_SEQUENTIAL-持久化顺序编号目录节点:客户端与zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号
  3. EPHEMERAL-临时目录节点:客户端与zookeeper断开连接后,该节点被删除
  4. EPHEMERAL_SEQUENTIAL-临时顺序编号目录节点:客户端与zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号

Zookeeper的特点

  1. 最终一致性:为客户端展示同一视图,这是zookeeper最重要的功能。
  2. 可靠性:如果消息被到一台服务器接受,那么它将被所有的服务器接受。
  3. 实时性:Zookeeper不能保证两个客户端能同时得到刚更新的数据,如果需要最新数据,应该在读数据之前调用sync()接口。
  4. 等待无关(wait-free):慢的或者失效的client不干预快速的client的请求。
  5. 原子性:更新只能成功或者失败,没有中间状态。
  6. 顺序性:所有Server,同一消息发布顺序一致。

场景分析

  1. 分布式锁的场景使用
zkCli.sh -server x.x.x.x:4180

ls /key

>[data, leader]

[zk: x.x.x.x:4180(CONNECTED) 6] get /key/leader

cZxid = 0xc1098cd0b0
ctime = Sun Jul 16 13:10:01 CST 2017
mZxid = 0xc1098cd0b0
mtime = Sun Jul 16 13:10:01 CST 2017
pZxid = 0xc112aec1c0
cversion = 152
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 2

[zk: x.x.x.x:4180(CONNECTED) 7] ls /key/leader
[_c_7ea9234d-3973-4e1d-8a6a-e2e30062cdc4-latch-0000000076, _c_5444e12a-c7ef-48bb-8ee6-271eea4a1c29-latch-0000000075]
[zk: x.x.x.x:4180(CONNECTED) 8] get /key/leader/_c_7ea9234d-3973-4e1d-8a6a-e2e30062cdc4-latch-0000000076
24
cZxid = 0xc112aec1c0
ctime = Fri Mar 30 16:58:50 CST 2018
mZxid = 0xc112aec1c0
mtime = Fri Mar 30 16:58:50 CST 2018
pZxid = 0xc112aec1c0
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0xd5848ddc5ec71f6
dataLength = 2
numChildren = 0

[zk: x.x.x.x:4180(CONNECTED) 9] get /key/leader/_c_5444e12a-c7ef-48bb-8ee6-271eea4a1c29-latch-0000000075
5
cZxid = 0xc1123e0f90
ctime = Tue Mar 27 10:55:03 CST 2018
mZxid = 0xc1123e0f90
mtime = Tue Mar 27 10:55:03 CST 2018
pZxid = 0xc1123e0f90
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x259977a5b1b3de0
dataLength = 1
numChildren = 0


经典文章链接

zookeeper系列
Leader选举
基本概念

Protobuf是什么

欢迎来到protocol buffer的开发者指南文档,一种语言无关、平台无关、扩展性好的用于通信协议、数据存储的结构化数据串行化方法。本文档面向希望使用protocol buffer的Java、C++或Python开发者。这个概览介绍了protocol buffer,并告诉你如何开始,你随后可以跟随编程指导深入了解protocol buffer编码方式API参考文档同样也是提供了这三种编程语言的版本,不够协议语言样式指导都是编写 .proto 文件。

什么是protocol buffer

ProtocolBuffer是用于结构化数据串行化的灵活、高效、自动的方法,有如XML,不过它更小、更快、也更简单。你可以定义自己的数据结构,然后使用代码生成器生成的代码来读写这个数据结构。你甚至可以在无需重新部署程序的情况下更新数据结构。

他们如何工作

你首先需要在一个 .proto 文件中定义你需要做串行化的数据结构信息。每个ProtocolBuffer信息是一小段逻辑记录,包含一系列的键值对。这里有个非常简单的 .proto 文件定义了个人信息:


message Person {
required string name=1;
required int32 id=2;
optional string email=3;

enum PhoneType {
MOBILE=0;
HOME=1;
WORK=2;
}

message PhoneNumber {
required string number=1;
optional PhoneType type=2 [default=HOME];
}

repeated PhoneNumber phone=4;
}

有如你所见,消息格式很简单,每个消息类型拥有一个或多个特定的数字字段,每个字段拥有一个名字和一个值类型。值类型可以是数字(整数或浮点)、布尔型、字符串、原始字节或者其他ProtocolBuffer类型,还允许数据结构的分级。你可以指定可选字段,必选字段和重复字段。你可以在proto.html找到更多关于如何编写 .proto 文件的信息。

一旦你定义了自己的报文格式(message),你就可以运行ProtocolBuffer编译器,将你的 .proto 文件编译成特定语言的类。

为什么不用XML?

ProtocolBuffer拥有多项比XML更高级的串行化结构数据的特性,ProtocolBuffer:

    更简单
    小3-10倍
    快20-100倍
    更少的歧义
    可以方便的生成数据存取类 

例如,让我们看看如何在XML中建模Person的name和email字段:


<person>
<name>John Doe</name>
<email>jdoe@example.com</email>
</person>

对应的ProtocolBuffer报文则如下:

ProtocolBuffer的文本表示
这不是正常时使用的二进制数据

person {
name: "John Doe"
email: "jdoe@example.com"
}

当这个报文编码到ProtocolBuffer的二进制格式时(上面的文本仅用于调试和编辑),它只需要28字节和100-200ns的解析时间。而XML的版本需要69字节(除去空白)和 5000-10000ns的解析时间。

设计模式之创建型模式

##创建型模式
这六个模式都是与创建对象相关的

  • 简单工厂模式(Simple Factory);
  • 工厂方法模式(Factory Method);
  • 抽象工厂模式(Abstract Factory);
  • 创建者模式(Builder);
  • 原型模式(Prototype);
  • 单例模式(Singleton);

简单工厂模式(Simple Factory);

工厂方法模式(Factory Method);

建立一个工厂类,对实现同一接口的类进行实例化创建。

``
package design.pattern.factory;

/**
* Created by Aaron on 15/9/13.
*/
public interface IParser {
String parse(Object obj);
}
package design.pattern.factory;

/**
* Created by Aaron on 15/9/13.
*/
public class JSONParser implements IParser{
@Override
public String parse(Object obj) {
//create json string
return "{class:"+obj.getClass()+"}";
}
}
package design.pattern.factory;

/**
* Created by Aaron on 15/9/13.
*/
public class XMLParser implements IParser{
@Override
public String parse(Object obj) {
//create xml string....
return "<object><class>"+obj.getClass()+"</class></object>";
}
}
package design.pattern.factory;

/**
* Created by Aaron on 15/9/13.
*/
public class ParserFactory {
public static final String TYPE_XML="xml";
public static final String TYPE_JSON="json";
public static IParser buildParser(String type){
switch (type){
case ParserFactory.TYPE_XML:return new XMLParser();
case ParserFactory.TYPE_JSON:return new JSONParser();
}
return null;
}

public static void main(String[] args){
IParser parser= ParserFactory.buildParser(ParserFactory.TYPE_JSON);
System.out.print(parser.parse(parser));
}
}

//output {class:JSONParser}

抽象工厂模式(Abstract Factory);

工厂方法,每创建一个新的类时,就要个性类工厂类,这样拓展性比较差,如何能通过不个性工厂类而进行扩展呢。这里就用到了抽象工厂模式,就是创建多个工厂,一旦要增加新的类型就增加一个新的工厂,不需要修改现有代码。

基于上面代码将ParserFactory工厂类用一个抽象工厂类和两个子工厂类进行代替
package design.pattern.abstractfactory;

import design.pattern.factory.*;

/**
* Created by Aaron on 15/9/13.
*/
public abstract class AbstractParserFactory {
abstract IParser create();
}

package design.pattern.abstractfactory;

/**
* Created by Aaron on 15/9/13.
*/
public class JSONParserFactory extends AbstractParserFactory {
@Override
IParser create() {
return new JSONParser();
}
}

package design.pattern.abstractfactory;

/**
* Created by Aaron on 15/9/13.
*/
public class XMLParserFactory extends AbstractParserFactory {
@Override
IParser create() {
return new XMLParser();
}
}

建造者模式(Builder);

GoF这样定义:

建造者模式:是将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

咱们这里以创建应用为例,这里我们创建两个应用,考试系统和CRM系统,创建过程是,需求->原型图->开发计划->表设计->架构设计->功能实现->测试->交付 大概是这样一个简单的过程,这里就会看到同样的构建过程得到不同的表示。
package design.pattern.builder;

import java.util.Vector;

/**
* Created by Aaron on 15/9/13.
*/
public class Project {

private Vector<String> impleProcess=new Vector<String>();
public void process(String imple){
impleProcess.add(imple);
}
public Vector<String> getImpleProcess() {
return impleProcess;
}

}

package design.pattern.builder;

/**
* Created by Aaron on 15/9/13.
*/
public interface IProjectBuilder {
Project getProject();
void makeRequirement();

void makePrototype();

void makeScheduler();

void makeTables();

void makeAppFrameWork();

void programming();

void test();

void delivery();
}

package design.pattern.builder;

/**
* Created by Aaron on 15/9/13.
*/
public class ExamProjectBuilder implements IProjectBuilder {
private Project project;

public ExamProjectBuilder() {
this.project = new Project();
}

public Project getProject() {
return project;
}

@Override
public void makeRequirement() {
this.project.process("创建考试系统需求");

}

@Override
public void makePrototype() {
this.project.process("创建考试原型");
}

@Override
public void makeScheduler() {
this.project.process("创建考试计划");
}

@Override
public void makeTables() {
this.project.process("创建考试系统表");
}

@Override
public void makeAppFrameWork() {
this.project.process("创建考试应用架构");
}

@Override
public void programming() {
this.project.process("考试应用代码实现");
}

@Override
public void test() {
this.project.process("测试考试应用");
}

@Override
public void delivery() {
this.project.process("交付考试应用");
}
}

package design.pattern.builder;

/**
* Created by Aaron on 15/9/13.
*/
public class CRMProjectBuilder implements IProjectBuilder {
public CRMProjectBuilder() {
this.project = new Project();
}

public Project getProject() {
return project;
}

private Project project;

@Override
public void makeRequirement() {
this.project.process("创建CRM系统需求");
}

@Override
public void makePrototype() {
this.project.process("创建CRM原型");
}

@Override
public void makeScheduler() {
this.project.process("创建CRM计划");
}

@Override
public void makeTables() {
this.project.process("创建CRM系统表");
}

@Override
public void makeAppFrameWork() {
this.project.process("创建CRM应用架构");
}

@Override
public void programming() {
this.project.process("CRM应用代码实现");
}

@Override
public void test() {
this.project.process("测试CRM应用");
}

@Override
public void delivery() {
this.project.process("交付CRM应用");
}
}

package design.pattern.builder;

/**
* Created by Aaron on 15/9/13.
*/
public class Director {
private IProjectBuilder builder;
public Director(IProjectBuilder builder){
this.builder=builder;
}
public Project process(){
this.builder.makeRequirement();
this.builder.makePrototype();
this.builder.makeScheduler();
this.builder.makeAppFrameWork();
this.builder.makeTables();
this.builder.programming();
this.builder.test();
this.builder.delivery();
return builder.getProject();
}

public static void main(String[] args){
Director director = new Director(new CRMProjectBuilder());
Project project = director.process();
System.out.println(project.getImpleProcess());
}
}

//输出 [创建CRM系统需求, 创建CRM原型, 创建CRM计划, 创建CRM应用架构, 创建CRM系统表, CRM应用代码实现, 测试CRM应用, 交付CRM应用]

原型模式(Prototype);

GoF这样定义:

用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。

package design.pattern.prototype;

import java.io.*;
import java.util.Vector;

/**
* Created by Aaron on 15/9/13.
*/
public class DeepClonePrototype implements Cloneable,Serializable {
public Vector<String> attrs=new Vector<String>();

public Object deepClone() throws CloneNotSupportedException, IOException, ClassNotFoundException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return ois.readObject();
}

public static void main(String[] args) throws Exception{
Object pro=new DeepClonePrototype().deepClone();
System.out.println(pro.getClass());
}

}

单例模式(Singleton);

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

package design.pattern.singleton;

/**
* Created by Aaron on 15/9/11.
*/
public class Singleton {
private Singleton() {

}

private static Singleton instance = null;

private static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
return instance = new Singleton();
} else {
return instance;
}
}
} else {
return instance;
}
}

public String getName() {
return Singleton.class.getName();
}

public static void main(String args[]) {
Singleton instance = Singleton.getInstance();
System.out.print(instance.getName());
}

}