Zookeeper学习笔记

目录

一、Zookeeper简介

1.1 什么是Zookeeper

1.2 Zookeeper应用场景

二、搭建Zookeeper服务器

2.1 安装启动

2.2 zoo.cfg配置说明

2.3 基础操作命令:

三、内部数据模型

3.1 zk是怎么存储数据的?

3.2 Znode结构是什么样的?

3.3 Znode有哪些类型?

3.4 数据持久化机制是什么?

四、客户端使用(zkCli):

4.1 多节点类型创建:

4.2 查询节点:

4.3 删除节点:

4.4 设置权限:

五、Curator客户端使用

5.1 简介:

5.2 快速使用

六、zk实现分布式锁

6.1 概述:

6.2 zk使用读锁:

6.3 zk使用写锁:

6.4 羊群效应:

6.5 Curator使用读写锁

七、zk的watch机制

7.1 watch机制原理:

7.2 zkCli客户端使用watch

7.3 Curator客户端使用watch

八、集群实战

8.1 zk集群中的角色有哪些?

8.2 集群的搭建

九、ZAB协议

9.1 什么是ZAB协议:

9.2 ZAB协议定义的四种节点状态:

9.3 集群启动时选举Leader选举:

9.4 崩溃恢复时Leader选举:

9.5 主从之间数据同步:

9.6 zk中的NIO与BIO应用

十、CAP理论

10.1 什么是CAP理论?

10.2 Zookeeper中的CAP:

10.3 BASE理论


 

一、Zookeeper简介

1.1 什么是Zookeeper

  • ZooKeeper主要服务于分布式系统,可以用ZooKeeper来做:统一配置管理、统一命名服务、分布式锁、集群管理。
  • 使用分布式系统就无法避免对节点管理的问题(需要实时感知节点的状态、对节点进行统一管理等等),而由于这些问题处理起来可能相对麻烦和提高了系统的复杂性,ZooKeeper作为一个能够通用解决这些问题的中间件就应运而生了。
  • zk在整个分布式组件中属于鼻祖的地位

1.2 Zookeeper应用场景

分布式协调组件:

分布式锁:实现分布式锁,可以做到强一致性。(具体请参考后续的ZAB)

无状态话的实现:保存登录信息,用户访问其他服务是就能做到无状态。

二、搭建Zookeeper服务器

2.1 安装启动

官网:Apache ZooKeeper

解压:tar -zxvf apache-zookeeper-3.7.1-bin.tar.gz

进入:apache-zookeeper-3.7.1-bin/conf

拷贝配置文件(配置文件名必须是zoo.cfg):cp zoo_sample.cfg zoo.cfg

修改配置:vim zoo.

修改数据保存地址(建议在zookeeper安装同目录):dataDir=/usr/zookeeper/zkdata

启动:

cd /usr/zookeeper/apache-zookeeper-3.7.1-bin/bin

./zkServer.sh start

查看状态:./zkServer.sh stauts

2.2 zoo.cfg配置说明

#ZK中的时间配置最小但域,其他时间配置以整数倍tickTime计算
tickTime=2000
#Leader允许Follower启动时在initLimit时间内完成数据同步,单位:tickTime
initLimit=10
#Leader发送心跳包给集群中所有Follower,若Follower在syncLimit时间内没有响应,那么Leader就认为该follower已经挂掉了,单位:tickTime
syncLimit=5
#配置ZK的数据目录(数据持久化机制)
dataDir=/usr/zookeeper/zkdata
#配置ZK的日志目录(若没有配置dataLogDir,则日志数据也会默认保存在dataDir中)
dataLogDir=/usr/local/zookeeper/logs
#用于接收客户端请求的端口号
clientPort=2181
#是否开启管理端服务。 可选值 : true ,false 。 默认开启
admin.enableServer=false
#管理端服务端口。默认为 8080 。
admin.serverPort=8081

#ZK集群节点配置,端口号2888用于集群节点之间数据通信,端口号3888用于集群中Leader选举
server.1=192.168.123.100:2888:3888
server.2=192.168.123.101:2888:3888
server.3=192.168.123.102:2888:3888

2.3 基础操作命令:

  • 启动zk服务器:
./bin/zkServer.sh start ./confg/zoo.cfg
  • 查看服务器状态:
./bin/zkServer.sh status
  • 停止服务器:
./bin/zkServer.sh stop

三、内部数据模型

3.1 zk是怎么存储数据的?

