软件架构演变+zookeeper--->安装配置+数据模型+常用命令+与java交互

Posted ahcfl

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了软件架构演变+zookeeper--->安装配置+数据模型+常用命令+与java交互相关的知识,希望对你有一定的参考价值。

一、软件架构演进

软件架构的发展经历了由单体架构、垂直架构、SOA架构到微服务架构的演进过程,

下面我们分别了解一下这几个架构。

可参考阿里淘宝的 14 次架构演进之路

软件架构演进概览:

image-20210616193754993

1. 单体架构

image-20210616194119788
特点:all in one
① 所有功能集中在一个项目中
② 所有功能都要打成war包部署到服务器
③ 通过集群(session共享集群,如使用redis缓存存储session数据)来提高服务器的性能

优点:①.项目架构简单,前期开发的成本低,周期短,小型企业首选.
缺点:①全部的功能都集中在一个项目中完成,对于大型项目来说,开发难度高,不容易开发及扩展和维护

2. 垂直架构

image-20210616194417124

架构说明:按照业务进行切割,形成小的单体项目。

特点:
    ①.以单体架构为单位进行系统的划分,划分成一个个系统.
    ②.项目与项目之间独立开发,开发效率高.
    ③.项目是以接口调用为主(早期主要使用webservice)
    
优点:
    ①.项目架构简单,前期开发的成本低,周期短,小型企业首选.
    ②.垂直架构进行mvc分层设计,针对分层做相应的处理做到集群(10~1000)
    ③.不同的项目采用不同的技术实现. 
缺点:
    ①.全部的功能都集中在一个项目中完成,对于大型项目来说,开发难度高,不容易开发及扩展和维护.
    ②.集群扩展有瓶颈
    ②.项目与项目之间存在数据冗余,耦合度高.
    ②.项目是以接口调用为主,存在数据同步问题.

3. SOA架构

image-20210616194718951
架构说明:将重复功能或模块抽取成组件的形式,对外提供服务,在项目与服务之间使用ESB(企业服务总线)的形式作为通信的桥梁。

特点:
    ①.基于soa服务思想进行功能的抽取(重复代码问题解决),以服务为中心来管理项目
    ②.各个系统之间要进行调用,所以出现ESB来管理项目(可以使用各种技术实现:webservice,rpc等)
    ③.ESB是作为系统与系统之间连接的桥梁,进行统一管理.

优点:
    ①.重复代码进行了抽取,提高了开发效率,提高了系统的可维护性.
    ②.可以针对某个系统进行扩展,做集群更容易.
    ③.采用ESB来管理服务组件,有利于降低企业开发项目难度 

缺点:
    ①.系统与服务的界限模糊的,不利于设计.
    ②.ESB是作为系统与系统之间桥梁,没有统一标准,种类很多,不利于维护!

4. 微服务架构

image-20210616195323239 image-20210616195217990
架构说明:
将系统服务层完全独立出来,抽取为一个一个的微服务。
抽取的粒度更细,遵循单一原则。
采用轻量级框架协议传输。

架构优点:
服务拆分粒度更细,有利于提高开发效率。 
可以针对不同服务制定对应的优化方案。
适用于互联网时代,产品迭代周期更短。

架构缺点:
粒度太细导致服务太多,维护成本高。 
分布式系统开发的技术成本高,对团队的挑战大。

5. Serverless架构

image-20210616195841135

减少运维,降低部署难度。

目前微服务架构开发Serverless模式的有腾讯的tsf:https://cloud.tencent.com/product/tsf

二、zookeeper分布式协调服务

1. 服务注册中心引入

问题:一旦采用分布式架构,服务都部署在不同的机器上,如何实现服务的通信呢?服务和服务之间如何进行调用的?

解决方案:
需要使用到服务注册中心了(zookeeper可以实现服务注册中心)。
 采用服务中心,可以发现服务,进行服务治理。

无服务中心,服务之间调用

image-20210616200506888

使用服务注册中心管理服务

image-20210616200602863

2. zookeeper介绍

【1】概念

https://zookeeper.apache.org/

ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务。是Google的Chubby开源实现,是Hadoop和Hbase的重要组件。是一款在分布式系统中用于程序协调的软件
提供的功能包括:配置维护、域名服务、分布式同步、组服务等
其由JAVA编写,支持JAVA 和C两种语言的客户端。

