chlins 10 X 10
Last updated: 2018-12-14
chlins:~ Desktop$ node home.js

> Blog.purpose
Sharing something interesting in my limited life.

> Blog.author
chlins

> Blog.more
check here
zookeeper小谈

介绍

ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services. All of these kinds of services are used in some form or another by distributed applications. Each time they are implemented there is a lot of work that goes into fixing the bugs and race conditions that are inevitable. Because of the difficulty of implementing these kinds of services, applications initially usually skimp on them ,which make them brittle in the presence of change and difficult to manage. Even when done correctly, different implementations of these services lead to management complexity when the applications are deployed.

以上摘自官方文档对zookeeper的定义和主要功能的介绍,简单的来说,可以将它定义为一个分布式的协调器,本身它也是Google chubby框架的开源实现,可以用它来实现分布式锁,配置中心等功能。zookeeper的文件存储模型本身也是非常的友好的,是一种类似标准文件系统的树形结构,如:

1
2
3
4
5
6
7
8
/------
/Services-------
/Service1
/Service2

/Groups---------
/Group1
/Group2

数据结构特征:

  1. 目录项称为znode,唯一标识
  2. znode下可以创建子znode,每个znode可以存储数据,类似redis中的key-value
  3. znode可以定义版本
  4. znode可以通过session与server之间创建临时节点,即当session失效后,自动删除znode
  5. 顺序节点,即zk提供自动向后编号节点,例如 app1, app2, app3 ……
  6. 提供watch机制,可以对znode进行监控

应用场景

👆介绍了zk的存储的数据结构,现在我们看看可以用它来实现哪些功能

  • 分布式锁

​ zk可以实现跨主机之间的锁,实现的方法其实就是创建一个临时的目录节点,查看该目录下的子目录中节点编号最小的那个节点,如果是自己创建的,则拿到了锁,否则对比自己小的中最大的那个节点建立监听器,注意这里为什么不是对最小的那个建立监听器是为了避免一旦最小节点的锁释放,而导致需要向所有监听节点发送事件而导致的羊群效应,当自己为集群中最小的节点时,即拿到锁,释放锁只要删除自己创建的znode就可以了。

  • 队列

​ 创建顺序节点,每次返回节点编号数最小的那个,即实现了FIFO。

  • 命名服务

​ 通过znode间的层次关系以及顺序节点的特效可以实现更加方便快捷的服务命名。

  • 配置中心

​ 集群中如果某个配置变更,需要所有运行的app切换至新的配置,如果手工去操作,当集群规模很大时,无异于是非常繁琐的一个工作,这时候我们可以让所有的app的去监控配置目录,由应用自主重启。

  • 集群管理

​ 集群的管理主要是两个核心功能,即新机器的上线和旧机器的下线,我们可以很方便的通过watch机制来实现。

Zab协议

zookeeper之所以能够实现分布式,保障数据的一致性,是通过zookeeper atomic broadcast来保障的,即zookeeper原子广播协议,在分布式领域,有一个非常经典的理论,即CAP理论,也同样有一个非常经典的分布式算法,即Paxos算法,不过Paxos算法的工程实现较为复杂,所以后来出现了Multi Paxos算法,例如zab和raft等。

集群状态

  1. 崩溃恢复状态

进入情况:

  • 服务启动
  • leader服务崩溃或者网络故障
  • 新节点加入集群且集群处于广播状态

此时集群异常,需要开始新的一轮选主,节点状态又可分为以下四种:

  • looking 集群无leader,准备选主
  • following 集群存在leader
  • leading 即唯一leader
  • observing 观察者

数据模型:

  • sid server id标识机器
  • zxid 事务id 递增

选主规则:

  • 初始状态会给自己投票
  • 接收到其他服务器的投票后,优先检查zxid,zxid比较大的优先作为leader,若相同,则比较sid,大的优先作为leader
  • 超过集群半数的机器投了一个node,则投票结束,node设置各自为leader或者follower
  1. 消息广播状态

进入情况:

集群已有leader,且超过半数的机器状态同步完成

这个状态就是集群的正常工作态,也就是数据同步的状态

  • 读请求由follower或observer直接返回给client
  • 写请求统一都会被转发给leader,leader分配唯一的事务id,然后向follower发起proposal,follower收到后首先以事务日志的形式写到磁盘上,防止丢失,然后在写入成功后,向leader发送成功写入的Ack,leader收到半数以上的follower的Ack后,广播commit消息通知follower进行事务提交,同时自身也会进行commit

Reference

感谢广大网友的热心分享

https://mp.weixin.qq.com/s/DjYEreC-5ADiZXKdlzpnxw

http://zookeeper.apache.org/

https://www.ibm.com/developerworks/cn/opensource/os-cn-zookeeper/index.html

https://www.cnblogs.com/felixzh/p/5869212.html

sync.Pool使用

sync.Pool

这是在golang1.3版本的时候新加入标准包sync里面的一个新特性,目的就是提供一个通用的对象池,复用临时对象,减少GC的压力,并且保证pool中的资源时协程安全的。

pool的用法也十分的简单,操作的话其实只有两个方法,分别是PutGet,语义是放入资源和取出资源。

1
2
3
4
5
6
7
8
9
10
package main

import "fmt"
import "sync"

func main() {
var pool sync.Pool

fmt.Println(pool.Get())
}

此时我们得到的结果是<nil>,是因为在声明pool的时候我们没有给它设置初始化资源的方法New func() interface{},现在我们声明一个方法

1
2
3
4
func main() {
pool := &sync.Pool{New: func() interface{}{return "hello"}}
fmt.Println(pool.Get())
}

此时我们得到的输出就是hello了,假设我们再次Get,此时会得到还是hello,那是因为我们传递的New方法就是返回一个hello对象,当pool中没有对象了,就会调用New分配一个资源出来,假设pool中有资源,还是会优先返回其中的资源,如下:

1
2
3
4
5
6
func main() {
pool := &sync.Pool{New: func() interface{}{return "hello"}}
pool.Put("world")
fmt.Println(pool.Get())
fmt.Println(pool.Get())
}

此时首先打印world再打印hello

最后在使用pool的时候同样也有一些注意点,如果不注意就会踩坑(😭)

注意:

  • 放入pool中的对象,并不会一直等待被Get,每过一段时间就会被GC回收,(所以千万不要把pool当成cache用!!!)

  • pool的应用场景主要是一些临时的状态无关的数据,所以一些有状态的数据并不适合存储在其中(例如数据库连接等)

Hello World

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

Test Code

1
2
3
4
5
6
7
8
9
package main

import (
"fmt"
)

func main() {
fmt.Println("Hello world!")
}