什么是Zk

ZooKeeper致力于提供一个高性能、高可用,且具备严格的顺序访问控制能力的分布式协调服务,是雅虎公司创建,是Google的Chubby一个开源的实现,也是Hadoop和Hbase的重要组件。

设计目标

简单的数据结构:共享的树形结构,类似文件系统,存储于内存;
可以构建集群:避免单点故障,3-5台机器就可以组成集群,超过半数正常工作就能对外提供服务;
顺序访问:对于每个读请求,zk会分配一个全局唯一的递增编号,利用这个特性可以实现高级协调服务;
高性能:基于内存操作,服务于非事务请求,适用于读操作为主的业务场景。3台zk集群能达到13w的QPS。

Zk的特性

Zk的特性从会话、数据节点、版本、Watcher、ACL权限控制、集群角色这些部分来了解,其中重点是数据节点与Watcher。

会话

客户端与服务端的一次会话连接,本质是TCP长连接,通过会话可以进行心跳检测和数据传输。
会话(session)是zk非常重要的概念,客户端和服务端之间的任何交互操作都与会话有关。
会话状态:Zk客户端和服务端成功连接后,就创建了一次会话,Zk会话在整个运行期间的生命周期中,会在不同的会话状态之间切换,这些状态包括:
CONNECTING、CONNECTED、RECONNECTING、RECONNECTRD、CLOSE。
一旦客户端开始创建Zk对象,那么客户端状态就会变成 CONNECTING 状态,同时客户端开始尝试连接服务端,连接成功后,客户端状态变为CONNECTED,通常情况下,由于断网或其他原因,客户端与服务端之间会出现断开情况,一旦碰到这种情况,Zk客户端会自动进行重连服务,同时客户端状态再次变成CONNECTING,直到重新连上服务端后,状态又变为CONNECTED,在通常情况下,客户端的状态总是介于CONNECTING和CONNECTED之间。但是,如果出现诸如会话超时、权限检查或是客户端主动退出程序等情况,客户端的状态就会直接变更为CLOSE状态。

Zk数据模型

Zookeeper的视图结构和标准的Unix文件系统类似(文件系统数据结构),其中每个节点称为数据节点或ZNode,每个ZNode可以存储数据,还可以挂载子节点,因此可以称为树。
第二点需要注意的是,每一个ZNode都必须有值,如果没有值,节点是不能创建成功的。
image.png
在Zookeeper中,ZNode是一个跟Unix文件系统路径相似的节点,可以往这个节点存储或获取数据,通过客户端可对ZNode进行增删改查的操作,还可以注册watcher监控ZNode的变化。
Zk节点类型
Znode有四种类型的目录节点,默认是PERSISTENT。

  1. PERSISTENT ­持久化目录节点

客户端与zookeeper断开连接后,该节点依旧存在,只要不手动删除该节点,他将永远存在;

  1. PERSISTENT_SEQUENTIAL­ 持久化顺序编号目录节点

客户端与zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号;

  1. EPHEMERAL­ 临时目录节点

客户端与zookeeper断开连接后,该节点被删除;

  1. EPHEMERAL_SEQUENTIAL­ 临时顺序编号目录节点

