微服务应用-基于SpringCloud和Reactor构建网上商店微服务(下)

HBase1.2.2伪分布式安装(HDFS)+ZooKeeper-3.4.8安装配置+HBase表和数据操作+HBase的架构体系+单例安装,记录了在Ubuntu下对HBase1.2.2的实践操作,HBase的安装到数据库表的操作.包含内容1.HBase单例安装2.HBase伪分布式安装(基于Hadoop的HDFS)过程,3.HBase的shell编程,对HBase表的创建,删除等的命令,HBase对数据的增删查等操作.4.简单概述了Hbase的架构体系.5.zookeeper的单例安装和常用操作.

1.HBase单例安装

1.1下载

1.2.解压并放置特定路径如 /opt

wxl@wxl-pc:~/Downloads$ sudo mv hbase /opt/

1.3.设置JAVA_HOME 环境变量

前言

上篇主要是讲解理论知识和项目架构要点,这篇将集中在微服务中使用Spring Boot、Spring Cloud和Project Reactor实现事件溯源的原始主题。文章中也会介绍项目实现一些技术细节,项目Git下载地址:https://github.com/kbastani/spring-cloud-event-sourcing-example,项目我自己已经运行了一遍,非常适合学习使用。下面是原文翻译内容:

Project Reactor

Project Reactor 是一个开源基于JVM实现Reactive流规范的开发框架,是Spring生态系统一个成员,在微服务中,经常在一个上下文下需要和其他微服务交互操作,由于微服务架构天然属性是最终一致性,而最终一致性并不保证数据的安全性。它提供我们一个使用异步非堵塞方式进行通讯的方式,这里正是使用Reactor目的所在。

很少情况下,领域模型状态会被跨微服务共享,但是如果在微服务之间需要共享状态怎么办?或者说多个微服务需要访问同一个数据库数据表怎么办?在微服务中ES只保存有序事件的日志,使用事件流取代领域模型在数据库中存储,我们可以存储有序事件流来代表对象的状态,这样,意味著我们就不再使用基于HTTP的RESTful进行微服务之间同步通讯,这些同步会造成堵塞和性能延迟。

Reactor为核心的事件溯源

在网上商店的微服务之一是购物车服务(Shopping Cart Service),已验证的用户从商店Web应用程序的用户界面浏览产品目录。用户可以添加和删除他们的购物车的商品条目,以及清除他们的购物车或结帐。

 

 

一个用户的购物车为如何实现事件追溯工作描绘了一个简单的样例。我们以网上商店中购物车服务为案例,展示Reactor + ES是如何实现的:

购物车服务Shopping Cart Service是一个MYSQL数据库拥有者,有一个数据表称为cart_event。这个表包含用户操作动作产生的有序事件日志,用户操作就是反复将商品加入购物车或去除等各种购物车管理操作。

Example 1. CartEventType.java

// These will be the events that are stored in the event log for a cart

public enum CartEventType {

ADD_ITEM,

REMOVE_ITEM,

CLEAR_CART,

CHECKOUT

}

CartEventType是枚举类型,已经列出了4种不同的事件类型。这些事件类型中的每一个都代表用户在购物车上执行的动作。根据ES,这些购物车事件可以影响用户的购物车的最终状态结果。当用户添加或删除一个商品条码到他们的购物车时,一个动作产生一个事件,会对购物车中进行递增或递减一行条目。当这些事件使用同样顺序进行回放时,同样一系列的条目会被重新创建或删除:

id created_at last_modified cart_event_type product_id quantity user_id

1 1460990971645 1460990971645 0 SKU-12464 2 0

2 1460992816398 1460992816398 1 SKU-12464 1 0

3 1460992826474 1460992826474 0 SKU-12464 2 0

4 1460992832872 1460992832872 0 SKU-12464 2 0

5 1460992836027 1460992836027 1 SKU-12464 5 0

我们看到每行都有一个唯一时间戳来确保严格顺序,使用整数来代表4个购物车事件类型,product_id 和数据quantity都是每次加入购物车的商品条码信息。

 

 

这一结果显示在上面的截图,在这里,我们看到一个用户的购物车,生成作为一个总结果集的对象。

选择事件存储库