数据存储在内存中,数据模型类似“数据结构”中的树,也类似文件系统的目录,即采用了分层存储结构,数据就保存在层级节点上(这个节点称为znode)

  • 与文件系统目录的区别:它的各个节点中是允许存储数据的,需要注意的是zk的每个节点存储数据不能超过1M。
  • 它的内存数据结果如下图:

3.2 Znode结构是什么样的?

Znode包括下面四部分:

data:保存数据
acl:权限,定义什么样的用户拥有什么哪些权限操作当前几点
    c:创建,允许创建子节点
    w:修改,允许更新子节点
    r:读,雨荨读取当前节点的内容以及子节点列表信息
    d:删除,运行删除改节点的子节点
    a:管理者权限,允许对该节点进行acl权限设置
stat:描述当前zonde元数据
child:记录当前节点的子节点(记录其子节点地址)

3.3 Znode有哪些类型?

  • 持久节点:创建出的节点,客户端会话结束后节点仍存在(保存数据)

                例(登录客户端后输入):create /test

  • 持久顺序节点:创建节点时,根据先后顺序,会在节点后带上一个数值,越靠后创建数值越大。适用于分布式锁(单调递增)

                例(登录客户端后输入):create -s /test

  • 临时节点:临时节点创建后,会话结束后,自动被删除。(利用该特点可以实现服务的注册与发现)

                例:create -e /test2

                临时节点心跳维持:(靠会话的session,session失效后就会删除)

  • 临时序号节点:创建节点是临时的,会话过期后,自动删除,且带根据添加的先后顺序自动添加序号。(使用临时的分布式锁)

                例:create -e -s /test2

  • Container节点(3.5.3版本新增):即容器节点,容器中没有任何节点,该节点会被zk定期删除(60s)

                例:create -c /test3

  • TTL节点:可以指定节点的到期时间,到期后被zk删除(不稳定)

3.4 数据持久化机制是什么?

  • 事务日志:zk把执行指令以日志的方式保存在dataLogDir指定的路径中
  • 数据快照:zk会在一定的时间间隔做一次内存快照,把数据保存在快照文件中
  • 数据回复:zk恢复数据时先读取快照文件恢复数据,然后读取日志文件做增量恢复,恢复速度很快。

四、客户端使用(zkCli):

zk提供的客户端工具,在安装目录的bin目录下:zkCli.sh

./zkCli.sh 执行后即可进入客户端

4.1 多节点类型创建:

  • 创建持久节点:create /test1
  • 创建持久序号节点:create -s /test2
  • 创建临时节点:create -e /test3
  • 创建临时序号节点:create -e -s /test4
  • 创建容器节点:create -c /test5
  • 创建带有数据的节点:create /test6 data1
  • 创建某个节点的子节点:create /test1/sub1 data1

4.2 查询节点:

  • 查询节点:

        查询直接子节点,例:ls /

        递归查询子节点(包括子节点的子节点),例:ls -R /

  • 查询节点信息:

        获取节点中的数据:get /test1/sub1

        获取节点的信息:get -s /test1/sub1

  • 节点信息字段描述:
cZxid:创节点的事务ID
mZxid:修改节点的事务ID
pZxid:添加和删除子节点的事务ID
ctime:节点创建时间
mtime:节点最近修改的时间
dataVsersion:节点内数据的版本,每更新一次,版本+1
aclVersion:节点的权限版本
ephemeralOwner:节点为临时节点时,值为节点所有者的session_id。否则,值为0
dataLength:节点内数据的长度
numChildren:节点拥有的子节点个数

4.3 删除节点:

  • 普通删除(拥有子节点的节点不能被删除):delete /test1/sub1
  • 乐观锁删除(根据数据的版本号删除节点):delete -v 1 /test1/sub2
  • 被删除的节点的dataVersion值要与 -v 指定的值一致时才能删除(这个特性可以用来做分布式的乐观锁)

4.4 设置权限:

  • 创建当前会话的账号和密码:addauth digest username1:123456
  • 创建节点并设置权限:

                例:create /test2 aaa auth:username1:123456:cdrwa

                说明:auth参数指定有权限的用户,cdrwa即声明有哪些权限

  • 其他会话需要操作节点需要创建同样的账号密码:addauth digest username1:123456

五、Curator客户端使用

5.1 简介:

Curator还为 ZooKeeper客户端框架提供了一些比较普遍的、开箱即用的、分布式开发用的解决方案,例如Recipe、共享锁服务、Master选举机制和分布式计算器等,帮助开发者避免了“重复造轮子”的无效开发工作。