【2】应用场景

配置管理: 分布式集群环境下配置文件共享

image-20210324091227584

分布式锁: 分布式锁实现原理

image-20210616201906677

服务注册中心:

image-20210616201849896

3. zookeeper安装启动停止

下载地址: https://zookeeper.apache.org/releases.html

【1】window

1.确保jdk环境变量配置正确
2.将apache-zookeeper-3.5.8-bin.tar.gz压缩文件进行解压
==注意: 不要安装在有中文和空格的目录下==

解压后目录结构:

image-20210616202141725

3.在安装目录下新建一个data文件夹

image-20210616202232526

4.进入conf文件夹并将zoo_samle.cfg文件复制一份重命名为zoo.cfg

5.编辑并修改zoo.cfg文件内容中dataDir目录地址

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IHoX7FaM-1624429525215)(C:/Users/16096/Desktop/java127/Zookeeper/img/18.png)]

配置说明:

# zookeeper时间配置中的基本单位 (毫秒)
tickTime=2000
# 允许follower初始化连接到leader最大时长,它表示tickTime时间倍数 即:initLimit*tickTime
initLimit=10
# 允许follower与leader数据同步最大时长,它表示tickTime时间倍数 
syncLimit=5
#zookeper 数据存储目录
dataDir=/tmp/zookeeper
#对客户端提供的端口号
clientPort=2181
#单个客户端与zookeeper最大并发连接数
#maxClientCnxns=60
# 保存的数据快照数量,之外的将会被清除
#autopurge.snapRetainCount=3
#自动触发清除任务时间间隔,小时为单位。默认为0,表示不自动清除。
#autopurge.purgeInterval=1

6.启动服务端 ,找到bin目录下zkServer.cmd,双击运行。

注意:

1.此版本zookeeper启动会默认占用8080端口,如果你当前8080端口被占用了,那么启动的时候会闪退,cmd窗口会自动关闭,此时可以在zoo.cfg配置文件里面最后一行添加admin.serverPort=8123,然后再双击zkServer.cmd运行就ok了。

2.dataDir路径配置的一定不要包含中文,并且路径使用’\\‘不要使用’/’。

7.客户端访问,在bin目录下双击zkCli.cmd

image-20210616202830754

【2】linux

这里以centos7为例,确保虚拟中安装了jdk8及以上版本

1、下载安装包,上传到 /opt 目录下,解压缩文件

tar -zxvf apache-zookeeper-3.5.8-bin.tar.gz

2、解压后的文件夹移动到 /usr/local 目录下 并重新命名

mv apache-zookeeper-3.5.8-bin /usr/local/zookeeper

3、进入zookeeper目录,创建数据存放目录

cd /usr/local/zookeeper/
mkdir data

4、进入conf目录,将文件zoo_sample.cfg备案一份,文件名为zoo.cfg

cd conf
cp zoo_sample.cfg zoo.cfg

5、修改zoo.cfg配置文件,修改dataDir属性为自己的目录地址:

vi zoo.cfg

启动zookeeper服务端

# 先切换到zookeeper的bin目录
cd /usr/local/zookeeper/bin/
# 执行脚本
./zkServer.sh start

启动zookeeper客户端

# 同样在bin目录下执行
./zkCli.sh

注:

  1. 执行完如果出现WatchedEvent state:SyncConnected type:None path:null。一直卡主住这里可以敲回车即可。

  2. zookeeper默认创建了一个名称为"zookeeper"的znode节点。

停止服务

./zkServer.sh stop

4. zookeeper数据模型

【1】节点介绍

Zookeeper是一个树形目录服务, 数据模型和Linux的文件系统目录树很类似, 用一个层次化的结构存放数据。这里面的每一个节点都被称之为: ZNode(节点), 每一个节点上都会保存自己的数据和节点信息.节点可以有子节点, 同时也可以将少量数据存放在该节点上(1MB)。

image-20210616204435677

image-20210615100829981

zookeeper存储的数据节点 都是以/ 开头 以树状结构进行存储数据!

并且zookeeper对所在的节点和数据 自带监控功能,可以随时监听到数据节点和存储数据的变化。

