diff --git a/README.md b/README.md
index f06de08..48a8ed0 100644
--- a/README.md
+++ b/README.md
@@ -99,7 +99,7 @@ TODO
## 九、HBase
-1. Hbase 简介
+1. [Hbase 简介](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Hbase简介.md)
2. [HBase系统架构及数据结构](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Hbase%E7%B3%BB%E7%BB%9F%E6%9E%B6%E6%9E%84%E5%8F%8A%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84.md)
3. [HBase基本环境搭建(Standalone /pseudo-distributed mode)](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Hbase%E5%9F%BA%E6%9C%AC%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA.md)
4. [HBase常用Shell命令](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Hbase%20Shell.md)
diff --git a/notes/Hbase简介.md b/notes/Hbase简介.md
new file mode 100644
index 0000000..6c35f93
--- /dev/null
+++ b/notes/Hbase简介.md
@@ -0,0 +1,70 @@
+# Hbase简介
+
+
+## 一、Hadoop的局限
+
+HBase是一个构建在Hadoop文件系统之上的面向列的数据库管理系统。既然有了Hadoop为什么还需要HBase ? 这里首先介绍一下Hadoop的限制。
+
+
+
+ Hadoop擅长存储任意的、半结构甚至非结构化的数据,主要通过HDFS来存储,使用MapReduce来处理。但是Hadoop只能执行批处理,并且只能以顺序方式访问数据。这意味着即使是最简单的工作,也必须搜索整个数据集。面对日益复杂的业务需求,需要一个新的解决方案来实现对海量数据的随机访问。实现数据的随机访问是传统的RDBMS所擅长的,但其却不能存储海量的数据。在这种情况下,必须有一种新的方案来解决海量数据存储和随机访问并存的问题,HBase就是其中之一。
+
+> 注:HBase,Cassandra,couchDB,Dynamo和MongoDB都能存储海量数据并支持随机访问。
+
+
+
+## 二、HBase简介
+
+HBase是一个构建在Hadoop文件系统之上的面向列的数据库管理系统。
+
+HBase是一种类似于Google’s big table的数据模型,它是Hadoop生态系统的一部分,它将数据存储在HDFS上,客户端可以通过HBase实现对HDFS上数据的随机访问。它具有以下特性:
+
+- 线性和模块化的可扩展性;
+- 提供一致的读写操作;
+- 支持数据分片;
+- 支持RegionServers之间的自动故障转移;
+- 易于使用的Java 客户端 API;
+- 支持BlockCache和布隆过滤器;
+- 过滤器支持谓词下推。
+
+
+
+## 三、HBase Table
+
+HBase是一个面向列的数据库管理系统,这里更为确切的而说,HBase是一个面向列族的数据库管理系统。表 schema 仅定义列族,表具有多个列族,每个列族可以包含任意数量的列,列由多个单元格(cell )组成,单元格可以存储多个版本的数据,多个版本数据以时间戳进行区分。
+
+下图为Hbase中一张表的:
+
++ RowKey为行的唯一标识,所有行按照RowKey的字典序进行排序;
++ 该表具有两个列族,分别是personal和office;
++ 其中列族personal拥有name、city、phone三个列,office拥有tel、addres两个列。
+
+
+
+> 图片引用自博客:HBase 是列式存储数据库吗(https://www.iteblog.com/archives/2498.html)
+
+
+
+## 四、Phoenix
+
+Phoenix是HBase的开源SQL中间层。使得您可以使用标准JDBC API而不是常规HBase客户端API来操作HBase上的数据。
+
+简单来说,如果你要直接使用HBase,你就只能通过它的Java API来进行调用,虽然官网介绍它的API是简单易用的,但相比于使用一行SQL就能实现数据的查询过滤,原生的API还是过于复杂,Phoenix 的理念是`we put sql SQL back in NOSQL`,即你可以使用标准的SQL就能完成对HBase中数据的操作。
+
+Phoenix完全使用Java编写,作为HBase内嵌的JDBC驱动。Phoenix查询引擎会将SQL查询转换为一个或多个HBase scan,并编排并行执行以生成标准的JDBC结果集,同时Phoenix还拥有二级索引等Hbase不具备的特性,这使得Phoenix具有接近原生HBase API的性能表现。
+
+
+
+
+
+## 参考资料
+
+1. [HBase - Overview](https://www.tutorialspoint.com/hbase/hbase_overview.htm)
+
+
+
diff --git a/notes/Hbase系统架构及数据结构.md b/notes/Hbase系统架构及数据结构.md
index c82ee66..b20a8c5 100644
--- a/notes/Hbase系统架构及数据结构.md
+++ b/notes/Hbase系统架构及数据结构.md
@@ -35,7 +35,7 @@ Row Key是用来检索记录的主键。访问HBase Table中的行,只有三
+ 全表扫描
-Row Key (行键)可以是任意字符串(最大长度是 64KB,实际应用中长度一般为 10-100bytes),在HBase内部,Row Key保存为字节数组。存储时,数据按照Row Key的字典序(byte order)排序存储。设计key时,要充分排序存储这个特性,将经常一起读取的行存储放到一起(位置相关性)。
+Row Key (行键)可以是任意字符串(最大长度是 64KB,实际应用中长度一般为 10-100bytes),在HBase内部,Row Key保存为字节数组。存储时,数据按照Row Key的字典序(byte order)排序存储。
需要注意以下两点:
diff --git a/notes/Storm核心概念详解.md b/notes/Storm核心概念详解.md
index 772d8af..051d583 100644
--- a/notes/Storm核心概念详解.md
+++ b/notes/Storm核心概念详解.md
@@ -1,4 +1,4 @@
-# Storm 核心概念核心概念详解
+# Storm 核心概念详解
-
## 一、Storm核心概念
+下图为Storm为运行流程图:
+
### 1.1 Topologies(拓扑)
diff --git a/notes/storm编程模型.md b/notes/storm编程模型.md
new file mode 100644
index 0000000..21eca93
--- /dev/null
+++ b/notes/storm编程模型.md
@@ -0,0 +1,200 @@
+# Storm 编程模型
+
+## 一、简介
+
+下图为Strom的运行流程图,也是storm的编程模型图,在storm 进行流处理时,我们需要自定义实现自己的spout(数据源)和bolt(处理单元),并通过`TopologyBuilder`将它们之间进行关联,定义好数据处理的流程。
+
+下面小结分别介绍如何按照storm内置接口分别实现spout和bolt,然后将其进行关联,最后将其提交到本地和服务器进行运行。
+
+
+
+## 二、IComponent
+
+`IComponent`接口定义了Topology中所有组件(spout/bolt)的公共方法,我们实现spout或bolt都必须直接或者间接实现这个接口。
+
+```java
+public interface IComponent extends Serializable {
+
+ /**
+ * 声明此拓扑的所有流的输出模式。
+ * @param declarer这用于声明输出流id,输出字段以及每个输出流是否是直接流(direct stream)
+ */
+ void declareOutputFields(OutputFieldsDeclarer declarer);
+
+ /**
+ * 声明此组件的配置。
+ *
+ */
+ Map getComponentConfiguration();
+
+}
+```
+
+## 三、spout
+
+### 3.1 ISpout接口
+
+实现自定义的spout需要实现`ISpout`,其定义了spout的所有可用方法:
+
+```java
+public interface ISpout extends Serializable {
+ /**
+ * 组件初始化时候被调用
+ *
+ * @param conf ISpout的配置
+ * @param context 应用上下文,可以通过其获取任务ID和组件ID,输入和输出信息等。
+ * @param collector 用来发送spout中的tuples,它是线程安全的,建议保存为此spout对象的实例变量
+ */
+ void open(Map conf, TopologyContext context, SpoutOutputCollector collector);
+
+ /**
+ * ISpout将要被关闭的时候调用。但是其不一定会被执行,如果在集群环境中通过kill -9 杀死进程时其就无法被执行。
+ */
+ void close();
+
+ /**
+ * 当ISpout从停用状态激活时被调用
+ */
+ void activate();
+
+ /**
+ * 当ISpout停用时候被调用
+ */
+ void deactivate();
+
+ /**
+ * 这是一个核心方法,主要通过在此方法中调用collector将tuples发送给下一个接收器,这个方法必须是非阻塞的。 * nextTuple/ack/fail/是在同一个线程中执行的,所以不用考虑线程安全方面。当没有tuples发出时应该
+ * 让nextTuple休眠(sleep)一下,以免浪费CPU。
+ */
+ void nextTuple();
+
+ /**
+ * 通过msgId进行tuples处理成功的确认,被确认后的tuples不会再次被发送
+ */
+ void ack(Object msgId);
+
+ /**
+ * 通过msgId进行tuples处理失败的确认,被确认后的tuples会再次被发送进行处理
+ */
+ void fail(Object msgId);
+}
+```
+
+### 3.2 BaseRichSpout抽象类
+
+**通常情况下,我们实现自定义的Spout时不会直接去实现`ISpout`接口,而是继承`BaseRichSpout`。**`BaseRichSpout`继承自`BaseCompont`,同时实现了`IRichSpout`接口。
+
+
+
+`IRichSpout`接口继承自`ISpout`和`IComponent`,自身并没有定义任何方法。
+
+```java
+public interface IRichSpout extends ISpout, IComponent {
+
+}
+```
+
+BaseComponent 抽象类也仅仅是空实现了`IComponent`的`getComponentConfiguration`方法。
+
+```java
+public abstract class BaseComponent implements IComponent {
+ @Override
+ public Map getComponentConfiguration() {
+ return null;
+ }
+}
+```
+
+`BaseRichSpout`通过继承自`BaseCompont`,同时实现了`IRichSpout`接口,并且空实现了其中部分方法。
+
+```java
+public abstract class BaseRichSpout extends BaseComponent implements IRichSpout {
+ @Override
+ public void close() {}
+
+ @Override
+ public void activate() {}
+
+ @Override
+ public void deactivate() {}
+
+ @Override
+ public void ack(Object msgId) {}
+
+ @Override
+ public void fail(Object msgId) {}
+}
+```
+
+通过这样的设计,我们在继承`BaseRichSpout`实现自己的spout时,就只需要实现三个必须的方法:
+
++ open : 来源于ISpout,可以通过此方法获取用来发送tuples的`SpoutOutputCollector`;
++ nextTuple :来源于ISpout,必须在此方法内部才能调用`SpoutOutputCollector`发送tuple;
++ declareOutputFields :来源于IComponent,通过此方法声明发送的tuple的名称,这样下一个组件才能知道如何接受数据。
+
+
+
+## 四、bolt
+
+通过上小结我们已经了解了storm如何对spout接口进行设计的,bolt接口的设计也是一样的。
+
+### 4.1 IBolt 接口
+
+```java
+ /**
+ * 在客户端计算机上创建的IBolt对象。会被被序列化到topology中(使用Java序列化),并提交给集群的主机(Nimbus)。
+ * Nimbus启动workers反序列化对象,调用prepare,然后开始处理tuples。
+ */
+
+public interface IBolt extends Serializable {
+ /**
+ * 组件初始化时候被调用
+ *
+ * @param conf storm中定义的此bolt的配置
+ * @param context 应用上下文,可以通过其获取任务ID和组件ID,输入和输出信息等。
+ * @param collector 用来发送spout中的tuples,它是线程安全的,建议保存为此spout对象的实例变量
+ */
+ void prepare(Map stormConf, TopologyContext context, OutputCollector collector);
+
+ /**
+ * 处理单个tuple输入。
+ *
+ * @param Tuple对象包含关于它的元数据(如来自哪个组件/流/任务)
+ */
+ void execute(Tuple input);
+
+ /**
+ * IBolt将要被关闭的时候调用。但是其不一定会被执行,如果在集群环境中通过kill -9 杀死进程时其就无法被执行。
+ */
+ void cleanup();
+```
+
+
+
+### 4.2 BaseRichBolt抽象类
+
+同样的,在实现我们自己的bolt时,我们也通常是继承`BaseRichBolt`抽象类来实现。`BaseRichBolt`继承自`BaseComponent`抽象类,并实现了`IRichBolt`接口。
+
+
+
+`IRichBolt`接口继承自`IBolt`和`IComponent`,自身并没有定义任何方法。
+
+```
+public interface IRichBolt extends IBolt, IComponent {
+
+}
+```
+
+通过这样的设计,我们在继承`BaseRichBolt`实现自己的bolt时,就只需要实现三个必须的方法:
+
+- prepare: 来源于IBolt,可以通过此方法获取用来发送tuples的`SpoutOutputCollector`;
+- execute:来源于IBolt,处理tuple和发送处理完成的tuple;
+- declareOutputFields :来源于IComponent,通过此方法声明发送的tuple的名称,这样下一个组件才能知道如何接受数据。
+
+
+
+## 五、使用案例
+
+
+
+## 六、提交到服务器运行
\ No newline at end of file
diff --git a/pictures/HBase_table-iteblog.png b/pictures/HBase_table-iteblog.png
new file mode 100644
index 0000000..b28bcbe
Binary files /dev/null and b/pictures/HBase_table-iteblog.png differ
diff --git a/pictures/storm-baseRichSpout.png b/pictures/storm-baseRichSpout.png
new file mode 100644
index 0000000..e837d34
Binary files /dev/null and b/pictures/storm-baseRichSpout.png differ
diff --git a/pictures/storm-baseRichbolt.png b/pictures/storm-baseRichbolt.png
new file mode 100644
index 0000000..ea6f117
Binary files /dev/null and b/pictures/storm-baseRichbolt.png differ