Curator 客户端使用更加方便,功能更加强大,目前应用更加广泛。

5.2 快速使用

  • 1)项目引入依赖:
<!--需要和zookeeper服务端版本保持一致-->
<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.7.1</version>
</dependency>
<!--zk客户端Curator-->
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>5.2.1</version>
</dependency>
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>5.2.1</version>
</dependency>
<!-- fastjson -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.79</version>
</dependency>
  • 2)配置Curator:
#curator配置---由配置类CuratorConfig读取
curator:
  # zookeeper 地址
  #  connectString: 192.168.198.155:2182,192.168.198.155:2183,192.168.198.155:2184
  connectString: 192.168.0.161:2181
  # 重试次数
  retryCount: 3
  # 重试间隔时间
  elapsedTimeMs: 5000
  # session超时时间
  sessionTimeoutMs: 60000
  # 连接超时时间
  connectionTimeoutMs: 10000
  • 3)读取配置
@Data
@Component
@ConfigurationProperties(prefix = "curator")
public class CuratorConfig {
    private int retryCount;
    private int elapsedTimeMs;
    private String connectString;
    private int sessionTimeoutMs;
    private int connectionTimeoutMs;
}
  • 4)配置公用连接bean

/**
 * 公用连接创建对象
 */
@Configuration
public class ZkConfiguration {
    @Autowired
    private CuratorConfig curatorConfig;

    /**
     * 这里会自动调用一次start,请勿重复调用
     */
    @Bean(initMethod = "start")
    public CuratorFramework curatorFramework() {
        return CuratorFrameworkFactory.newClient(
                curatorConfig.getConnectString(),
                curatorConfig.getSessionTimeoutMs(),
                curatorConfig.getConnectionTimeoutMs(),
                new RetryNTimes(curatorConfig.getRetryCount(), curatorConfig.getElapsedTimeMs()));
    }
}
  • 5)测试:
/**
 * @description: CuratorTest
 * @date: 2022/10/1 10:57
 * @author: Sito
 * @version: 1.0
 */
@SpringBootTest
public class CuratorTest {
    @Autowired
    private CuratorFramework client;

    // 测试连接
    @Test
    public void contextLoads() {
        System.out.println(client.toString());
    }

    // 创建节点
    @Test
    public void createPath() throws Exception {
        // 父节点不存在则创建
        String path = client.create().creatingParentsIfNeeded().forPath("/zkblog/p1",
                "Java博客".getBytes(StandardCharsets.UTF_8));
        System.out.println(path);
        byte[] data = client.getData().forPath("/zkblog/p1");
        System.out.println(new String(data));
    }

    /**
     * 创建临时序号节点
     *
     * @throws Exception
     */
    @Test
    public void createNode() throws Exception {
        // 父节点不存在则创建
        String path = client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL)
                .forPath("/zkblog/p1", "Java博客".getBytes(StandardCharsets.UTF_8));
        System.out.println(path);
        byte[] data = client.getData().forPath("/zkblog/p1");
        System.out.println(new String(data));
    }

    // 赋值,修改数据
    @Test
    public void setData() throws Exception {
        int version = 0; // 当前节点的版本信息
        Stat stat = new Stat();
        client.getData().storingStatIn(stat).forPath("/zkblog/p1");
        version = stat.getVersion();
        // 如果版本信息不一致,说明当前数据被修改过,则修改失败程序报错
        client.setData().withVersion(version).forPath("/zkblog/p1",
                "Java林的博客".getBytes(StandardCharsets.UTF_8));
        byte[] data = client.getData().forPath("/zkblog/p1");
        System.out.println(new String(data));
    }

    // 查询节点
    @Test
    public void getPath() throws Exception {
        // 查内容
        byte[] data = client.getData().forPath("/zkblog/p1");
        System.out.println(new String(data));

        // 查状态
        Stat stat = new Stat();
        client.getData().storingStatIn(stat).forPath("/zkblog/p1");
        System.out.println(JSON.toJSONString(stat, true));
    }

    // 删除节点
    @Test
    public void deletePath() throws Exception {
        // deletingChildrenIfNeeded如果有子节点一并删除
        // guaranteed必须成功比如网络抖动时造成命令失败
        client.delete().guaranteed().deletingChildrenIfNeeded().inBackground(new BackgroundCallback() {
            @Override
            public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
                System.out.println("删除成功");
                // { "path":"/javacui/p1","resultCode":0,"type":"DELETE"}
                System.out.println(JSON.toJSONString(curatorEvent, true));
            }
        }).forPath("/zkblog/p1");
    }

    // 查询子节点
    @Test
    public void getPaths() throws Exception {
        List<String> paths = client.getChildren().forPath("/zkblog");
        for (String p : paths) {
            System.out.println(p);
        }
    }
}