【2】 节点分类

Zookeeper的节点分为四大类

Persistent [pəˈsɪstənt] : 持久化节点【默认】 创建的节点永久保存
Ephemeral [ɪˈfemərəl] :临时节点 【-e】      创建的节点为临时的,当客户端重启时节点消失
Persistent_Sequential :持久化顺序节点 【-s】 创建的节点持久且有序
Ephemeral_Sequential [sɪˈkwenʃl] 临时顺序节点 【-es】 创建的节点临时且有序

-e: 临时
-s:  持久顺序
-es: 临时顺序

操作Zookeeper的多种方式

image-20210616204953324

5、zookeeper常用命令

通过命令可以操作Zookeeper上的各个节点

# 查看帮助
help 

# create 命令  注:当服务器重启时,所有的临时节点都会消失
create /节点路径			     # 【持久节点】创建空节点
create /节点路径 值 		        # 【持久节点】创建节点,并赋值
create -e /节点路径			     # 【临时节点】创建空节点
create -e /节点路径 值		    # 【临时节点】创建节点,并赋值
create -s /节点路径			     # 【持久顺序节点】创建空节点
create -s /节点路径	值		    # 【持久顺序节点】创建节点,并赋值
create -es /节点路径			 # 【临时顺序节点】创建空节点
create -es /节点路径	值		# 【临时顺序节点】创建节点,并赋值
例如:
create app1_cj
create app2_cj 200
create -e app3_cj 300

# set 命令
set /节点路径 value		// 给指定的节点设置值
set -s /节点路径 value	// 设置完值后查看节点状态
set -v version /节点路径 value // 设置当前节点的值
说明:
version:这个版本值 
值为当前版本号: 在当前版本号的基础上+1
值为-1: 在当前版本号的基础上+1 
使用这两个命令可查看当前版本
ls -s  /节点路径
set -s /节点路径 value  
例如:
set -v 0 app1_cj 100  # 那么 app1_cj的dataVersion版本就变为了 0+1

# ls 命令
ls /节点路径	// 查看目标节点下所有的子节点
ls -s /节点路径  // 查看节点详细信息
ls -w /节点路径		// 一次性监控节点状态(监控节点的删除)
ls -R /节点路径		// 递归罗列所有子节点
-------------------------------------------
cZxid = 0x24  //创建节点的事物ID
ctime = Mon Aug 10 16:45:17 CST 2020 //创建时间
mZxid = 0x26 //修改节点的事物ID
mtime = Mon Aug 10 16:46:39 CST 2020 //修改时间
pZxid = 0x24 //子节点变更的事物ID
cversion = 0 //这表示对此znode的子节点进行的更改次数(不包括子节点)
dataVersion = 1 // 数据版本,变更次数
aclVersion = 1 //权限版本,变更次数
ephemeralOwner = 0x0 //临时节点所属会话ID
dataLength = 3 //数据长度
numChildren = 0 //子节点数(不包括子子节点)
-------------------------------------------

# get命令
get /节点名       # 获取指定节点上的值
get -s /节点路径  # 获取值的同时查看节点状态
get -w /节点路径  # 一次性监控当前节点数据的变化

# 其他
stat /节点路径   # 查看节点属性
delete /节点路径	# 删除单个节点
deleteall /节点路径  # 删除带有子节点的节点
close   # 输入命令后会一直卡着,可以敲一下回车键回到客户端命令模式。
connect # 连接命令,如close完了以后想重新建立连接可以输入此命令
quit    # 退出当前客户端

三、Java客户端操作Zookeeper(了解)

已经了解通过zookeeper自带的zkCli客户端来操作zookeeper节点,那么我们怎么使用我们的java程序来操作我们的zookeeper呢。

java操作Zookeeper的方式有多种: (了解)

​ Apache Zookeeper提供的名称为Zookeeper类作为java客户端操作

​ 第三方提供的ZkClient作为java客户端操作Zookeeper

​ Apache Zookeeper提供的Curator框架

1. Zookeeper类操作zookeeper节点

Zookeeper客户端API ,核心类:org.apache.zookeeper.ZooKeeper创建与服务端的连接

构造函数参数说明如下:

参数名称类型说明
connectStringString连接串,包括ip+端口 ,集群模式下用逗号隔开 192.168.148.139:2181,192.168.148.140:2181
sessionTimeout**int **会话超时时间,该值不能超过服务端所设置的 minSessionTimeout 和maxSessionTimeout
watcherWatcher会话监听器,服务端事件将会触发该监听
sessionId**long **自定义会话ID
sessionPasswdbyte[]会话密码
canBeReadOnly**boolean **该连接是否为只读的
hostProviderHostProvider服务端地址提供者,指示客户端如何选择某个服务来调用,默认采用StaticHostProvider实现

pom依赖:Zookeeper客户端的pom依赖

<dependencies>
	<dependency>
		<groupId>org.apache.zookeeper</groupId>
		<artifactId>zookeeper</artifactId>
		<version>3.5.8</version>
	</dependency>
</dependencies>

创建 ZookeeperDemo类 演示 创建 PERSISTENT 节点:

1.创建maven项目,导入客户端maven依赖
2.创建zookeeper连接对象
3.通过zookeeper对象发送命令
4.关闭连接
package com.ahcfl.zookeeper;

import org.apache.zookeeper.*;
import java.util.Scanner;

public class ZookeeperDemo {
    // Zookeeper创建连接的方式是异步的.
    // 需要让main方法等待,我们使用了等待键盘录入
    public static void main(String[] args) throws Exception{
        //1.创建zookeeper对象,用于连接Zookeeper服务器
        // 参数1: 服务器地址:端口
        // 参数2: 会话连接超时时间
        // 参数3: 监控zookeeper对象的连接状态
        ZooKeeper zooKeeper = new ZooKeeper("127.0.0.1:2181", 1000,
                new Watcher() {
                    public void process(WatchedEvent event) {
                        if(event.getState()==Event.KeeperState.SyncConnected){
                            //   链接成功    线程放行
                            System.out.println("=======创建链接完毕======"+event.getState());
                        }
                    }
                }
        );
        System.in.read();//  主线程阻塞 :等待输入
        //2.判断/tps节点是否存在,不存在则创建
        // 如果节点不存在 返回null
        if(zooKeeper.exists("/tps",false) == null){
            // 当 /tps 节点不存在是则创建节点,并设置值
            // 参数1: 节点路径
            // 参数2: 节点数据
            // 参数3: Access Control: 访问节点的权限控制
                    //  OPEN_ACL_UNSAFE :完全开放
                    //  CREATOR_ALL_ACL :给创建该znode连接所有权限
                    //  READ_ACL_UNSAFE :所有的客户端都可读
            // 参数4: 节点类型
            zooKeeper.create("/tps",
                    "hello zookeeper".getBytes(),
                    ZooDefs.Ids.OPEN_ACL_UNSAFE,
                    CreateMode.PERSISTENT);
            System.out.println("/tps 节点创建完成-- ");
        }
        zooKeeper.close();//  关闭链接
    }
}

可以 ls /查看 get /tps获取值

【1】创建节点

ZooKeeper zooKeeper;

@Before
public void  before(){
    //1.zookeeper连接服务器
    try {
        zooKeeper  = new ZooKeeper("127.0.0.1:2181", 1000,
                new Watcher() {
                    public void process(WatchedEvent event) {
                        if(event.getState()==Event.KeeperState.SyncConnected){
                            //   链接成功    线程放行
                            System.out.println("=======创建链接完毕======"+event.getState());
                        }

                    }
                }
        );
    } catch (IOException e) {
        e.printStackTrace();
    }
}

/**
 * 创建持久节点
 */
@Test
public void test0() throws Exception {
    if(zooKeeper.exists("/tps-p1",false)==null){
        // 创建节点
        String result = zooKeeper.create(
            "/tps-p1",
            "持久节点信息".getBytes("utf-8"),
            ZooDefs.Ids.OPEN_ACL_UNSAFE,
            CreateMode.PERSISTENT
        );
        System.out.println("/tps-p1 创建成功: "+result);
    }
}

/**
 * 创建持久有序节点
 */