当选择事件追溯的适当存储选项时,有很多可用的选项。今天几乎所有的数据库都能提供数据流查询功能的工作,然而,有一些流行的开源项目,在这方面有着突出的优点。现在Event Sourcing标准的存储库是 Apache Kafka,微服务之间共享状态是通过共享Kafka的事件日志实现的,这是一个未来博客的主题。在这个例子中我们将使用MySQL,这是实现事件追溯一个在线购物车的不错选择。

您的事件存储技术的选择将永远取决于写入的数量和您的数据库的吞吐量。像Apache Kafka设计了精确的使用情况,却要求我们承担一些额外的工作责任去在生产中扩展,包括运行Apache ZooKeeper集群。

生成聚合

下面我们回到购物车,购物车微服务提供一个REST API方法接受来自Web端的事件。Web端发出事件的控制器 ShoppingCartControllerV1.java

Example 2. ShoppingCartControllerV1.java

@RequestMapping(path = “/events”, method = RequestMethod.POST)

public ResponseEntity addCartEvent(@RequestBody CartEvent cartEvent) throws Exception {

return Optional.ofNullable(shoppingCartService.addCartEvent(cartEvent))

.map(event -> new ResponseEntity(HttpStatus.NO_CONTENT))

.orElseThrow(() -> new Exception(“Could not find shopping cart”));

}

在上面的代码示例,我们定义了一个用于收集来自客户端新的CartEvent对象的控制器方法。这种方法的目的是在向事件日志追加事件。当客户端调用REST API检索用户的购物车,它将产生一个购物车聚合,使用Reactive流合并了所有购物车事件流。

下面在ShoppingCartServiceV1.java中使用Reactor产生购物车事件流:

Example 3. ShoppingCartServiceV1.java

public ShoppingCart aggregateCartEvents(User user, Catalog catalog) throws Exception {

// Create a reactive streams publisher by streaming ordered events from the database

Flux cartEvents =

Flux.fromStream(cartEventRepository.getCartEventStreamByUser(user.getId()));

// Aggregate the current state of the shopping cart until arriving at a terminal state in the stream

ShoppingCart shoppingCart = cartEvents

.takeWhile(cartEvent -> !ShoppingCart.isTerminal(cartEvent.getCartEventType()))

.reduceWith(() -> new ShoppingCart(catalog), ShoppingCart::incorporate)

.get();

// Generate the list of line items in the cart from the aggregate

shoppingCart.getLineItems();

return shoppingCart;

}

在上面的代码示例中,我们可以看到三个步骤来生成购物车对象,然后返回到客户端。第一步是从事件存储的数据源中创建一个Reactive流。一旦流建立,我们可以从事件流中产生我们的聚合。这些事件流不断改变购物车状态直至到最终状态,然后就可以将最终购物返回给用户客户端。

为了减少reactive流的聚合,我们使用了一个称为incorporate方法,这个方法是接受CartEvent对象,而CartEvent对象是用来改变购物车状态的。

Example 4. ShoppingCart.java

public ShoppingCart incorporate(CartEvent cartEvent) {

// Remember that thing about safety properties in microservices?

Flux validCartEventTypes =

Flux.fromStream(Stream.of(CartEventType.ADD_ITEM,

CartEventType.REMOVE_ITEM));

// The CartEvent’s type must be either ADD_ITEM or REMOVE_ITEM

if (validCartEventTypes.exists(cartEventType ->

cartEvent.getCartEventType().equals(cartEventType)).get()) {

// Update the aggregate view of each line item’s quantity from the event type

productMap.put(cartEvent.getProductId(),

productMap.getOrDefault(cartEvent.getProductId(), 0) +

(cartEvent.getQuantity() * (cartEvent.getCartEventType()

.equals(CartEventType.ADD_ITEM) ? 1 : -1)));

}

// Return the updated state of the aggregate to the reactive stream’s reduce method

return this;

}

在上面代码中我们看到ShoppingCart的incorporate方法实现,我们接受一个CartEvent对象然后做最重要的一件事:确保事件类型是正确的。这是在微服务需要自由与他们的单元测试,在最终一致的架构,以确保状态突变将确保数据的正确性。在本例中,我们确保事件类型是 ADD_ITEM 或 REMOVE_ITEM。