六、zk实现分布式锁

6.1 概述:

  • 核心思想:当客户想要获取锁,则创建节点,使用完锁,则删除该节点
  • zk中的锁种类:
    • 读锁(共享锁):大家都可以读,上读锁的前提是没有写锁
    • 写锁:只有得到写锁,才能进行写操作。上写锁前提是之前没有任何锁

6.2 zk使用读锁:

1、在lock节点下创建临时顺序节点;

2、获取lock节点下序号比自己小的所有节点;

3、判断最小节点是否是读锁:

        如果最小节点是读锁,则上读锁成功。

        如果最小节点是写锁,则上读锁失败,此时监听最小节点

6.3 zk使用写锁:

1、在lock节点下创建临时顺序节点;

2、获取lock节点下所有节点;

3、判断自己是否为最小节点:

如果是,则写锁成功;

如果不是,说明前面还有锁,上锁失败,此时监听最小节点,如果最小节点有变化,则返回第2步

6.4 羊群效应:

描述:zk使用写锁时,高并发情况下,所有等待锁的节点都监听最小节点,会发生惊厥效应,即羊群效应

解决方案:将监听方案改成链式监听,按大小顺序依次监听比自己小的上个节点

6.5 Curator使用读写锁

使用读锁

@SpringBootTest
public class CuratorLockTest {
    @Autowired
    private CuratorFramework client;

    @Test
    public void testGetReadLock() throws Exception {
        // 读写锁
        InterProcessReadWriteLock interProcessReadWriteLock = new InterProcessReadWriteLock(client, "/lock1");
        // 获取读锁对象
        InterProcessLock interProcessLock = interProcessReadWriteLock.readLock();
        System.out.println("等待获取锁对象!");
        // 获取锁
        interProcessLock.acquire();
        System.out.println("成功获取锁,开始业务处理!");
        for (int i = 1; i <= 10; i++) {
            Thread.sleep(3000);
            System.out.println(i);
        }
        System.out.println("业务处理完成,开始释放锁!");
        // 释放锁
        interProcessLock.release();
        System.out.println("业务处理完成,锁已经释放!");
    }

    @Test
    public void testGetWriteLock() throws Exception {
        // 读写锁
        InterProcessReadWriteLock interProcessReadWriteLock = new InterProcessReadWriteLock(client, "/lock1");
        // 获取写锁对象
        InterProcessLock interProcessLock = interProcessReadWriteLock.writeLock();
        System.out.println("等待获取锁对象!");
        // 获取锁
        interProcessLock.acquire();
        for (int i = 1; i <= 100; i++) {
            Thread.sleep(300);
            System.out.println(i);
        }
        // 释放锁
        interProcessLock.release();
        System.out.println("等待释放锁!");
    }
}

七、zk的watch机制

7.1 watch机制原理:

轻量级设计:zookeeper的是watch机制,是一个轻量级的设计。服务器感知内容的变化,发送个事件类型和节点信息给客户端,不包含具体变更的内容,客户端根据事件自己去获取数据。

watche机制分为监听数据监听节点

watch监听机制:

1. 客户端注册Watcher到服务端;

2. 服务端收到请求,返回节点数据,并且在对应的哈希表里插入被监听的Znode路径和对应的监听者;

3. 节点数据变更后,服务器会查找哈希表,异步通知客户端,并且删除哈希表中对应的key-value;

4. 客户端回调Watcher处理变更应对逻辑;

7.2 zkCli客户端使用watch

指令示例

描述

get -w /node

一次性监听节点内容数据变化

ls -w /node

监听节点目录,创建、删除子节点都会收到通知。(修改节点数据不通知;子节点中创建节点不通知)

ls -R -w /node

监听节点所有目录变化(节点内容变化不通知)

7.3 Curator客户端使用watch

说明:Curator引入了Cache的概念用来实现对ZooKeeper服务器端进行事件监听。

Curator中的cache共有三种:

NodeCache(监听和缓存根节点变化)

PathChildrenCache(监听和缓存子节点变化)

