1、磁盘阵列(RAID),有“独立磁盘构成的具有冗余能力的阵列”之意。
RAID0 是一种简单的、无数据校验的数据条带化技术。实际上不是一种真正的 RAID ,因为它并不提供任何形式的冗余策略。 RAID0 将所在磁盘条带化后组成大容量的存储空间,将数据分散存储在所有磁盘中,以独立访问方式实现多块磁盘的并读访问。由于可以并发执行 I/O 操作,总线带宽得到充分利用。再加上不需要进行数据校验,RAID0 的性能在所有 RAID 等级中是最高的。**理论上讲,一个由 n 块磁盘组成的 RAID0 ,它的读写性能是单个磁盘性能的 n 倍**,但由于总线带宽等多种因素的限制,实际的性能提升低于理论值。
RAID1 称为镜像,它将数据完全一致地分别写到工作磁盘和镜像 磁盘,它的磁盘空间利用率为 50% 。 RAID1 在数据写入时,响应时间会有所影响,但是读数据的时候没有影响。 RAID1 提供了最佳的数据保护,一旦工作磁盘发生故障,系统自动从镜像磁盘读取数据,不会影响用户工作。RAID1 与 RAID0 刚好相反,是为了增强数据安全性使两块 磁盘数据呈现完全镜像,从而达到安全性好、技术简单、管理方便。 RAID1 拥有完全容错的能力,但实现成本高。 RAID1 应用于对顺序读写性能要求高以及对数据保护极为重视的应用,如对邮件系统的数据保护
RAID5 应该是目前最常见的 RAID 等级,它的原理与 RAID4 相似,区别在于校验数据分布在阵列中的所有磁盘上,而没有采用专门的校验磁盘。对于数据和校验数据,它们的写操作可以同时发生在完全不同的磁盘上。因此, RAID5 不存在 RAID4 中的并发写操作时的校验盘性能瓶颈问题。另外, RAID5 还具备很好的扩展性。当阵列磁盘 数量增加时,并行操作量的能力也随之增长,可比 RAID4 支持更多的磁盘,从而拥有更高的容量以及更高的性能。RAID5的磁盘上同时存储数据和校验数据,数据块和对应的校验信息存保存在不同的磁盘上,当一个数据盘损坏时,系统可以根据同一条带的其他数据块和对应的校验数据来重建损坏的数据。与其他 RAID 等级一样,重建数据时, RAID5 的性能会受到较大的影响。RAID5 兼顾存储性能、数据安全和存储成本等各方面因素,它可以理解为 RAID0 和 RAID1 的折中方案,是目前综合性能最佳的数据保护解决方案。 RAID5 基本上可以满足大部分的存储应用需求,数据中心大多采用它作为应用数据的保护方案。
标准 RAID 等级各有优势和不足。自然地,我们想到把多个 RAID 等级组合起来,实现优势互补,弥补相互的不足,从而达到在性能、数据安全性等指标上更高的 RAID 系统,实际得到较为广泛应用的只有 RAID01 和 RAID10 两个等级。一些文献把这两种 RAID 等级看作是等同的,本文认为是不同的。 RAID01 是先做条带化再作镜像,(先分开,两个地方的备份相同,而不是同一个地方备份两次_)本质是对物理磁盘实现镜像;而 RAID10 是先做镜像再作条带化,是对虚拟磁盘实现镜像。相同的配置下,通常 RAID01 比 RAID10 具有更好的容错能力。RAID01 兼备了 RAID0 和 RAID1 的优点,它先用两块磁盘建立镜像,然后再在镜像内部做条带化。 RAID01 的数据将同时写入到两个磁盘阵列中,如果其中一个阵列损坏,仍可继续工作,保证数据安全性的同时又提高了性能。 RAID01 和 RAID10 内部都含有 RAID1 模式,因此整体磁盘利用率均仅为 50% 。(RAID100 通常是大数据库的最佳选择。)
2、Zookeeper 是一个分布式协调服务的开源框架。 主要用来解决分布式集群中应用系统的一致性问题,也可以看做是一个分布式的小文件(不大于1M)的存储,主要就是来管理集群中的一些公共的数据的(元数据–描述数据的数据–描述节点), 从而达到集群的管理,例如怎样避免同时操作同一数据造成脏读的问题。有leader和follower,leader可以增删改查,follower只能查,遇到其他请求,转发给leader操作,有时还有观察者Observe,只能读,也不具有follower的投票选leader的权利,主要用于提高读的并发访问量。如下是其六个作用:
1、一致性问题
2、统一命名服务
3、分布式配置管理:管理一些公共的配置信息
4、分布式消息队列(PubSub模式,是 Publish/Subscribe 的缩写,意为“发布/订阅”模式)订阅发布模式:定义了一种一对多的依赖关系,让多个订阅者对象同时监听某一个主题对象。这个主题对象在自身状态变化时,会通知所有订阅者对象,使它们能够自动更新自己的状态。
5、分布式锁
6、分布式协调
3、zookeeper的特性(偏序是什么意思,尚未解决)
1) 全局数据一致:每个 server 保存一份相同的数据副本, client 无论连接到哪个 server,展示的数据都是一致的,这是最重要的特征;
2) 可靠性:如果消息被其中一台服务器接受,那么将被所有的服务器接受。
3) 顺序性:包括全局有序和偏序两种:全局有序是指如果在一台服务器上消息 a 在消息 b 前发布,则在所有 Server 上消息 a 都将在消息 b 前被发布;偏序是指如果一个消息 b 在消息 a 后被同一个发送者发布, a 必将排在 b 前面(非全局)。
4) 数据更新原子性:一次数据更新要么成功(半数以上节点成功),要么失败,不存在中间状态;
5) 实时性: Zookeeper 保证客户端将在一个时间间隔范围内获得服务器的更新信息,或者服务器失效的信息。
4、zookeeper的数据模型
ZooKeeper 的数据模型,在结构上和标准文件系统的非常相似,拥有一个层次的命名空间,都是采用树形层次结构,ZooKeeper 树中的每个节点被称为—Znode。和文件系统的目录树一样,ZooKeeper 树中的每个节点可以拥有子节点。但也有不同之处:
1.Znode 兼具文件和目录两种特点。既像文件一样维护着数据、元信息、ACL、时间戳等数据结构,又像目录一样可以作为路径标识的一部分,并可以具有子Znode。用户对Znode具有增、删、改、查等操作(权限允许的情况下)。
2.Znode具有原子性操作,读操作将获取与节点相关的所有数据,写操作也将替换掉节点的所有数据。另外,每一个节点都拥有自己的 ACL(访问控制列表),这个列表规定了用户的权限,即限定了特定用户对目标节点可以执行的操作。
3.Znode存储数据大小有限制。ZooKeeper虽然可以关联一些数据,但并没有被设计为常规的数据库或者大数据存储,相反的是,它用来管理调度数据,比如分布式应用中的配置文件信息、状态信息、汇集位置等等。这些数据的共同特性就是它们都是很小的数据,通常以 KB为大小单位。ZooKeeper的服务器和客户端都被设计为严格检查并限制每个Znode的数据大小至多1M,常规使用中应该远小于此值。
4.Znode通过路径引用,如同Unix中的文件路径。路径必须是绝对的,因此他们必须由斜杠字符来开头。除此以外,他们必须是唯一的,也就是说每一个路径只有一个表示,因此这些路径不能改变。在ZooKeeper中,路径由Unicode字符串组成,并且有一些限制。字符串"/zookeeper"用以保存管理信息,比如关键配额信息。
可以通过在zkServer.sh 中 添加一个参数 : ZOO_USER_CFG="-Djute.maxbuffer=10240000" 修改znode数据大小,单位为字节
5、Zookeeper的Znode有有两种,临时节点和永久节点,节点类型在创建的时候就被确定了,而且后期不能改变。临时节点:该节点的生命周期依赖于创建它们的会话,一旦会话结束,临时节点将会被自动删除,也可以手动删除,临时节点不准许有子节点存在永久节点:此类型节点生命周期不依赖于会话,并且只能手动删除。Znode 还有一个序列化(顺序)的特性,如果创建的时候指定的话,该 Znode 的名字后面会自动追加一个不断增加的序列号。序列号对于此节点的父节点来说是唯一的,这样便会记录每个子节点创建的先后顺序。它的格式为“%10d”(10 位数字,没有数值的数位用 0 补充,例如“0000000001”)。
创建永久节点:(PERSISTENT)永久节点
[zk: localhost:2181(CONNECTED) 3] create /hello world
Created /hello
创建临时节点:(EPHEMERAL)临时节点
[zk: localhost:2181(CONNECTED) 5] create -e /abc 123
Created /abc
创建永久序列化节点:(PERSISTENT_SEQUENTIAL)永久节点、序列化
[zk: localhost:2181(CONNECTED) 6] create -s /zhangsan boy
Created /zhangsan0000000004
创建临时序列化节点:(EPHEMERAL_SEQUENTIAL)临时节点、序列化
zk: localhost:2181(CONNECTED) 11] create -e -s /lisi boy
Created /lisi0000000006
6、分布式:将一个业务或者任务分开,分别进行部署。 集群:将相同的系统或者业务部署了多次,在集群中各个节点是相同的(一般来说,这两种会共同存在,想想厨师做饭)
7、安装一个上传工具 rz : yum -y install lrzsz
rz 上传
sz 下载
8、在zookeeper的bin里启动zookeeper(zkServer.sh start ./zkCli.sh)资料里有个zookeeper的插件,在zookeeper打开后shell中随意输入,会给出可操作的命令帮助,或者-help------zookeeper的操作可以网络查询
create -s /path data 创建顺序节点
create -e /path data 创建临时节点
create /path data 创建持久节点
ls 查看某一个目录下有哪些子节点
get 查看某一个节点的数据和这个节点的信息
set path data 修改数据
delete path 删除节点
rmr path 强制删除
9、zookeeper的watcher机制
实现 watcher的方案:
1) 客户端向zookeeper注册 warcher(注册监听)
2) 服务端 某一个节点发生了状态的改变,触发watcher
3) 客户端就会回调对应的函数, 进行相关的操作
watcher的特点:
1) 一次性触发: 这个事件只能触发一次
2) 对事件进行封装: 通知状态 事件的类型 节点路径
3) event 异步发送,不会影响主线程
4) 先注册再触发
10、java操作
package com.itheima.zookeeper;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.ChildData;
import org.apache.curator.framework.recipes.cache.TreeCache;
import org.apache.curator.framework.recipes.cache.TreeCacheEvent;
import org.apache.curator.framework.recipes.cache.TreeCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.junit.Test;
public class ZookeeperTest {
// 创建节点
@Test
public void createNode() throws Exception {
//1. 创建 curator 核心对象 : CuratorFramework
ExponentialBackoffRetry retry = new ExponentialBackoffRetry(1000,3);
CuratorFramework client = CuratorFrameworkFactory.newClient("192.168.72.141:2181,192.168.72.142:2181,192.168.72.143:2181", retry);
//2. 通过 CuratorFramework 获取连接
client.start();
//3. 执行操作 : 默认不传递任何的值, 默认将当前服务器的ip地址保证zookeeper中
client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath("/test02");
//4. 释放资源
client.close();
}
// 2) 修改值
@Test
public void updateDataNode() throws Exception {
//1. 创建 curator 核心对象 : CuratorFramework
ExponentialBackoffRetry retry = new ExponentialBackoffRetry(1000,3);
CuratorFramework client = CuratorFrameworkFactory.newClient("192.168.72.141:2181,192.168.72.142:2181,192.168.72.143:2181", retry);
//2. 通过 CuratorFramework 获取连接
client.start();
//3. 修改数据 :
client.setData().forPath("/test02","abcd".getBytes());
//4. 释放资源
client.close();
}
//3) 删除值
@Test
public void delDataNode() throws Exception {
//1. 创建 curator 核心对象 : CuratorFramework
ExponentialBackoffRetry retry = new ExponentialBackoffRetry(1000,3);
CuratorFramework client = CuratorFrameworkFactory.newClient("192.168.72.141:2181,192.168.72.142:2181,192.168.72.143:2181", retry);
//2. 通过 CuratorFramework 获取连接
client.start();
//3. 修改数据 :
client.delete().forPath("/test02");
//4. 释放资源
client.close();
}
// 4) watcher机制演示
@Test
public void watcherDemo() throws Exception {
//1. 创建 curator 核心对象 : CuratorFramework
ExponentialBackoffRetry retry = new ExponentialBackoffRetry(1000,3);
CuratorFramework client = CuratorFrameworkFactory.newClient("192.168.72.141:2181,192.168.72.142:2181,192.168.72.143:2181", retry);
//2. 通过 CuratorFramework 获取连接
client.start();
//3) 绑定监听(watcher) : TreeCache
TreeCache treeCache = new TreeCache(client,"/test02");
treeCache.getListenable().addListener(new TreeCacheListener() {
// 匿名内部类: 本质上就是一个子类对象
// 回调函数
// 参数1: CuratorFramework 客户端 参数2: TreeCacheEvent 事件对象
@Override
public void childEvent(CuratorFramework client, TreeCacheEvent treeCacheEvent) throws Exception {
ChildData data = treeCacheEvent.getData();
TreeCacheEvent.Type type = treeCacheEvent.getType();
switch (type) {
case NODE_ADDED:
// 业务逻辑代码
System.out.println("节点被创建了..."+new String(data.getData()));
break;
case NODE_UPDATED:
System.out.println("节点被修改了..."+new String(data.getData()));
break;
case NODE_REMOVED:
System.out.println("节点被移除了...."+new String(data.getData()));
break;
default:
System.out.println("......22222" + type);
break;
}
}
});
// 4) 启动监听
treeCache.start();
//System.in.read();// 等待键盘输入
Thread.sleep(1000000000);
}
}