下一步是更新购物车中每个条目的聚合视图,通过映射相应的事件类型到商品条目的数量递增或递减。最后我们返回这样一个带有最终可变状态的购物车给客户端。

Docker Compose演示

示例项目使用Docker Compose构建和运行,每个微服务的容器镜像都作为Maven编译过程的一部分。

入门

首先,访问该示例项目的GitHub库:

https://github.com/kbastani/spring-cloud-event-sourcing-example

克隆或复制项目并将存储库下载到您的机器上。下载后,您将需要使用Maven和Docker来编译和构建本地镜像。

下载Docker

首先,如果你还没有下载Docker。可遵循这里的指示https://www.docker.com/docker-toolbox,把Docker toolbox在你的开发机器上运行。

在你安装了Docker toolbox以后,运行下面的命令来初始化这个示例应用程序的一个新的VirtualBox虚拟机。

$ docker-machine create env event-source-demo –driver virtualbox –virtualbox-memory “11000” –virtualbox-disk-size “100000”

$ eval “$(docker-machine env event-source-demo)”

环境要求

能够运行实例程序,需要在你的开发机上安装下面的软件:

Maven 3Java 8DockerDocker Compose

构建项目

通过命令行方式来构建当前项目,在项目的根目录中运行如下的命令:

$ sh run.sh

该项目将下载所有所需的依赖关系,并编译每一个项目的组件。每个服务都将被构建,然后一个Maven Docker插件会自动构建每个镜像到你的本地Docker注册表里。在根目录运行命令之前,一定要保证Docker正常运行,只有这样,你的sh run.sh命令才会构建成功。

Docker Compose启动集群

现在,每个镜像都已经搭建成功,我们可以使用Docker Compose快速启动集群。run.sh脚本将建立每个项目和Docker容器,并使用Docker Compose开启每个服务。值得注意的是,集群需要首先启动的服务是配置服务和发现服务。其余的服务在开始启动,并最终开始相互沟通。

我强烈建议你运行此示例的机器上至少16GB的系统内存。

一旦启动序列完成后,你可以浏览到Eureka主机和看到发现服务里注册的所有服务。复制并粘贴以下命令到终端,Docker可以使用$DOCKER_HOST环境变量进行访问。