TreeCache(监听和缓存根节点变化和子节点变化

具体使用请百度

八、集群实战

8.1 zk集群中的角色有哪些?

  • Leader:主

主服务器,集群中只有一个主。处理所有事务请求(写操作)

  • Follower:从

从服务器,只处理读请求,参与Leader选举。

  • Observer:观察者

只处理读请求,不参与Leader选举,提高集群性能

8.2 集群的搭建

创建4个节点,其中一个节点为Observer

  • 1、在dataDir指定的目录下创建4个文件夹
mkdir mkdir -p /usr/zookeeper/zkdata/zk1
mkdir mkdir -p /usr/zookeeper/zkdata/zk2
mkdir mkdir -p /usr/zookeeper/zkdata/zk3
mkdir mkdir -p /usr/zookeeper/zkdata/zk4
  • 2、创建4个节点的myid,并设置值
echo 1 > /usr/zookeeper/zkdata/zk1/myid
echo 2 > /usr/zookeeper/zkdata/zk2/myid
echo 3 > /usr/zookeeper/zkdata/zk3/myid
echo 4 > /usr/zookeeper/zkdata/zk4/myid
  • 3、修改配置文件zoo.conf,添加集群信息
#server.A=B:C:D
#- A 是一个数字,表示这个是第几号服务器。集群模式下需要在zoo.cfg中dataDir指定的目录下创建一个文件myid,这个文件里面有一个数据就是A的值,Zookeeper启动时读取此文件,拿到里面的数据与zoo.cfg里面的配置信息比较从而判断到底是哪个server。
#- B 是这个服务器的地址。
#- C 是这个服务器Follower与集群中的Leader服务器交换信息的端口。
#- D 是万一集群中的Leader服务器挂了,需要一个端口来重新进行选举,选出一个新的Leader,而这个端口就是用来执行选举时服务器相互通信的端口。
#下面单机模拟搭建集群
#server.A=B:C:D:observer  表示主机作为observer
server.1=127.0.0.1:2001:3001
server.2=127.0.0.1:2002:3002
server.3=127.0.0.1:2003:3003
server.4=127.0.0.1:2004:3004:observer
  • 4、创建4个zoo.conf配置文件,并修改端口,和数据保存位置
cp zoo.cfg zoo1.cfg
cp zoo.cfg zoo2.cfg
cp zoo.cfg zoo3.cfg
cp zoo.cfg zoo4.cfg

        修改4个配置文件配置:

dataDir=/usr/zookeeper/zkdata/zk1
clientPort=2181

dataDir=/usr/zookeeper/zkdata/zk2
clientPort=2182

dataDir=/usr/zookeeper/zkdata/zk3
clientPort=2183

dataDir=/usr/zookeeper/zkdata/zk4
clientPort=2184
  • 5、启动服务器:
./zkServer.sh start ../conf/zoo1.cfg
./zkServer.sh start ../conf/zoo2.cfg 
./zkServer.sh start ../conf/zoo3.cfg 
./zkServer.sh start ../conf/zoo4.cfg 
  • 6、连接Zookeeper
./zkCli.sh -server 192.168.0.161:2181,192.168.0.161:2182,192.168.0.161:2183,192.168.0.161:2184

九、ZAB协议

9.1 什么是ZAB协议:

        ZAB协议又称为 Zookeeper 原子广播协议,用于Zookeeper崩溃恢复场景,维持集群各副本数据一致性,当leader崩溃或者集群中参与选票的个数不足一半,表示整个集群对外服务不可用,需要进行崩溃恢复。

9.2 ZAB协议定义的四种节点状态:

  • Looking:选举状态
  • Following:从节点状态Follower
  • Leading:主节点状态Leader
  • Observing:观察者状态Observer

9.3 集群启动时选举Leader选举:

投票依据:

会根据myid和zXid大小进行投票选举,选择出一个主节点!

  • myid:就是创建的myid文件当中的值
  • zXid:事务id,就是只要在这个服务下做的增删改操作,查不算,每操作一次,那么zxid就会+1

选举流程如下:

第一轮投票:

  • 两个节点各自生成各自的选票,选票就是myid和zXid
  • 把票都互相交给对方(说白了就是我把我的情况告诉你,你把你的情况告诉我,咱俩公平点,选出一个能胜任的来当老大)
  • 两个节点各自选出zxid/myid最大的,放到投票箱当中

第二轮投票:

  • 把手上较大票交换给对方
  • 这时候再进行投票,选择zxid/myid最大的 投到箱子中

通过两轮的选票后,2号节点成功上任主节点!之所以要通过两轮就是为了确保选举的可靠性!

9.4 崩溃恢复时Leader选举:

        Leader建⽴完后,Leader周期性地不断向Follower发送⼼跳(ping命令,没有内容的socket)。当Leader崩溃后,Follower发现socket通道已关闭,于是Follower开始进⼊到Looking状态,重新回到上⼀节中的Leader选举过程,此时集群不能对外提供服务。

为什么要进行选举,而不是随便拿一个节点当主节点?

        之所以选举,就是为了选择出一个数据比较新的来当主节点,一般事务id比较大,那自然他的数据要比较新。而myid无非就是开放出来的一种人为干预选举的一种方式!也就是我想让哪台当主机,我可以设置myid特别大就可以了。

9.5 主从之间数据同步:

同步的原理就是:通过两阶段数据提交

  1. 向zk写数据的时候
  2. 先写到主节点的持久化数据文件当中,写完的时候返回一个ACK。
  3. 主节点收到ACK后,开始将数据发送给从节点。
  4. 从节点收到数据后开始写到本地数据文件当中。
  5. 从节点持久化完数据之后,返回ACK给主节点(通知主节点写完了)。
  6. 主节点在收到半数以后的ACK后向从节点发送提交。
  7. 这时候主节点和从节点再把数据同步到内存当中。

zk会数据同步,难道还会出现事务id不一样的情况?

        在第六步的时候,只要收到半数以上就开始同步内存数据,也就意味着假如有服务器网络延迟并没有发生ACK,但是也超过了半数,超过半数就不等他了,直接数据同步内存,而当别的服务器都同步完后,这时候网络延迟的那台服务器又好了,这时他的事务id就会和其他节点数据不一致!

9.6 zk中的NIO与BIO应用

NIO:(3.1版本后使用Netty来做)

  • 与客户端的链接是NIO(通过2181端口连接的客户端)
  • 客户端开启watch时,也是用的NIO

BIO:

  • 集群选举是,多个节点的投票同学端口使用的是BIO

十、CAP理论

CAP 理论正式成为分布式计算领域的公认定理

10.1 什么是CAP理论?

        即一个分布式系统最多只能同时满⾜⼀致性(Consistency)、可⽤性(Availability)和分区容错性(Partition tolerance)这三项中的两项。

  • ⼀致性(C):更新操作成功并返回客户端完成后,所有节点在同⼀时间的数据完全⼀致
  • 可⽤性(A):可⽤性指“Reads and writes always succeed”,即服务⼀直可⽤,⽽且是正常响应时间(指的是一切访问正常并且打开的值是自己预期的值,这叫可用)
  • 分区容错性(P):即分布式系统在遇到某节点或⽹络分区故障的时候,仍然能够对外提供满⾜⼀致性或可⽤性的服务。——避免单点故障,就要进⾏冗余部署,冗余部署相当于是服务的分区,这样的分区就具备了容错性。

10.2 Zookeeper中的CAP:

        Zookeeper追求的是CAP当中的CP,虽然追求的是一致性,但是在数据同步时,实际上并不是强⼀致性,⽽是顺序⼀致性(事务id的单调递增)。这一点从上面的主从服务器之间的数据同步就可以看出!

10.3 BASE理论

        eBay 的架构师 Dan Pritchett 源于对⼤规模分布式系统的实践总结,在 ACM 上发表⽂章提出BASE 理论,BASE 理论是对 CAP 理论的延伸,核⼼思想是即使⽆法做到强⼀致性(Strong Consistency,CAP 的⼀致性就是强⼀致性),但应⽤可以采⽤适合的⽅式达到最终⼀致性(Eventual Consitency)。

  • 基本可⽤(Basically Available):基本可⽤是指分布式系统在出现故障的时候,允许损失部分可⽤性,即保证核⼼可⽤。电商⼤促时,为了应对访问量激增,部分⽤户可能会被引导到降级⻚⾯,服务层也可能只提供降级服务。这就是损失部分可⽤性的体现。
  • 软状态(Soft State):软状态是指允许系统存在中间状态,⽽该中间状态不会影响系统整体可⽤性。分布式存储中⼀般⼀份数据⾄少会有三个副本,允许不同节点间副本同步的延时就是软状态的体现。mysql replication 的异步复制也是⼀种体现。
  • 最终⼀致性(Eventual Consistency):最终⼀致性是指系统中的所有数据副本经过⼀定时间后,最终能够达到⼀致的状态。弱⼀致性和强⼀致性相反,最终⼀致性是弱⼀致性的⼀种特殊情况。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值