@Test
public  void  test1(){
    try {
        if(zooKeeper.exists("/tps-p1",false) == null){
            //  返回值 就是节点的路径
            String path = zooKeeper.create("/tps-p1", "hello pesistent order".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
            System.out.println("/tps-p1 节点创建完成-- "+path);
            byte[] data = zooKeeper.getData(path,null, null);
            System.out.println("/tps-e 持久有序节点数据 -- "+new String(data));
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

// 同上:
// CreateMode.EPHEMERAL 创建临时节点
// CreateMode.EPHEMERAL_SEQUENTIAL 创建临时有序节点
    
@After
public  void  after(){
    try {
        zooKeeper.close();//  关闭链接
    } catch (Exception e) {
        e.printStackTrace();
    }
}

【2】更新节点

注意参数3 :

version 版本一致才可以更新节点数据: 每次更新 版本号自动+1

如果我们在调用api 传递version=-1 那么版本号不参与更新!不会自动+1

@Test  //  更新节点数据
public  void  test4(){
    try {
        // 参数1: 节点路径/名称
        // 参数2: 设置的节点数据
        // 参数3: 节点版本
        //      节点的当前版本  或  -1
        zooKeeper.setData("/tps-p/node","xixi".getBytes(),-1);
        System.out.println("设置成功...");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

【3】删除节点

@Test  //  删除节点
public  void  test5(){
    try {
        zooKeeper.delete("/tps-p/node",-1);
        System.out.println("删除成功...");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

【4】获取节点

@Test  //  获取节点内容数据
public  void  test6(){
    try {
        // 创建点击状态对象,用于存放查询的节点状态信息
        Stat state = new Stat();
        byte[] data = zooKeeper.getData("/tps-p", false, state);
        System.out.println("获取数据:"+new String(data));
        System.out.println("获取数据版本号:"+state.getVersion());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

【5】获取子节点数据

在 /tps-p 节点下创建两个节点 p1和p2 数据内容分别是 : nihao p1 和 nihao p2

@Test  //  获子取节点内容数据
public  void  test7(){
    try {
        // 存放节点信息
        Stat parent_state = new Stat();
        // 获取所有子节点名称
        List<String> children = zooKeeper.getChildren("/tps-p", false,parent_state);
        for (String child : children) {
            Stat son_state = new Stat(); // 子节点的状态
            byte[] data = zooKeeper.getData("/tps-p/" + child, false, son_state);
            System.out.println("子节点路径/名称:/tps-p/"+child);
            System.out.println("子节点获取数据:"+new String(data));
            System.out.println("获取数据版本号:"+son_state.getVersion());
            System.out.println("+++++++++++++++++++++++++");
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

【6】监听节点数据变化

监听节点

执行下面代码: 进入阻塞监听状态,在客户端窗口 设置节点数据进行测试

@Test  //  监听节点数据变化
public  void  test8(){
    try {
        Stat state = new Stat();
        // 参数1: 节点路径/名称
        // 参数2: 编写监听对象 对节点数据进行监听
        zooKeeper.getData("/tps-p", new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                System.out.println(event);
                //  当节点数据变化  该方法会自动执行
                System.out.println("节点数据变化一次"+event.getState());
            }
        },state);
        System.in.read(); //  当前线程阻塞 一直监听
    } catch (Exception e) {
        e.printStackTrace();
    }

}

监听子节点数据变化(了解)

@Test  //  监听子节点以及子节点数据变化
public  void  test9(){
    try {
        Stat state = new Stat();
        // 获取所有子节点名称
        List<String> children = zooKeeper.getChildren("/tps-p", false, state);

        for (String child : children) {
            zooKeeper.getData("/tps-p/" + child, new Watcher() {
                @Override
                public void process(WatchedEvent event) {
                    String childPath = event.getPath();
                    try {
                        byte[] data = zooKeeper.getData( childPath, null, state);
                        System.out.println("子节点:" + childPath + " 节点数据变化了。。。。" + new String(data));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }, state);

        }
        System.out.println(架构师必备软件:安装Dubbo注册中心(Zookeeper-3.4.6)

自从看了大牛级大数据架构师整理的ZooKeeper安装配置!瞬间会!

Dubbo的RPC远程过程调用+Dubbo的负载均衡+Zookeeper注册中心

软件系统架构演变

Linux安装部署集群化软件Zookeeper

互联网技术架构演变过程-软件架构设计学习第四天(非原创)