客户端与zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号;

  1. Container 节点(3.5.3 版本新增,如果Container节点下面没有子节点,则Container节点 在未来会被Zookeeper自动清除,定时任务默认60s 检查一次)
  2. TTL 节点( 默认禁用,只能通过系统配置 zookeeper.extendedTypesEnabled=true 开启,不稳定)

    image.png
    创建ZNode时设置顺序标识,ZNode名称后会附加一个值,顺序号是一个单调递增的计数器,由父节点维护。
    image.png
    在分布式系统中,顺序号可以被用于为所有的事件进行全局排序,这样客户端可以通过顺序号推断事件的顺序。

    监听通知机制

    注意:所有的通知都是一次性的,及无论是对节点还是对目录进行的监听,一旦触发,对应的监听即被移除。递归子节点,监听是对所有子节点的,所以,每个子节点下面的事件同样只会被触发一次。

    1. 如果注册的是对某个节点的监听,则当这个节点被删除,或者被修改时,对应的客户端将被通知
    1. 如果注册的是对某个目录的监听,则当这个目录有子节点被创建,或者有子节点被删除,对应的客户端将被通知
    1. 如果注册的是对某个目录的递归子节点进行监听,则当这个目录下面的任意子节点有目录结构的变化(有子节点被创建,或被删除)或者根节点有数据变化时,对应的客户端将被通知。

      Zookeeper 经典的应用场景

    2. 分布式配置中心
      2. 分布式注册中心
      3. 分布式锁
      4. 分布式队列
      5. 集群选举
      6. 分布式屏障
      7. 发布/订阅

      Zookeeper 的 ACL 权限控制(Access Control List)

      权限模式(Scheme)

      范围验证

      所谓的范围验证就是说 ZooKeeper 可以针对一个 IP 或者一段 IP 地址授予某种权限。比如我们可以让一个 IP 地址为“ip:192.168.0.110”的机器对服务器上的某个数据节点具有写入的权限。或者也可以通过“ip:192.168.0.1/24”给一段 IP 地址的机器赋权。

      口令验证

      也可以理解为用户名密码的方式。在 ZooKeeper 中这种验证方式是 Digest 认证,而 Digest 这种认证方式首先在客户端传送“username:password”这种形式的权限表示符后,ZooKeeper 服务端会对密码部分使用 SHA-1 和 BASE64 算法进行加密,以保证安全性。

      Super权限模式

      Super 可以认为是一种特殊的 Digest 认证。具有 Super 权限的客户端可以对 ZooKeeper 上的任意数据节点进行任意操作。

      授权对象(ID)

      IP 方式

      使用的授权对象可以是一个 IP 地址或 IP 地址段

      Digest 或 Super 方式

      则对应于一个用户名

      World 模式

      是授权系统中所有的用户

      权限信息(Permission)

      数据节点(c: create)创建权限,授予权限的对象可以在数据节点下创建子节点
      数据节点(w: wirte)更新权限,授予权限的对象可以更新该数据节点;
      数据节点(r: read)读取权限,授予权限的对象可以读取该节点的内容以及子节点的列表信息;
      数据节点(d: delete)删除权限,授予权限的对象可以删除该数据节点的子节点;
      数据节点(a: admin)管理者权限,授予权限的对象可以对该数据节点体进行 ACL 权限设置。

      命令

      getAcl:获取某个节点的acl权限信息
      setAcl:设置某个节点的acl权限信息
      addauth: 输入认证授权信息,相当于注册用户信息,注册时输入明文密码,zk将以密文的形式存储

      生成授权ID

      a.代码生成ID
      b.在xshell 中生成
      echo -n : | openssl dgst -binary -sha1 | openssl base64

      设置ACL方式

      节点创建的同时设置ACL

      setAcl 设置

      auth 明文授权
      IP 授权模式
      Super 超级管理员模式

      ZooKeeper 内存数据和持久化

      Zookeeper数据的组织形式为一个类似文件系统的数据结构,而这些数据都是存储在内存中的,所以我们可以认为,Zookeeper是一个基于内存的小型数据库。
      有了事务日志,为啥还要快照数据。
      快照数据主要是为了快速恢复,事务日志文件是每次事务请求都会进行追加的操作,而快照是达到某种设定条件下的内存全量数据。所以通常快照数据是反应当时内存数据的状态。事务日志是更全面的数据,所以恢复数据的时候,可以先恢复快照数据,再通过增量恢复事务日志中的数据即可。

      内存中的数据

      DataNode 是Zookeeper存储节点数据的最小单位

      事务日志

      事务日志:针对每一次客户端的事务操作,记录了操作时间,客户端会话ID,CXID,ZXID,操作类型,节点路径,节点数据(用#+ascii 码表示),节点版本。

      数据快照

      数据快照用于记录Zookeeper服务器上某一时刻的全量数据,并将其写入到指定的磁盘文件中。

      问题一:简单说一下 zk 集群动态扩容/缩容 的几种方式(扩容2种 缩容2种)?

      缩容:
      缩减掉 Observer 很简单,基本不会影响源集群。
      缩减 Follower,就稍微复杂些。
      扩容:
      Observer 扩容
      Follower 扩容

      问题二:当我们的系统查询性能不佳时,只要关注 SQL 优化和索引优化就行了。MySQL 的其他部分跟我们没啥影响。这种说法对吗?

      当向 MySQL 发送一个请求的时候, 会发生一下事情:
      1)客户端发送一条查询给服务器。
      2)服务器先检查查询缓存,如果命中了缓存,则立刻返回存储在缓存中的结果。否则进入下一阶段(当然从 MySQL8.0 开始,这个部分就没有了) 。
      3)服务器端进行 SQL 解析、预处理,再由优化器生成对应的执行计划。
      4) MySQL 根据优化器生成的执行计划,调用存储引擎的 API 来执行查询。
      5)将结果返回给客户端。
      所以 MySQL 查询的生命周期大致可以按照顺序来看:从客户端到服务器,然后在服务器上进行解析,生成执行计划,执行,并返回结果给客户端。所以查询由一系列子任务组成,每个子任务都会消耗一定的时间。如果要优化查询,实际上要优化其子任务,要么消除其中一些子任务,要么减少子任务的执行次数, 要么让子任务运行得更快。其中“执行”可以认为是整个生命周期中最重要的阶段,这其中包括了大量为了检索数据到存储引擎的调用以及调用后的数据处理,包括排序、分组等。但是决定不能认为其他子任务对查询的性能毫无影响。

      问题三:zookeeper 是如何保证事务的顺序一致性的?

      zookeeper 采用了全局递增的事务 Id 来标识,所有的 proposal(提议)都在被提出的时候加上了zxid,zxid 实际上是一个 64 位的数字,高 32 位是 epoch( 时期; 纪元; 世; 新时代)用来标识 leader 周期,如果有新的 leader 产生出来,epoch 会自增,低 32 位用来递增计数。当新产生 proposal 的时候,会依据数据库的两阶段过程,首先会向其他的 server 发出事务执行请求,如果超过半数的机器都能执行并且能够成功,那么就会开始执行。

      问题四:在工作中如何优化MySQL?简单描述下优化思路

      最好是按照以下顺序优化:
      1.通过慢查询分析工具等分析工具找到需要优化的SQL
      2.SQL语句及索引的优化
      3.数据库表结构的优化
      4.系统配置的优化
      5.硬件的优化

      问题五:简单说下事务日志和快照是什么?

      ZooKeeper集群中的每个服务器节点每次接收到写操作请求时,都会先将这次请求发送给leader,leader将这次写操作转换为带有状态的事务,然后leader会对这次写操作广播出去以便进行协调。当协调通过(大多数节点允许这次写)后,leader通知所有的服务器节点,让它们将这次写操作应用到内存数据库中,并将其记录到事务日志中。
      当事务日志记录的次数达到一定数量后(默认10W次),就会将内存数据库序列化一次,使其持久化保存到磁盘上,序列化后的文件称为”快照文件”。每次拍快照都会生成新的事务日志。
      有了事务日志和快照,就可以让任意节点恢复到任意时间点(只要没有清理事务日志和快照)。

      问题六:什么情况下设置了索引但无法使用

      1.以“%”开头的LIKE语句,模糊匹配
      2. OR语句前后没有同时使用索引
      3. 数据类型出现隐式转化(如varchar不加单引号的话可能会自动转换为int型)
      4.通用答案:根据成本,判断使用索引花费更高

      问题七:ZK的事务日志存放在哪里包含了哪些内容?简单描述一下

      dataLogDir目录是ZK的事务日志目录,包含了所有ZK的事务日志。正常运行过程中,针对所有更新操作,在返回客户端“更新成功”的响应前,ZK会确保已经将本次更新操作的事务日志写到磁盘上,只有这样,整个更新操作才会生效。每触发一次数据快照,就会生成一个新的事务日志。事务日志的文件名是log.,zxid是写入这个文件的第一个事务id。