$ open $(echo \”$(echo $DOCKER_HOST)\”|

\sed ‘s/tcp:\/\//http:\/\//g’|

\sed ‘s/[0-9]\{4,\}/8761/g’|

\sed ‘s/\”//g’)

如果Eureka正确的启动,浏览器将会启动并打开Eureka服务的仪表盘,如下图所示:

 

 

当所有的应用程序在Eureka上已经完成启动和注册,你可以使用以下命令访问网上商店的Web应用。

$ open $(echo \”$(echo $DOCKER_HOST)\”|

\sed ‘s/tcp:\/\//http:\/\//g’|

\sed ‘s/[0-9]\{4,\}/8787/g’|

\sed ‘s/\”//g’)

应用程序启动可能需要一些时间,所以请确保你每隔几分钟刷新用户界面,直到看见产品目录。

 

 

要开始向购物车添加产品,您需要登录默认用户。单击Login按钮,你将被重定向到身份验证网关页面,在此页面你可以使用用户的默认凭据和密码进行登录。

 

 

登录成功后,你将被重定向到需要身份验证才能呈现的主页面上,并可以开始管理你的购物车中的项目。

 

 

总结

在这篇文章中,我们很难看到在微服务架构中的高可用性和数据一致性的挑战。我们期待一个完整的网上商店原生云应用程序,能作为一系列微服务的集合,使用事件追溯保持一致的世界观,同时还保证高可用性。

在接下来的博客,我将继续探索如何在事件追溯中使用Spring Cloud Stream和用Apache Kafka对事件流处理。

特别感谢

省略。

(注意,如果本机已经设置好JAVA_HOME系统变量则此不步骤不是必须的)进入到hbase路径下

/opt/hbase

wxl@wxl-pc:/opt/hbase$ vim conf/hbase-env.sh

#增加JAVA_HOME路径,根据自己jdk安装位稍有不同

export JAVA_HOME=/opt/java/

1.4.编辑conf/hbase-site.xml

HBase默认存储在/tmp路径下,可是每次机器重启,/tmp下的数据会被清除,所以首席那应该更改存储路径,如存在/home/wxl 路径下,并且会创建新的hbase文件夹(如果没有安装zookeeper,没关系,不影响在开发和测试环境下的HBase使用)

wxl@wxl-pc:/opt/hbase$ vim conf/hbase-site.xml

hbase.rootdir

file:///home/wxl/hbase

hbase.zookeeper.property.dataDir

/home/wxl/zookeeper

 

 

1.5.启动HBase

wxl@wxl-pc:/opt/hbase$ bin/start-hbase.sh

 

 

2.HBase的shell命令操作

2.1连接HBase shell

wxl@wxl-pc:/opt/hbase$ ./bin/hbase shell

 

 

可以通过输入help命令,来大致了解可以输入命令和Hbase存储的数据结构

2.2.创建表

必须输入表名和列族名(ColumnFamily name)

hbase(main):002:0> create ‘test’,’cf’

 

 

2.3.查看表

hbase(main):003:0> list ‘test’

TABLE

test

1 row(s) in 0.0320 seconds

=> [“test”]

2.4.给表赋值

hbase(main):004:0> put ‘test’, ‘wangxiaolei’, ‘cf:a’, ‘wov@outlook.com’

0 row(s) in 0.2010 seconds

hbase(main):005:0> put ‘test’, ‘王小雷’,’cf:b;’,’bio get it done’

0 row(s) in 0.0120 seconds

hbase(main):006:0> put ‘test’, ‘row3’, ‘cf:c’, ‘value3’

0 row(s) in 0.0240 seconds

 

 

2.5.对列表计数

使用scan关键字

 

 

2.6.查询列表中某行

如查询第二行,输入

hbase(main):009:0> get ‘test’,’王小雷’

 

 

2.7.更改表(删除,修改表)

在更改表之前需要将表的状态更改为disable,在更改完之后可以enable

hbase(main):009:0> disable ‘test’

0 row(s) in 2.5870 seconds

hbase(main):010:0> enable ‘test’

0 row(s) in 1.2680 seconds

hbase(main):011:0> disable ‘test’

0 row(s) in 2.2370 seconds

在test表为 disable 状态下,删除test表

hbase(main):012:0> drop ‘test’

0 row(s) in 1.2590 seconds

2.8.退出shell并停止HBase

在shell中使用quit命令(或者exit),可以退出hbase shell,但是hbase仍在运行

输入jps可以查看HMaseter守护程序还在

 

 

使用stop-hbase.sh退出hbase

wxl@wxl-pc:/opt/hbase$ ./bin/stop-hbase.sh

stopping hbase…….

 

vcHBpbmc=” height=”84″ src=”http://www.2cto.com/uploadfile/Collfiles/20160804/20160804091738445.png” width=”457″ />

 

3.HBase伪分布式安装

如果没有安装Hadoop请安装伪分布式的Hadoop教程如下Ubuntu16.04安装Hadoop2.6+Spark1.6+开发实例

首先停止2HBase(2.8.退出shell并停止HBase)

3.1.配置伪分布式的hbase-site.xml文件

设置distributed为true,是为了让jvm模拟集群,再者是修改数据保存路径,放置到HDFS上,配置rootdir,其中hdfs://localhost:9000根据自己hadoop配置指定(也可能是hdfs://localhost:8020/hbase)(但是可以不配至,HBase会自动寻找HDFS路径)

hbase.cluster.distributed

true

hbase.rootdir

hdfs://localhost:9000/hbase

3.2.启动HBase

wxl@wxl-pc:/opt/hbase$ ./bin/start-hbase.sh

3.3.在HDFS上查看HBase文件

wxl@wxl-pc:/opt/hbase$ hadoop fs -ls /hbase

 

 

3.4.HBase上的数据操作,创建表,赋值,删除表等见步骤1.2-1.5

4.HBase的HRegionServer和HMaster及架构体系图

4.1此时使用jps(我开启来hadoop,spark,hbase)

可见,HBase的HRegionServer和HMaster已经开启.

wxl@wxl-pc:/opt/hbase$ jps

18065 Master

17795 NodeManager

19379 HRegionServer

17331 DataNode

17669 ResourceManager

17511 SecondaryNameNode

19255 HMaster

19991 Jps

17177 NameNode

19181 HQuorumPeer

18206 Worker

18607 SparkSubmit

 

 

4.2.关于HBase的HRegionServer和HMaster是什么,什么样的体系结构,如下图.

 

 

5.1 ZooKeeper-3.4.8安装+常用操作实践

版本ZooKeeper-3.4.8 系统Ubuntu16.04

5.1.创建conf/zoo.cfg

wxl@wxl-pc:/opt/zookeeper$ cp conf/zoo_sample.cfg conf/zoo.cfg

查看zookeeper配置信息

(注意此处为了测试所以dataDir=/tmp/zookeeper,这里每次重启计算机数据就会丢失,如果保留可以放入其他路径,如/home/wxl/zookeeper)

tickTime=2000

initLimit=10

syncLimit=5

dataDir=/tmp/zookeeper

clientPort=2181

其中,

– tickTime

– tickTime是ZooKeeper的毫秒级计量单位,表示正常的会话时间,如果超过设置值的两倍就会连接超时.

– dataDir

– 设置HBase的路径用于保存内存数据快照和更新数据库事务的日志.

– clientPort

– 设置监听连接客户端的接口

5.2. 执行zookeeper

开启zookeeper

wxl@wxl-pc:/opt/zookeeper$ bin/zkServer.sh start

 

 

连接zookeeper

wxl@wxl-pc:/opt/zookeeper$ bin/zkCli.sh -server 127.0.0.1:2181

 

 

5.3. zookeeper基本命令

[zk: 127.0.0.1:2181(CONNECTED) 0] help

ZooKeeper -server host:port cmd args

stat path [watch]

set path data [version]

ls path [watch]

delquota [-n|-b] path

ls2 path [watch]

setAcl path acl

setquota -n|-b val path

history

redo cmdno

printwatches on|off

delete path [version]

sync path

listquota path

rmr path

get path [watch]

create [-s] [-e] path data acl

addauth scheme auth

quit

getAcl path

close

connect host:port

5.3.1. ls查看路径下有那些文件(在zoo.cfg设置的的参数datadir)

查看

#如果没安装HBase此处只显示zookeeper

[zk: 127.0.0.1:2181(CONNECTED) 1] ls /

 

 

5.3.2.HBase创建Znode为zk_test_wangxiaolei

[zk: 127.0.0.1:2181(CONNECTED) 2] create /zk_test_wangxiaolei my_data

 

 

5.3.3.验证(查看)zk_test_wangxiaolei节点下数据

[zk: 127.0.0.1:2181(CONNECTED) 3] get /zk_test_wangxiaolei

my_data

cZxid = 0x66

ctime = Mon Aug 01 22:06:36 CST 2016

mZxid = 0x66

mtime = Mon Aug 01 22:06:36 CST 2016

pZxid = 0x66

cversion = 0

dataVersion = 0

aclVersion = 0

ephemeralOwner = 0x0

dataLength = 7

numChildren = 0

 

 

5.3.4.set命令来改变某(如zk_test_wangxiaolei)节点下的数据

[zk: 127.0.0.1:2181(CONNECTED) 4] set /zk_test_wangxiaolei junk

cZxid = 0x66

ctime = Mon Aug 01 22:06:36 CST 2016

mZxid = 0x69

mtime = Mon Aug 01 22:29:46 CST 2016

pZxid = 0x66

cversion = 0

dataVersion = 1

aclVersion = 0

ephemeralOwner = 0x0

dataLength = 4

numChildren = 0

 

 

再次get节点zk_test_wangxiaolei可以看到数据已经改变

5.3.5.最后删除测试节点

[zk: 127.0.0.1:2181(CONNECTED) 5] delete /zk_test_wangxiaolei

[zk: 127.0.0.1:2181(CONNECTED) 6] ls /

[zookeeper, hbase]

[zk: 127.0.0.1:2181(CONNECTED) 7]

Leave A Comment