精华内容
下载资源
问答
  • 教育行业数字桌面云典型应用场景.pptx
  • 教育行业数字桌面云典型应用场景.pdf
  • 对物联网技术系统、层次介绍和典型应用场景
  • 对物联网技术系统、层次介绍和典型应用场景.pdf
  • SpringBoot整合RabbitMQ之 典型应用场景实战一

    万次阅读 多人点赞 2018-10-09 15:08:04
    特别是在一些典型的应用场景以及业务模块中具有重要的作用,比如业务服务模块解耦、异步通信、高并发限流、超时业务、数据延迟处理等。 其中课程的学习链接地址:https://edu.csdn.net/course/detail/9314 ...

    实战前言

    RabbitMQ 作为目前应用相当广泛的消息中间件,在企业级应用、微服务应用中充当着重要的角色。特别是在一些典型的应用场景以及业务模块中具有重要的作用,比如业务服务模块解耦、异步通信、高并发限流、超时业务、数据延迟处理等。

    其中课程的学习链接地址:https://edu.csdn.net/course/detail/9314 

    RabbitMQ 官网拜读

    首先,让我们先拜读 RabbitMQ 官网的技术开发手册以及相关的 Features,感兴趣的朋友可以耐心的阅读其中的相关介绍,相信会有一定的收获,地址可见:

    http://www.rabbitmq.com/getstarted.html

    阅读该手册过程中,我们可以得知 RabbitMQ 其实核心就是围绕 “消息模型” 来展开的,其中就包括了组成消息模型的相关组件:生产者,消费者,队列,交换机,路由,消息等!而我们在实战应用中,实际上也是紧紧围绕着 “消息模型” 来展开撸码的!

    下面,我就介绍一下这一消息模型的演变历程,当然,这一历程在 RabbitMQ 官网也是可以窥览得到的!

    展开全文
  • Zookeeper典型应用场景介绍

    万次阅读 多人点赞 2018-07-07 22:08:05
    1.前言之前自己写了一些关于Zookeeper的基础知识,Zookeeper作为一种协调分布式应用高性能的调度服务,实际的应用场景也非常的广泛,这里主要通过几个例子来具体的说明Zookeeper在特定场景下的使用方式(下面的这些...

    1.前言

    之前自己写了一些关于Zookeeper的基础知识,Zookeeper作为一种协调分布式应用高性能的调度服务,实际的应用场景也非常的广泛,这里主要通过几个例子来具体的说明Zookeeper在特定场景下的使用方式(下面的这些功能估计consul和etcd也能实现,以后学到了再说吧)。

    2.具体应用

    2.1.一致性配置管理

    我们在开发的时候,有时候需要获取一些公共的配置,比如数据库连接信息等,并且偶然可能需要更新配置。如果我们的服务器有N多台的话,那修改起来会特别的麻烦,并且还需要重新启动。这里Zookeeper就可以很方便的实现类似的功能。

    2.1.1.思路

    1. 将公共的配置存放在Zookeeper的节点中
    2. 应用程序可以连接到Zookeeper中并对Zookeeper中配置节点进行读取或者修改(对于写操作可以进行权限验证设置),下面是具体的流程图:

    2.1.2.事例

    数据库配置信息一致性的维护

    配置类:
    public class CommonConfig implements Serializable{
    	// 数据库连接配置
    	private String dbUrl;
    	private String username;
    	private String password;
    	private String driverClass;
    	
    	public CommonConfig() {}
    	
    	public CommonConfig(String dbUrl, String username, String password, String driverClass) {
    		super();
    		this.dbUrl = dbUrl;
    		this.username = username;
    		this.password = password;
    		this.driverClass = driverClass;
    	}
    
    	public String getDbUrl() {
    		return dbUrl;
    	}
    
    	public void setDbUrl(String dbUrl) {
    		this.dbUrl = dbUrl;
    	}
    
    	public String getUsername() {
    		return username;
    	}
    
    	public void setUsername(String username) {
    		this.username = username;
    	}
    
    	public String getPassword() {
    		return password;
    	}
    
    	public void setPassword(String password) {
    		this.password = password;
    	}
    
    	public String getDriverClass() {
    		return driverClass;
    	}
    
    	public void setDriverClass(String driverClass) {
    		this.driverClass = driverClass;
    	}
    	
    	@Override
    	public String toString() {
    		return "CommonConfig:{dbUrl:" + this.dbUrl +
    				", username:" + this.username + 
    				", password:" + this.password + 
    				", driverClass:" + this.driverClass + "}";
    	}
    }
    

    配置管理中心

    1. 获取本地配置信息

    2. 修改配置,并同步

    同步配置信息到Zookeeper服务器

    public class ZkConfigMng {
    	private String nodePath = "/commConfig";
    	private CommonConfig commonConfig;
    	private ZkClient zkClient;
    	
    	public CommonConfig initConfig(CommonConfig commonConfig) {
    		if(commonConfig == null) {
    			this.commonConfig = new CommonConfig("jdbc:mysql://127.0.0.1:3306/mydata?useUnicode=true&characterEncoding=utf-8",
    					"root", "root", "com.mysql.jdbc.Driver");	
    		} else {
    			this.commonConfig = commonConfig;
    		}
    		return this.commonConfig;
    	}
    	
    	/**
    	 * 更新配置
    	 * 
    	 * @param commonConfig
    	 * @return
    	 */
    	public CommonConfig update(CommonConfig commonConfig) {
    		if(commonConfig != null) {
    			this.commonConfig = commonConfig;
    		}
    		syncConfigToZookeeper();
    		return this.commonConfig;
    	}
    	
    	public void syncConfigToZookeeper() {
    		if(zkClient == null) {
    			zkClient = new ZkClient("127.0.0.1:2181");
    		}
    		if(!zkClient.exists(nodePath)) {
    			zkClient.createPersistent(nodePath);
    		}
    		zkClient.writeData(nodePath, commonConfig);
    	}
    }

    以上是提供者,下面我们需要一个客户端获取这些配置

    public class ZkConfigClient implements Runnable {
    	
    	private String nodePath = "/commConfig";
    	
    	private CommonConfig commonConfig;
    
    	@Override
    	public void run() {
    		ZkClient zkClient = new ZkClient(new ZkConnection("127.0.0.1:2181", 5000));
    		while (!zkClient.exists(nodePath)) {
    			System.out.println("配置节点不存在!");
    			try {
    				TimeUnit.SECONDS.sleep(1);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    		// 获取节点
    		commonConfig = (CommonConfig)zkClient.readData(nodePath);
    		System.out.println(commonConfig.toString());
    		zkClient.subscribeDataChanges(nodePath, new IZkDataListener() {
    			
    			@Override
    			public void handleDataDeleted(String dataPath) throws Exception {
    				if(dataPath.equals(nodePath)) {
    					System.out.println("节点:" + dataPath + "被删除了!");
    				}
    			}
    			
    			@Override
    			public void handleDataChange(String dataPath, Object data) throws Exception {
    				if(dataPath.equals(nodePath)) {
    					System.out.println("节点:" + dataPath + ", 数据:" + data + " - 更新");
    					commonConfig = (CommonConfig) data;
    				}
    			}
    		});
    	}
    
    }

    下面启动Main函数

    配置管理服务启动

    public static void main(String[] args) throws InterruptedException {
    		SpringApplication.run(ZookeeperApiDemoApplication.class, args);
    		
    		ZkConfigMng zkConfigMng = new ZkConfigMng();
    		zkConfigMng.initConfig(null);
    		zkConfigMng.syncConfigToZookeeper();
    		TimeUnit.SECONDS.sleep(10);
    		
    		// 修改值
    		zkConfigMng.update(new CommonConfig("jdbc:mysql://192.168.1.122:3306/mydata?useUnicode=true&characterEncoding=utf-8",
    				"root", "wxh", "com.mysql.jdbc.Driver"));
    	}
    }

    客户端启动:

    public static void main(String[] args) throws InterruptedException {
    		SpringApplication.run(ZookeeperApiDemoApplication.class, args);
    
    		ExecutorService executorService = Executors.newFixedThreadPool(3);
    		// 模拟多个客户端获取配置
    		executorService.submit(new ZkConfigClient());
    		executorService.submit(new ZkConfigClient());
    		executorService.submit(new ZkConfigClient());
    	}
    }

    2.2.分布式锁

    在我们日常的开发中,如果是单个进程中对共享资源的访问,我们只需要用synchronized或者lock就能实现互斥操作。但是对于跨进程、跨主机、跨网络的共享资源似乎就无能为力了。

    2.1.1.思路

    1. 首先zookeeper中我们可以创建一个/distributed_lock持久化节点
    2. 然后再在/distributed_lock节点下创建自己的临时顺序节点,比如:/distributed_lock/task_00000000008
    3. 获取所有的/distributed_lock下的所有子节点,并排序
    4. 判读自己创建的节点是否最小值(第一位)
    5. 如果是,则获取得到锁,执行自己的业务逻辑,最后删除这个临时节点。
    6. 如果不是最小值,则需要监听自己创建节点前一位节点的数据变化,并阻塞。
    7. 当前一位节点被删除时,我们需要通过递归来判断自己创建的节点是否在是最小的,如果是则执行5);如果不是则执行6)(就是递归循环的判断)

    下面是具体的流程图:


    2.1.3.事例

    public class DistributedLock {
    	
    	// 常亮
    	static class Constant {
    		private static final int SESSION_TIMEOUT = 10000;
    		private static final String CONNECTION_STRING = "127.0.0.1:2181";
    		private static final String LOCK_NODE = "/distributed_lock";
    		private static final String CHILDREN_NODE = "/task_";
    	}
    	
    	private ZkClient zkClient;
    	
    	public DistributedLock() {
    		// 连接到Zookeeper
    		zkClient = new ZkClient(new ZkConnection(Constant.CONNECTION_STRING));
    		if(!zkClient.exists(Constant.LOCK_NODE)) {
    			zkClient.create(Constant.LOCK_NODE, "分布式锁节点", CreateMode.PERSISTENT);
    		}
    	}
    	
    	public String getLock() {
    		try {
    			// 1。在Zookeeper指定节点下创建临时顺序节点
    			String lockName = zkClient.createEphemeralSequential(Constant.LOCK_NODE + Constant.CHILDREN_NODE, "");
    			// 尝试获取锁
    			acquireLock(lockName);
    			return lockName;
    		} catch(Exception e) {
    			e.printStackTrace();
    		}
    		
    		return null;
    	}
    	
    	/**
    	 * 获取锁
    	 * @throws InterruptedException 
    	 */
    	public Boolean acquireLock(String lockName) throws InterruptedException {
    		// 2.获取lock节点下的所有子节点
    		List<String> childrenList = zkClient.getChildren(Constant.LOCK_NODE);
    		// 3.对子节点进行排序,获取最小值
    		Collections.sort(childrenList, new Comparator<String>() {
    			@Override
    			public int compare(String o1, String o2) {
    				return Integer.parseInt(o1.split("_")[1]) - Integer.parseInt(o2.split("_")[1]);
    			}
    			
    		});
    		// 4.判断当前创建的节点是否在第一位
    		int lockPostion = childrenList.indexOf(lockName.split("/")[lockName.split("/").length - 1]);
    		if(lockPostion < 0) {
    			// 不存在该节点
    			throw new ZkNodeExistsException("不存在的节点:" + lockName);
    		} else if (lockPostion == 0) {
    			// 获取到锁
    			System.out.println("获取到锁:" + lockName);
    			return true;
    		} else if (lockPostion > 0) {
    			// 未获取到锁,阻塞
    			System.out.println("...... 未获取到锁,阻塞等待 。。。。。。");
    			// 5.如果未获取得到锁,监听当前创建的节点前一位的节点
    			final CountDownLatch latch = new CountDownLatch(1);
    			IZkDataListener listener = new IZkDataListener() {
    				
    				@Override
    				public void handleDataDeleted(String dataPath) throws Exception {
    					// 6.前一个节点被删除,当不保证轮到自己
    					System.out.println("。。。。。。前一个节点被删除  。。。。。。");
    					acquireLock(lockName);
    					latch.countDown();
    				}
    				
    				@Override
    				public void handleDataChange(String dataPath, Object data) throws Exception {
    					// 不用理会
    				}
    			};
    			try {
    				zkClient.subscribeDataChanges(Constant.LOCK_NODE + "/" + childrenList.get(lockPostion - 1), listener);
    				latch.await();
    			} finally {
    				zkClient.unsubscribeDataChanges(Constant.LOCK_NODE + "/" + childrenList.get(lockPostion - 1), listener);
    			}
    		}
    		return false;
    	}
    	
    	/**
    	 * 释放锁(删除节点)
    	 * 
    	 * @param lockName
    	 */
    	public void releaseLock(String lockName) {
    		zkClient.delete(lockName);
    	}
    	
    	public void closeZkClient() {
    		zkClient.close();
    	}
    }
    
    @SpringBootApplication
    public class ZookeeperDemoApplication {
    
    	public static void main(String[] args) throws InterruptedException {
    		SpringApplication.run(ZookeeperDemoApplication.class, args);
    		
    		DistributedLock lock = new DistributedLock();
    		String lockName = lock.getLock();
    		/** 
    		 * 执行我们的业务逻辑
    		 */
    		if(lockName != null) {
    			lock.releaseLock(lockName);
    		}
    		
    		lock.closeZkClient();
    	}
    }

    2.3.分布式队列

    在日常使用中,特别是像生产者消费者模式中,经常会使用BlockingQueue来充当缓冲区的角色。但是在分布式系统中这种方式就不能使用BlockingQueue来实现了,但是Zookeeper可以实现。

    2.1.1.思路

    1. 首先利用Zookeeper中临时顺序节点的特点
    2. 当生产者创建节点生产时,需要判断父节点下临时顺序子节点的个数,如果达到了上限,则阻塞等待;如果没有达到,就创建节点。
    3. 当消费者获取节点时,如果父节点中不存在临时顺序子节点,则阻塞等待;如果有子节点,则获取执行自己的业务,执行完毕后删除该节点即可。
    4. 获取时获取最小值,保证FIFO特性。
    2.1.2.事例

    这个是一个消费者对一个生产者,如果是多个消费者对多个生产者,对代码需要调整。

    public interface AppConstant {
    	static String ZK_CONNECT_STR = "127.0.0.1:2181";
    	static String NODE_PATH = "/mailbox";
    	static String CHILD_NODE_PATH = "/mail_";
    	static int MAILBOX_SIZE = 10;
    }
    
    public class MailConsumer implements Runnable, AppConstant{
    
    	private ZkClient zkClient;
    	private Lock lock;
    	private Condition condition;
    	
    	public MailConsumer() {
    		lock = new ReentrantLock();
    		condition = lock.newCondition();
    		zkClient = new ZkClient(new ZkConnection(ZK_CONNECT_STR));
    		System.out.println("sucess connected to zookeeper server!");
    		// 不存在就创建mailbox节点
    		if(!zkClient.exists(NODE_PATH)) {
    			zkClient.create(NODE_PATH, "this is mailbox", CreateMode.PERSISTENT);
    		}
    	}
    
    	@Override
    	public void run() {
    		IZkChildListener listener = new IZkChildListener() {		
    			@Override
    			public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception {
    				System.out.println("Znode["+parentPath + "] size:" + currentChilds.size());
    				// 还是要判断邮箱是否为空
    				if(currentChilds.size() > 0) {
    					// 唤醒等待的线程
    					try {
    						lock.lock();
    						condition.signal();
    					} catch (Exception e) {
    						e.printStackTrace();
    					} finally {
    						lock.unlock();
    					}
    				}
    			}
    		};
    		// 监视子节点的改变,不用放用while循环中,监听一次就行了,不需要重复绑定
    		zkClient.subscribeChildChanges(NODE_PATH, listener);
    		try {
    			//循环随机发送邮件模拟真是情况
    			while(true) {
    				// 判断是否可以发送邮件
    				checkMailReceive();
    				// 接受邮件
    				List<String> mailList = zkClient.getChildren(NODE_PATH);
    				// 如果mailsize==0,也没有关系;可以直接循环获取就行了
    				if(mailList.size() > 0) {
    					Collections.sort(mailList, new Comparator<String>() {
    						@Override
    						public int compare(String o1, String o2) {
    							return Integer.parseInt(o1.split("_")[1]) - Integer.parseInt(o2.split("_")[1]);
    						}
    					});
    					// 模拟邮件处理(0-1S)
    					TimeUnit.MILLISECONDS.sleep(new Random().nextInt(1000));
    					zkClient.delete(NODE_PATH + "/" + mailList.get(0));
    					System.out.println("mail has been received:" + NODE_PATH + "/" + mailList.get(0));
    				}
    			} 
    		}catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			zkClient.unsubscribeChildChanges(NODE_PATH, listener);
    		}
    	}
    
    	private void checkMailReceive() {
    		try {
    			lock.lock();
    			// 判断邮箱是为空
    			List<String> mailList = zkClient.getChildren(NODE_PATH);
    			System.out.println("mailbox size: " + mailList.size());
    			if(mailList.size() == 0) {
    				// 邮箱为空,阻塞消费者,直到邮箱有邮件
    				System.out.println("mailbox is empty, please wait 。。。");
    				condition.await();
    				// checkMailReceive();
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			lock.unlock();
    		}
    	}
    }
    
    public class MailProducer implements Runnable, AppConstant{
    	
    	private ZkClient zkClient;
    	private Lock lock;
    	private Condition condition;
    	
    	/**
    	 * 初始化状态
    	 */
    	public MailProducer() {
    		lock = new ReentrantLock();
    		condition = lock.newCondition();
    		zkClient = new ZkClient(new ZkConnection(ZK_CONNECT_STR));
    		System.out.println("sucess connected to zookeeper server!");
    		// 不存在就创建mailbox节点
    		if(!zkClient.exists(NODE_PATH)) {
    			zkClient.create(NODE_PATH, "this is mailbox", CreateMode.PERSISTENT);
    		}
    	}
    
    	@Override
    	public void run() {
    		IZkChildListener listener = new IZkChildListener() {		
    			@Override
    			public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception {
    				System.out.println("Znode["+parentPath + "] size:" + currentChilds.size());
    				// 还是要判断邮箱是否已满
    				if(currentChilds.size() < MAILBOX_SIZE) {
    					// 唤醒等待的线程
    					try {
    						lock.lock();
    						condition.signal();
    					} catch (Exception e) {
    						e.printStackTrace();
    					} finally {
    						lock.unlock();
    					}
    				}
    			}
    		};
    		// 监视子节点的改变,不用放用while循环中,监听一次就行了,不需要重复绑定
    		zkClient.subscribeChildChanges(NODE_PATH, listener);
    		try {
    			//循环随机发送邮件模拟真是情况
    			while(true) {
    				// 判断是否可以发送邮件
    				checkMailSend();
    				// 发送邮件
    				String cretePath = zkClient.createEphemeralSequential(NODE_PATH + CHILD_NODE_PATH, "your mail");
    				System.out.println("your mail has been send:" + cretePath);
    				// 模拟随机间隔的发送邮件(0-10S)
    				TimeUnit.MILLISECONDS.sleep(new Random().nextInt(1000));
    			} 
    		}catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			zkClient.unsubscribeChildChanges(NODE_PATH, listener);
    		}
    	}
    	
    	private void checkMailSend() {
    		try {
    			lock.lock();
    			// 判断邮箱是否已满
    			List<String> mailList = zkClient.getChildren(NODE_PATH);
    			System.out.println("mailbox size: " + mailList.size());
    			if(mailList.size() >= MAILBOX_SIZE) {
    				// 邮箱已满,阻塞生产者,直到邮箱有空间
    				System.out.println("mailbox is full, please wait 。。。");
    				condition.await();
    				checkMailSend();
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			lock.unlock();
    		}
    	}
    }

    2.4.均衡负载

    首先我们需要简单的理解分布式和集群,通俗点说:分布式就是将一个系统拆分到多个独立运行的应用中(有可能在同一台主机也有可能在不同的主机上),集群就是将单个独立的应用复制多分放在不同的主机上来减轻服务器的压力。而Zookeeper不仅仅可以作为分布式集群的服务注册调度中心(例如dubbo),也可以实现集群的负载均衡。

    2.4.1.思路

    1. 首先我们要理解,如果是一个集群,那么他就会有多台主机。所以,他在Zookeeper中信息的存在应该是如下所示:
    2. 如上的结构,当服务调用方调用服务时,就可以根据特定的均衡负载算法来实现对服务的调用(调用前需要监听/service/serviceXXX节点,以更新列表数据)

    2.4.2.事例

    /**
     * 服务提供者
     * 
     * @author Administrator
     *
     */
    public class ServiceProvider {
    	// 静态常量
    	static String ZK_CONNECT_STR = "127.0.0.1:2181";
    	static String NODE_PATH = "/service";
    	static String SERIVCE_NAME = "/myService";
    	
    	private ZkClient zkClient;
    	
    	public ServiceProvider() {
    		zkClient = new ZkClient(new ZkConnection(ZK_CONNECT_STR));
    		System.out.println("sucess connected to zookeeper server!");
    		// 不存在就创建NODE_PATH节点
    		if(!zkClient.exists(NODE_PATH)) {
    			zkClient.create(NODE_PATH, "this is mailbox", CreateMode.PERSISTENT);
    		}
    	}
    	
    	public void registryService(String localIp, Object obj) {
    		if(!zkClient.exists(NODE_PATH + SERIVCE_NAME)) {
    			zkClient.create(NODE_PATH + SERIVCE_NAME, "provider services list", CreateMode.PERSISTENT);
    		}
    		// 对自己的服务进行注册
    		zkClient.createEphemeral(NODE_PATH + SERIVCE_NAME + "/" + localIp, obj);
    		System.out.println("注册成功![" + localIp + "]");
    	}	
    }
    
    /**
     * 消费者,通过某种均衡负载算法选择某一个提供者
     * 
     * @author Administrator
     *
     */
    public class ServiceConsumer {
    	// 静态常量
    	static String ZK_CONNECT_STR = "127.0.0.1:2181";
    	static String NODE_PATH = "/service";
    	static String SERIVCE_NAME = "/myService";
    	
    	private List<String> serviceList = new ArrayList<String>();
    	
    	private ZkClient zkClient;
    	
    	public ServiceConsumer() {
    		zkClient = new ZkClient(new ZkConnection(ZK_CONNECT_STR));
    		System.out.println("sucess connected to zookeeper server!");
    		// 不存在就创建NODE_PATH节点
    		if(!zkClient.exists(NODE_PATH)) {
    			zkClient.create(NODE_PATH, "this is mailbox", CreateMode.PERSISTENT);
    		}
    	}
    	
    	/**
    	 * 订阅服务
    	 */
    	public void subscribeSerivce() {
    		serviceList = zkClient.getChildren(NODE_PATH + SERIVCE_NAME);
    		zkClient.subscribeChildChanges(NODE_PATH + SERIVCE_NAME, new IZkChildListener() {
    			@Override
    			public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception {
    				serviceList = currentChilds;
    			}
    		});
    	}
    	
    	/**
    	 * 模拟调用服务
    	 */
    	public void consume() {
    		//负载均衡算法获取某台机器调用服务
    		int index = new Random().nextInt(serviceList.size());
    		System.out.println("调用[" + NODE_PATH + SERIVCE_NAME + "]服务:" + serviceList.get(index));
    	}
    }

    3.总结

    Zookeeper是一个功能非常强大的应用,除了上面几种应用外,还有命名服务、分布式协调通知等也是常用的场景。




    展开全文
  • ZooKeeper介绍及典型使用场景

    万次阅读 热门讨论 2015-01-15 20:40:31
    4 ZooKeeper典型使用场景 4.1 数据发布于订阅 4.1.1 特性、用法 发布与订阅即所谓的配置管理,顾名思义就是将数据发布到zk节点上,供订阅者动态获取数据,实现配置信息的集中式管理和动态更新。例如:全局的配置...

    1 概述

      ZooKeeper(动物园管理员),顾名思义,是用来管理Hadoop(大象)、Hive(蜜蜂)、Pig(小猪)的管理员,同时Apache HBase、Apache Solr、LinkedIn Sensei等众多项目中都采用了ZooKeeper。

      ZooKeeper曾是Hadoop的正式子项目,后发展成为Apache顶级项目,与Hadoop密切相关但却没有任何依赖。它是一个针对大型应用提供高可用的数据管理、应用程序协调服务的分布式服务框架,基于对Paxos算法的实现,使该框架保证了分布式环境中数据的强一致性,提供的功能包括:配置维护、统一命名服务、状态同步服务、集群管理等。

      在分布式应用中,由于工程师不能很好地使用锁机制,以及基于消息的协调机制不适合在某些应用中使用,因此需要有一种可靠的、可扩展的、分布式的、可配置的协调机制来统一系统的状态。Zookeeper的目的就在于此。

    2 特征

    1. ZooKeeper是简单的:ZooKeeper的核心是一个精简文件系统,它提供一些简单的操作和一些额外的抽象操作,例如:排序和通知。
    2. ZooKeeper是富有表现力的:ZooKeeper的原语操作是一组构件(building block),可用于实现很多协调数据结构和协议,例如:分布式队列、分布式锁和一组同级节点中的leader选举(leader election)。
    3. ZooKeeper具有高可用性:ZooKeeper运行在集群上,被设计成具有较高的可用性,因此应用程序可以完全依赖它。ZooKeeper可以帮助系统避免出现单点故障,从而构建一个可靠的应用。
    4. ZooKeeper采用松耦合交互方式:在ZooKeeper支持的交互过程中,参与者之间不需要彼此了解。例如:ZooKeeper可以被用作一个rendezvous机制,让进程在不了解其他进程或网络状况的情况下能够彼此发现并进行交互。参与协调的各方甚至可以不必同时存在,因为一个进程在ZooKeeper中留下一条消息,在该进程结束后,另外一个进程还可以读取这条消息。
    5. ZooKeeper是一个资源库:ZooKeeper提供了一个关于通用协调模式实现和方法的开源共享存储库,能使程序员免于编写这类通用的协议。所有人都能够对这个资源库进行添加和改进,随着时间的推移,会使每个人都从中收益。
    6. ZooKeeper是高性能的:在它的诞生地Yahoo!公司,对于以写为主的工作负载来说,ZooKeeper的基准吞吐量已超过每秒10000个操作;对于常规的以读为主的工作负载来说,吞吐量更是高出好几倍。

    3 ZooKeeper的数据模型

    理解ZooKeeper的一种方法是将其看做一个具有高可用性的文件系统。但这个文件系统中没有文件和目录,而是统一使用节点(node)的概念,称为znode。znode既可以保存数据(如同文件),也可以保存其他znode(如同目录)。所有的znode构成一个层次化的数据结构,。

    • Persistent Nodes: 永久有效地节点,除非client显式的删除,否则一直存在
    • Ephemeral Nodes: 临时节点,仅在创建该节点client保持连接期间有效,一旦连接丢失,zookeeper会自动删除该节点
    • Sequence Nodes: 顺序节点,client申请创建该节点时,zk会自动在节点路径末尾添加递增序号,这种类型是实现分布式锁,分布式queue等特殊功能的关键

      ZooKeeper是Hadoop的正式子项目,与Hadoop密切相关但却没有任何依赖。它是一个针对大型应用提供高可用的数据管理、应用程序协调服务的分布式服务框架,基于对Paxos算法的实现,使该框架保证了分布式环境中数据的强一致性,提供的功能包括:配置维护、统一命名服务、状态同步服务、集群管理等。

    4 ZooKeeper典型使用场景

    4.1 数据发布于订阅

    4.1.1 特性、用法

    发布与订阅即所谓的配置管理,顾名思义就是将数据发布到zk节点上,供订阅者动态获取数据,实现配置信息的集中式管理和动态更新。例如:全局的配置信息、地址列表等。

    4.1.2 具体用法

    1. 索引信息和集群中机器节点状态放在zk的一些指定节点,供各个客户端订阅使用。
    2. 系统日志(经处理后)存储,这些日志通常2-3天后清除。
    3. 应用中用到的一些配置信息集中管理,在应用启动的时候主动来获取一次,并在节点上注册一个Watcher,以后每次配置有更新,实时通知到应用,获取最新的配置信息。
    4. 业务逻辑中需要用到的一些全局变量,比如一些消息中间件的消息队列通常有个offset,这个offset存放在zk上,这样集群中每个发送者都能知道当前的发送进度。
    5. 系统中有些信息需要动态获取,并且还会存在人工手动去修改这个信息。以前通常是暴露出接口,例如JMX接口,有了zk后,只要将这些信息存放到zk节点上即可。

    4.2 命名服务

    4.2.1 特性、用法

    这个主要是作为分布式命名服务,通过调用zk的create node api,能够很容易创建一个全局唯一的path,可以将这个path作为一个名称。

    4.3 分布通知/协调

    4.3.1 特性、用法

    ZooKeeper中特有的watcher注册于异步通知机制,能够很好的实现分布式环境下不同系统之间的通知与协调,实现对数据变更的实时处理。使用方法通常是不同系统都对zk上同一个znode进行注册,监听znode的变化(包括znode本身内容及子节点内容),其中一个系统update了znode,那么另一个系统能够收到通知,并做出相应处理。

    使用ZooKeeper来进行分布式通知和协调能够大大降低系统之间的耦合。

    4.3.2 具体用法

    1. 心跳检测机制:检测系统和被测系统之间并不直接关联起来,而是通过zk上某个节点关联,大大减少系统耦合。
    2. 系统调度模式:某系统有控制台和推送系统两部分组成,控制台的职责是控制推送系统进行相应的推送工作。管理人员在控制台做的一些操作,实际上是修改了zk上某些节点的状态,而zk就把这些变化通知给它们注册watcher的客户端,即推送系统,于是,做出相应的推送任务。
    3. 工作汇报模式:一些类似于任务分发系统,子任务启动后,到zk来注册一个临时节点,并定时将自己的进度进行汇报(将进度写回这个临时节点),这样任务管理者就能够实时指导任务进度。

    4.4 分布式锁

    4.4.1 特性、用法

    分布式锁,主要得益于ZooKeeper保证数据的强一致性,即zk集群中任意节点(一个zk server)上系统znoe的数据一定相同。

    锁服务可以分为两类:

    1. 保持独占锁:所有试图来获取这个锁的客户端,最终只有一个可以成功获得这把锁。通常的做法是把zk上的一个znode看做是一把锁,通过create znode的方式来实现。所有客户端都去创建/distribute_lock节点,最终成功创建的那个客户端也即拥有了这把锁。
    2. 控制时序锁:所有试图来获取这个锁的客户端,最终都是会被安排执行,只是有个全局时序了。与保持独占锁的做法类似,不同点是/distribute_lock已经预先存在,客户端在它下面创建临时有序节点(可以通过节点控制属性控制:CreateMode.EPHEMERAL_SEQUENTIAL来指定)。zk的父节点(/distribute_lock)维持一份sequence,保证子节点创建的时序性,从而形成每个客户端的全局时序。

    4.5 集群管理

    4.5.1 特性、用法

    1. 集群机器监控:这通常用于那种对集群中机器状态、机器在线率有较高要求的场景,能够快速对集群中机器变化做出响应。这样的场景中,往往有一个监控系统,实时监测集群机器是否存活。过去的做法通常是:监控系统通过某种手段(比如ping)定时检测每个机器、或每个机器定时向监控系统发送心跳信息。这种做法存在两个弊端:1.集群中机器有变动的时候,牵连修改的东西比较多。2.有一定的延迟。利用ZooKeeper,可以实现另一种集群机器存活性监控系统:a.客户端在节点x上注册watcher,如果x的子节点发生变化,会通知该客户端。b.创建EPHEMERAL类型的节点,一旦客户端和服务器的会话结束或过期,该节点就会消失。例如:监控系统在/clusterServers节点上注册一个watcher,以后每动态加机器,就往/culsterServer下创建一个EPHEMERAL类型的节点:/clusterServer/{hostname}。这样,监控系统就能实时知道机器的增减情况,至于后续处理就是监控系统的业务了。
    2. Master选举:在分布式环境中,相同的业务应用分布在不同的机器上,有些业务逻辑(例如一些耗时的计算、网络I/O处理),往往需要让整个集群中的某一台机器进行执行,其余机器可以共享这个结果,这样可以减少重复劳动、提高性能。利用ZooKeeper的强一致性,能够保证在分布式高并发情况下节点创建的全局唯一性,即:同时有多个客户端请求创建/currentMaster节点,最终一定只有一个客户端请求能够创建成功。利用这个特性,就能很轻易的在分布式环境中进行集群选取了。另外,这种场景演化一下,就是动态Master选举。这就要用到 EPHEMERAL_SEQUENTIAL类型节点的特性了。上文中提到,所有客户端创建请求,最终只有一个能够创建成功。在这里稍微变化下,就是允许所有请求都能够创建成功,但是得有个创建顺序,于是所有的请求最终在zk上创建结果的一种可能情况是这样: /currentMaster/{sessionId}-1、/currentMaster/{sessionId}-2、/currentMaster/{sessionId}-3……。每次选取序列号最小的那个机器作为Master,如果这个机器挂了,由于他创建的节点会马上消失,那么之后最小的那个机器就是Master了。

    4.5.2 具体用法

    1. 在搜索系统中,如果集群中每个机器都生成一份全量索引,不仅耗时,而且不能保证彼此之间索引数据一致。因此让集群中的Master来进行全量索引的生成,然后同步到集群中其它机器。
    2. Master选举的容灾措施是,可以随时进行手动指定master,就是说应用在zk在无法获取master信息时,可以通过比如http方式,向一个地方获取master。

    4.6 分布式队列

    4.6.1 特性、用法

    队列方面,有两种方式:一种是常规的先进先出队列,另一种是要等到队列成员聚齐之后的才统一按序执行。

    对于先进先出队列,和分布式锁服务中的控制时序场景基本原理一致,这里不再赘述。

    第二种队列其实是在FIFO队列的基础上作了一个增强。通常可以在/queue这个znode下预先建立一个/queue/num节点,并且赋值为n(或者直接给/queue赋值n),表示队列大小,之后每次有队列成员加入后,就判断下是否已经到达队列大小,决定是否可以开始执行了。这种用法的典型场景是,分布式环境中,一个大任务Task A,需要在很多子任务完成(或条件就绪)情况下才能进行。这个时候,凡是其中一个子任务完成(就绪),那么就去/taskList下建立自己的临时时序节点(CreateMode.EPHEMERAL_SEQUENTIAL),当/taskList发现自己下面的子节点满足指定个数,就可以进行下一步按序进行处理了。

    展开全文
  • Elasticsearch Top5典型应用场景

    万次阅读 2018-09-16 19:56:50
    刚接触Elasticsearch的朋友,或多或少会遇到一个问题,Elasticsearch在实际公司应用中除了搜索到底能做什么? 本文给出了答案。 除了“You Know, for Search”,Elasticsearch的使用会不断增长和变化。...

    Elasticsearch 最少必要知识实战教程直播回放

    题记

    刚接触Elasticsearch的朋友,或多或少会遇到一个问题,Elasticsearch在实际公司应用中除了搜索到底能做什么?
    本文给出了答案。

    除了“You Know, for Search”,Elasticsearch的使用会不断增长和变化。ObjectRocket作为一家托管云计算公司,已经在ObjectRocket平台上提供托管Elasticsearch一段时间了,并且能够看到我们客户之间的一些明确趋势以及他们如何使用该产品。以下是我们在平台上看到的Top5场景用例:

    1 - 记录和日志分析

    对于熟悉Elasticsearch的人来说,这个应该不足为奇。围绕Elasticsearch构建的生态系统使其成为最容易实施和扩展日志记录解决方案之一。我们平台上的许多用户都没有什么不同,他们利用这一点来将日志记录添加到他们的主要用例中,或者将我们纯粹用于日志记录。

    从Beats,Logstash到Ingest Nodes,Elasticsearch为您提供了大量的选项,可以在任何地方获取数据并将其索引化。然后,使用Kibana工具使您能够创建丰富的仪表板和分析,而Curator使得您自动化管理索引的生命周期。

    这里写图片描述

    2 - 采集和组合公共数据

    与日志数据一样,Elastic Stack拥有大量工具,可以轻松抓取和索引远程数据。此外,与大多数文档存储一样,非严格的模式使Elasticsearch可以灵活地接收多个不同的数据源,并能使得这些数据可以管理和搜索。

    您可以查看的一个很酷的例子是我们的Twitter连接器(如下图所示),它允许您设置在Twitter上看到的主题标签,然后采集这些主题标签的相关推文并在Kibana中进行分析。我们在核心Elastic Stack组件上构建了该产品,并添加了一些额外的部件以帮助它扩展。
    这里写图片描述

    3 - 全文搜索

    毫无疑问,作为Elasticsearch的核心功能,全文搜索在此列表中占据重要位置。令人惊讶的是,我们的客户群中的全文检索的应用远远超出了传统的企业搜索或电子商务。

    从欺诈检测/安全到协作等,我们的用户已经证明Elasticsearch的搜索功能强大,灵活,并且包含大量工具以使搜索更容易; Elasticsearch有自己的查询DSL、内置的自动补全功能等等。

    4 - 事件数据和指标

    Elasticsearch还可以很好地处理时间序列数据,如指标(metrics )和应用程序事件。这是另一个巨大的Beats生态系统允许您轻松获取常见应用程序数据的区域。无论您使用何种技术,Elasticsearch都有很好的机会获取开箱即用的指标和事件…,添加该功能非常简单。

    5 - 数据可视化

    凭借大量的图表选项,地理数据的平铺服务和时间序列数据的TimeLion,Kibana是一款功能强大且易于使用的可视化工具。对于上面的每个用例,Kibana都会处理一些可视化组件

    一旦您对各种数据提取工具感到满意,您就会发现Elasticsearch + Kibana将成为您可视化数据的首选工具。

    #结论
    虽然并非每个用例都是如此,但这Top5是我们服务中统计出的最典型应用。 Elasticsearch和Elastic Stack的其他部分已被证明是非常通用的,正如您在上面所看到的,有多种方法可以将Elasticsearch集成到您今天所做的事情中并获得额外的洞察力。对我而言,这是Elasticsearch最酷的部分,它能够增强您已经使用的技术,而不仅仅是另一个数据库来存储您的数据。

    [1] 翻译:http://t.cn/EviiHBi

    这里写图片描述
    打造Elasticsearch基础、进阶、实战第一公众号!

    展开全文
  • 物联网四大产业群的典型应用场景

    千次阅读 2011-07-20 17:01:21
    物联网四大产业群的典型应用场景前文中把物联网应用分为四大类:RFID相关应用、基于传感网络的应用、M2M应用和两融合相关应用。同时也描述了物联网典型的“管控营一体”功能应用场景。本文将从技术架构角度...
  • Redis的典型应用场景

    千次阅读 2018-12-22 17:44:01
    如何解决缓存雪崩 事前:redis高可用,主从+哨兵,redis cluster,避免全盘崩溃 事中:本地ehcache缓存 + hystrix限流&降级,避免MySQL被打死 事后:redis持久,快速恢复缓存数据 缓存穿透是什么? 假如客户端每...
  • SpringBoot整合RabbitMQ之 典型应用场景实战二

    千次阅读 热门讨论 2018-10-09 15:16:42
    特别是在一些典型的应用场景以及业务模块中具有重要的作用,比如业务服务模块解耦、异步通信、高并发限流、超时业务、数据延迟处理等。上一篇博文我分享了RabbitMQ在业务服务模块解耦,异步通信与抢单系统高并发情况...
  • 智简园区网络解决方案大中型园区网络典型配置案例(虚拟化场景),华为针对大中型网络进行的真实设计方案,内容丰富,各位网络工程师撰写方案的资料参考
  • SAP解决方案(典型业务场景

    千次阅读 2018-06-28 11:08:12
    一、SAP解决方案 在华为云上部署SAP业务,能够充分利用华为云大规格、高性能、高安全和高可靠的能力,以及全生命周期的管理服务,帮助企业简化管理、节省成本、高效运营,快速实现数字转型 1、典型业务场景: ...
  • 这是OracleText比较普遍且常用的应用场景。创建OracleText中Context类型的索引,生成大量的关键词,用于加快类似于普通的like ‘%xx%’操作速度,或者查询一些比较大的文档。可以使用contains函数进行数据检索。缺点...
  • RabbitMQ的几种典型使用场景

    万次阅读 2018-08-17 11:37:16
    5.Message: 由Header和Body组成,Header是由生产者添加的各种属性的集合,包括Message是否被持久、由哪个Message Queue接受、优先级是多少等。而Body是真正需要传输的APP数据。 6.Binding:Binding联系了...
  • BC:带你温习并解读《中国区块链技术和应用发展白皮书》—区块链典型应用场景 目录 区块链典型应用场景 3.1 区块链与医疗健康 3.2 区块链与金融服务 3.3 区块链与供应链管理 3.4 区块链与文化娱乐 3.5 ...
  • Zookeeper系列(6)-- Zookeeper的典型应用场景

    千次阅读 多人点赞 2018-02-25 22:20:58
    在寒假前,完成了Zookeeper系列的前5篇...今天,完成Zookeeper系列的最后一篇也是最为重要的内容:Zookeeper的典型应用场景的介绍,我们只有知道zk怎么用,用在哪,我们才能真正掌握Zookeeper这个优秀的分布式协调框...
  • PaaS 的一个私有云典型应用场景

    千次阅读 2015-10-20 14:23:32
    只要是现有的中间件应用系统,如果系统采用的服务器数量比较多,或是采用中间件平台实例的数量...由于目前完整的 PaaS 私有云解决方案实施的案例不多,在此抛砖引玉,描述一个典型而比较完整的 PaaS 的私有云应用场景
  • 典型综合场景数据流转设计 综合场景一 T+1数据加工 图 4 T+1方式数据流转   T+1是数据仓库领域最为常见的数据集成模式,T+1模式下数据仓库会在每天固定时间点采集当天或者前一天交易系统数据。 根据数据...
  • 一种典型的架构是在Hadoop和服务存储之间使用队列进行解耦,以防止压垮目标服务存储,一般会选择Kafka作为队列,该架构会导致相同数据冗余存储在DFS(用于对计算结果进行离线分析)和Kafka(用于分发)上。...
  • 无人驾驶技术的7大典型应用场景

    千次阅读 2019-07-23 17:28:52
    来源 | 数据观综合无人驾驶风口来临,引得各方资本竞相追逐。据业内预测,2019年到2020年无人驾驶L3(条件自动)级别的汽车将实现量产,2022年后部分企业将实现L...
  • 各种机器学习算法的应用场景分别是什么?   关于这个问题我今天正好看到了这个文章。讲的正是各个算法的优劣分析,很中肯。 https://zhuanlan.zhihu.com/p/25327755正好14年的时候有人做过一个实验[1],比较在...
  •  为了实现自动的线上运维,我们必须对机器的上/下线情况有一个全聚德监控。通常在新增机器的时候,需要首先将指定的Agent部署到这些机器上去。Agent部署启动之后,会首先向ZooKeeper的指定节点进行注册,具体的...
  • 前言动态查找树主要有:二叉查找树、平衡二叉树、...B树和B+树非常典型场景就是用于关系型数据库的索引(MySQL)B树B树是一种平衡多路搜索树,B树与红黑树最大的不同在于,B树的结点可以有多个子女,从几个到几千个。
  • 5G技术切合了传统制造企业智能制造转型对无线网络的应用需求,能满足工业环境下设备互联和远程交互应用需求,在协同设计、 自动控制、柔性生产、辅助装配等十大工业典型应用领域中起着关键支撑作用...
  • ZooKeeper八大典型的应用场景

    千次阅读 2020-01-26 17:18:57
    什么是配置中心,有什么用? 数据发布/订阅( Publish/Subscribe)系统,即所谓的配置中心,顾名思义就是发布者将数据发布到ZooKeeper的一个或一系列节点上,供订阅者进行数据订阅,进而达到动态获取数据的目的,实现...
  • 数据中台 业务应用典型场景

    千次阅读 2020-05-25 15:43:43
    (三)华为组件能力架构 根据数据中台技术能力架构,数据接入、存储计算、数据分析数据服务、数据资产管理数据运营管理六方面能力对应华为公司多个技术组件,具体如下图所示: 图3华为数据中台...,适用于不同的场景...
  • 注:论文发表于《包装工程》杂志2017年第6期“工业设计”栏目。虽然是17年才发表,但这篇论文其实是很早之前写的,所以用的案例比较老。...方法 通过阐述交互设计各阶段中客观场景、目标场景、实际场景...
  • 3.非当前reactor线程调用的各种方法,在设置参数的时候通过hashcode,例如在推送系统的业务线程里面,根据用户的标识,找到对应的channel引用,然后调用Write类方法向该用户推送消息,就会进入到这种场景。...
  • 其中,众多的变化在今天看起来不可思议,但在未来,正是稀疏平常的场景。 壹|未来的银行业 未来30年,货币将如何发展? 是采用数字加密货币,还是继续延用国家货币,又或两者兼有? 现在的银行业又将...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 200,189
精华内容 80,075
关键字:

典型化场景是什么