HBase详解(05) - HBase优化 整合Phoenix 集成Hive

HBase优化

预分区

每一个region维护着startRow与endRowKey,如果加入的数据符合某个region维护的rowKey范围,则该数据交给这个region维护。那么依照这个原则,可以将数据所要投放的分区提前大致的规划好,以提高HBase性能。

1.手动设定预分区

hbase> create 'staff1','info',SPLITS => ['1000','2000','3000','4000']

2.生成16进制序列预分区

create 'staff2','info',{NUMREGIONS => 15, SPLITALGO => 'HexStringSplit'}

3.按照文件中设置的规则预分区

创建splits.txt文件内容如下:

aaaa

bbbb

cccc

dddd

然后执行:

create 'staff3','info',SPLITS_FILE => 'splits.txt'

4.使用JavaAPI创建预分区

//自定义算法,产生一系列Hash散列值存储在二维数组中

byte[][] splitKeys = 某个散列值函数

//创建HbaseAdmin实例

HBaseAdmin hAdmin = new HBaseAdmin(HbaseConfiguration.create());

//创建HTableDescriptor实例

HTableDescriptor tableDesc = new HTableDescriptor(tableName);

//通过HTableDescriptor实例和散列值二维数组创建带有预分区的Hbase表

hAdmin.createTable(tableDesc, splitKeys);

RowKey设计

一条数据的唯一标识就是rowkey,那么这条数据存储于哪个分区,取决于rowkey处于哪个一个预分区的区间内,设计rowkey的主要目的 ,就是让数据均匀的分布于所有的region中,在一定程度上防止数据倾斜。rowkey常用的设计方案:

  1. 生成随机数、hash、散列值

一条数据的唯一标识就是rowkey,那么这条数据存储于哪个分区,取决于rowkey处于哪个一个预分区的区间内,设计rowkey的主要目的 ,就是让数据均匀的分布于所有的region中,在一定程度上防止数据倾斜。rowkey常用的设计方案:

比如:

原本rowKey为1001的,SHA1后变成:dd01903921ea24941c26a48f2cec24e0bb0e8cc7

原本rowKey为3001的,SHA1后变成:49042c54de64a1e9bf0b33e00245660ef92dc7bd

原本rowKey为5001的,SHA1后变成:7b61dec07e02c188790670af43e717f0f46e8913

在做此操作之前,一般会选择从数据集中抽取样本,来决定什么样的rowKey来Hash后作为每个分区的临界值。

2.字符串反转

20170524000001转成10000042507102

20170524000002转成20000042507102

这样也可以在一定程度上散列逐步put进来的数据。

3.字符串拼接

20170524000001_a12e

20170524000001_93i7

内存优化

HBase操作过程中需要大量的内存开销,毕竟Table是可以缓存在内存中的,但是不建议分配非常大的堆内存,因为GC过程持续太久会导致RegionServer处于长期不可用状态,一般16~36G内存就可以了,如果因为框架占用内存过高导致系统内存不足,框架一样会被系统服务拖死。

基础优化

1.Zookeeper会话超时时间

hbase-site.xml

属性:zookeeper.session.timeout

解释:默认值为90000毫秒(90s)。当某个RegionServer挂掉,90s之后Master才能察觉到。可适当减小此值,以加快Master响应,可调整至60000毫秒。

2.设置RPC监听数量

hbase-site.xml

属性:hbase.regionserver.handler.count

解释:默认值为30,用于指定RPC监听的数量,可以根据客户端的请求数进行调整,读写请求较多时,增加此值。

3.手动控制Major Compaction

hbase-site.xml

属性:hbase.hregion.majorcompaction

解释:默认值:604800000秒(7天), Major Compaction的周期,若关闭自动Major Compaction,可将其设为0

4.优化HStore文件大小

hbase-site.xml

属性:hbase.hregion.max.filesize

解释:默认值10737418240(10GB),如果需要运行HBase的MR任务,可以减小此值,因为一个region对应一个map任务,如果单个region过大,会导致map任务执行时间过长。该值的意思就是,如果HFile的大小达到这个数值,则这个region会被切分为两个Hfile。

5.优化HBase客户端缓存

hbase-site.xml

属性:hbase.client.write.buffer

解释:默认值2097152bytes(2M)用于指定HBase客户端缓存,增大该值可以减少RPC调用次数,但是会消耗更多内存,反之则反之。一般我们需要设定一定的缓存大小,以达到减少RPC次数的目的。

6.指定scan.next扫描HBase所获取的行数

hbase-site.xml

属性:hbase.client.scanner.caching

解释:用于指定scan.next方法获取的默认行数,值越大,消耗内存越大。

7.BlockCache占用RegionServer堆内存的比例

hbase-site.xml

属性:hfile.block.cache.size

解释:默认0.4,读请求比较多的情况下,可适当调大

8.MemStore占用RegionServer堆内存的比例

hbase-site.xml

属性:hbase.regionserver.global.memstore.size

解释:默认0.4,写请求较多的情况下,可适当调大

HBase整合Phoenix

Phoenix简介

Phoenix定义:Phoenix是HBase的开源SQL皮肤。可以使用标准JDBC API代替HBase客户端API来创建表,插入数据和查询HBase数据。

Phoenix特点

1)容易集成:如Spark,Hive,Pig,Flume和Map Reduce;

2)操作简单:DML命令以及通过DDL命令创建和操作表和版本化增量更改;

3)支持HBase二级索引创建。

Phoenix架构

Phoenix 安装

1.下载

官网地址:http://phoenix.apache.org/

下载地址:https://downloads.apache.org/phoenix/

5.0.0版本下载地址:https://downloads.apache.org/phoenix/apache-phoenix-5.0.0-HBase-2.0/bin/apache-phoenix-5.0.0-HBase-2.0-bin.tar.gz

2.Phoenix部署

1)上传并解压tar包

[hadoop@hadoop102 software]$ tar -zxvf apache-phoenix-5.0.0-HBase-2.0-bin.tar.gz -C /opt/module/

重命名

[hadoop@hadoop102 software]$ cd /opt/module/

[hadoop@hadoop102 module]$ mv apache-phoenix-5.0.0-HBase-2.0-bin/ phoenix

2)复制server包并拷贝到各个HBase节点的hbase/lib

[hadoop@hadoop102 phoenix]$ cp /opt/module/phoenix/phoenix-5.0.0-HBase-2.0-server.jar /opt/module/hbase/lib/

[hadoop@hadoop102 phoenix]$ scp /opt/module/phoenix/phoenix-5.0.0-HBase-2.0-server.jar hadoop103:/opt/module/hbase/lib/

[hadoop@hadoop102 phoenix]$ scp /opt/module/phoenix/phoenix-5.0.0-HBase-2.0-server.jar hadoop104:/opt/module/hbase/lib/

4)配置环境变量(可选)

#phoenix

export PHOENIX_HOME=/opt/module/phoenix

export PHOENIX_CLASSPATH=$PHOENIX_HOME

export PATH=$PATH:$PHOENIX_HOME/bin

5)重启Hbase

[hadoop@hadoop102 ~]$ stop-hbase.sh

[hadoop@hadoop102 ~]$ start-hbase.sh

6) 连接Phoenix

[hadoop@hadoop102 ~]$ /opt/module/phoenix/bin/sqlline.py hadoop102,hadoop103,hadoop104:2181

7) 退出Phoenix

!quit

Phoenix Shell操作

默认情况下,在phoenix中不能直接创建schema。需要将下面的参数添加到Hbase中conf目录下的hbase-site.xml和phoenix中bin目录下的 hbase-site.xml中

<property>

<name>phoenix.schema.isNamespaceMappingEnabled</name>

<value>true</value>

</property>

修改Hbase的的hbase-site.xml文件

[hadoop@hadoop102 ~]$ vi /opt/module/hbase/conf/hbase-site.xml

将修改后的文件同步到其他机器

[hadoop@hadoop102 conf]$ scp hbase-site.xml hadoop103:/opt/module/hbase/conf/

[hadoop@hadoop102 conf]$ scp hbase-site.xml hadoop104:/opt/module/hbase/conf/

修改phoenix的 hbase-site.xml文件

[hadoop@hadoop102 ~]$ vi /opt/module/phoenix/bin/hbase-site.xml

重新启动Hbase和连接phoenix客户端.

stop-hbase.sh

start-hbase.sh

/opt/module/phoenix/bin/sqlline.py hadoop102,hadoop103,hadoop104:2181

创建schema

create schema bigdata;

注意:在phoenix中,schema名,表名,字段名等会自动转换为大写,若要小写,使用双引号,如"student"。

1)显示所有表

!table 或 !tables

2)创建表

直接指定单个列作为RowKey

CREATE TABLE IF NOT EXISTS student(

id VARCHAR primary key,

name VARCHAR,

addr VARCHAR);

指定多个列的联合作为RowKey

CREATE TABLE IF NOT EXISTS us_population (

State CHAR(2) NOT NULL,

City VARCHAR NOT NULL,

Population BIGINT

CONSTRAINT my_pk PRIMARY KEY (state, city));

3)插入数据

upsert into student values('1001','zhangsan','beijing');

4)查询记录

select * from student;

select * from student where id='1001';

5)删除记录

delete from student where id='1001';

6)删除表

drop table student;

7)退出命令行

!quit

1)表的关系

默认情况下,直接在HBase中创建的表,通过Phoenix是查看不到的。如果要在Phoenix中操作直接在HBase中创建的表,则需要在Phoenix中进行表的映射。映射方式有两种:视图映射和表映射。

2)命令行中创建表test

HBase 中test的表结构如下,两个列族info1、info2。

Rowkey    info1    info2

id    name    address

启动HBase Shell

/opt/module/hbase/bin/hbase shell

创建HBase表test

hbase(main):001:0> create 'test','info1','info2'

3)视图映射

Phoenix创建的视图是只读的,所以只能用来做查询,无法通过视图对源数据进行修改等操作。在phoenix中创建关联test表的视图

0: jdbc:phoenix:hadoop101,hadoop102,hadoop103> create view "test"(id varchar primary key,"info1"."name" varchar, "info2"."address" varchar);

删除视图

0: jdbc:phoenix:hadoop101,hadoop102,hadoop103> drop view "test";

4)表映射

使用Apache Phoenix创建对HBase的表映射,有两种方法:

(1)HBase中不存在表时,可以直接使用create table指令创建需要的表,系统将会自动在Phoenix和HBase中创建person_infomation的表,并会根据指令内的参数对表结构进行初始化。

(2)当HBase中已经存在表时,可以以类似创建视图的方式创建关联表,只需要将create view改为create table即可。

0: jdbc:phoenix:hadoop101,hadoop102,hadoop103> create table "test"(id varchar primary key,"info1"."name" varchar, "info2"."address" varchar) column_encoded_bytes=0;

Hbase中存储数值类型的值(如int,long等)会按照正常数字的补码进行存储. 而phoenix对数字的存储做了特殊的处理. phoenix 为了解决遇到正负数同时存在时,导致负数排到了正数的后面(负数高位为1,正数高位为0,字典序0 < 1)的问题。 phoenix在存储数字时会对高位进行转换.原来为1,转换为0, 原来为0,转换为1.

因此,如果hbase表中的数据的写是由phoenix写入的,不会出现问题,因为对数字的编解码都是phoenix来负责。如果hbase表中的数据不是由phoenix写入的,数字的编码由hbase负责. 而phoenix读数据时要对数字进行解码。 因为编解码方式不一致。导致数字出错.

hbase(main):001:0> create 'person','info'

hbase(main):001:0> put 'person','1001', 'info:salary',Bytes.toBytes(123456)

注意: 如果要插入数字类型,需要通过Bytes.toBytes(123456)来实现。

2)在phoenix中创建映射表并查询数据

create table "person"(id varchar primary key,"info"."salary" integer ) column_encoded_bytes=0;

select * from "person";

在查询结果中会发现数字显示有问题

在phoenix中创建表时使用无符号的数值类型. unsigned_long

create table "person"(id varchar primary key,"info"."salary" unsigned_long ) column_encoded_bytes=0;

Phoenix JDBC操作

[hadoop@hadoop102 ~]$ cd /opt/module/phoenix/

[hadoop@hadoop102 phoenix]$ bin/queryserver.py start

2)创建新项目并导入依赖

<dependencies>

<dependency>

<groupId>org.apache.phoenix</groupId>

<artifactId>phoenix-queryserver-client</artifactId>

<version>5.0.0-HBase-2.0</version>

</dependency>

</dependencies>

package com.zhangjk.phoenix;

import java.sql.*;

import org.apache.phoenix.queryserver.client.ThinClientUtil;

public
class PhoenixTest {

public
static
void main(String[] args)
throws SQLException {

String connectionUrl = ThinClientUtil.getConnectionUrl("hadoop102",
8765);

Connection connection = DriverManager.getConnection(connectionUrl);

PreparedStatement preparedStatement = connection.prepareStatement("select * from student3");

ResultSet resultSet = preparedStatement.executeQuery();

while
(resultSet.next())
{

System.out.println(resultSet.getString(1)
+
"\t"
+ resultSet.getString(2));

}

//关闭

connection.close();

}

}

1)在pom中加入依赖

<dependencies>

<dependency>

<groupId>org.apache.phoenix</groupId>

<artifactId>phoenix-core</artifactId>

<version>5.0.0-HBase-2.0</version>

<exclusions>

<exclusion>

<groupId>org.glassfish</groupId>

<artifactId>javax.el</artifactId>

</exclusion>

</exclusions>

</dependency>

<dependency>

<groupId>org.glassfish</groupId>

<artifactId>javax.el</artifactId>

<version>3.0.1-b06</version>

</dependency>

</dependencies>

2)编写代码

package com.zhangjk.phoenix;

import java.sql.*;

import java.util.Properties;

public
class TestThick {

public
static
void main(String[] args)
throws SQLException {

String url =
"jdbc:phoenix:hadoop102,hadoop103,hadoop104:2181";

Properties props =
new Properties();

props.put("phoenix.schema.isNamespaceMappingEnabled","true");

Connection connection = DriverManager.getConnection(url,props);

PreparedStatement ps = connection.prepareStatement("select * from student3");

ResultSet rs = ps.executeQuery();

while(rs.next()){

System.out.println(rs.getString(1)+":"
+rs.getString(2));

}

}

}

Phoenix二级索引

添加如下配置到HBase的HRegionserver节点的hbase-site.xml

<!-- phoenix regionserver 配置参数-->

<property>

<name>hbase.regionserver.wal.codec</name>

<value>org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec</value>

</property>

<property>

<name>hbase.region.server.rpc.scheduler.factory.class</name>

<value>org.apache.hadoop.hbase.ipc.PhoenixRpcSchedulerFactory</value>

<description>Factory to create the Phoenix RPC Scheduler that uses separate queues for index and metadata updates</description>

</property>

<property>

<name>hbase.rpc.controllerfactory.class</name>

<value>org.apache.hadoop.hbase.ipc.controller.ServerRpcControllerFactory</value>

<description>Factory to create the Phoenix RPC Scheduler that uses separate queues for index and metadata updates</description>

</property>

Global Index是默认的索引格式,创建全局索引时,会在HBase中建立一张新表。也就是说索引数据和数据表是存放在不同的表中的,因此全局索引适用于多读少写的业务场景。

写数据的时候会消耗大量开销,因为索引表也要更新,而索引表是分布在不同的数据节点上的,跨节点的数据传输带来了较大的性能消耗。

在读数据的时候Phoenix会选择索引表来降低查询消耗的时间。

1.创建单个字段的全局索引

CREATE INDEX my_index ON my_table (my_col);

如果想查询的字段不是索引字段的话索引表不会被使用,也就是说不会带来查询速度的提升。

创建携带其他字段的全局索引

CREATE INDEX my_index ON my_table (v1) INCLUDE (v2);

Local Index适用于写操作频繁的场景。

索引数据和数据表的数据是存放在同一张表中(且是同一个Region),避免了在写操作的时候往不同服务器的索引表中写索引带来的额外开销。

CREATE LOCAL INDEX my_index ON my_table (my_column);

与Hive的集成

HBase与Hive的对比

(1) 数据分析工具

Hive的本质其实就相当于将HDFS中已经存储的文件在Mysql中做了一个双射关系,以方便使用HQL去管理查询。

(2) 用于数据分析、清洗

Hive适用于离线的数据分析和清洗,延迟较高。

(3) 基于HDFS、MapReduce

Hive存储的数据依旧在DataNode上,编写的HQL语句终将是转换为MapReduce代码执行。

(1) 数据库

是一种面向列族存储的非关系型数据库。

(2) 用于存储结构化和非结构化的数据

适用于单表非关系型数据的存储,不适合做关联查询,类似JOIN等操作。

(3) 基于HDFS

数据持久化存储的体现形式是HFile,存放于DataNode中,被ResionServer以region的形式进行管理。

(4) 延迟较低,接入在线业务使用

面对大量的企业数据,HBase可以直线单表大量数据的存储,同时提供了高效的数据访问速度。

HBase与Hive集成使用

在hive-site.xml中添加zookeeper的属性,如下:

<property>

<name>hive.zookeeper.quorum</name>

<value>hadoop102,hadoop103,hadoop104</value>

</property>

<property>

<name>hive.zookeeper.client.port</name>

<value>2181</value>

</property>

案例一

目标:建立Hive表,关联HBase表,插入数据到Hive表的同时能够影响HBase表。

分步实现:

CREATE TABLE hive_hbase_emp_table(

empno int,

ename string,

job string,

mgr int,

hiredate string,

sal double,

comm double,

deptno int)

STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'

WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key,info:ename,info:job,info:mgr,info:hiredate,info:sal,info:comm,info:deptno")

TBLPROPERTIES ("hbase.table.name" = "hbase_emp_table");

提示:完成之后,可以分别进入Hive和HBase查看,都生成了对应的表

2.在Hive中创建临时中间表,用于load文件中的数据

提示:不能将数据直接load进Hive所关联HBase的那张表中

CREATE TABLE emp(

empno int,

ename string,

job string,

mgr int,

hiredate string,

sal double,

comm double,

deptno int)

row format delimited fields terminated by '\t';

3.向Hive中间表中load数据

hive> load data local inpath '/home/admin/softwares/data/emp.txt' into table emp;

4.通过insert命令将中间表中的数据导入到Hive关联Hbase的那张表中

hive> insert into table hive_hbase_emp_table select * from emp;

5.查看Hive以及关联的HBase表中是否已经成功的同步插入了数据

Hive:

hive> select * from hive_hbase_emp_table;

HBase:

Hbase> scan 'hbase_emp_table'

案例二

目标:在HBase中已经存储了某一张表hbase_emp_table,然后在Hive中创建一个外部表来关联HBase中的hbase_emp_table这张表,使之可以借助Hive来分析HBase这张表中的数据。

注:该案例2基于案例1,所以完成此案例前,请先完成案例1。

分步实现:

CREATE EXTERNAL TABLE relevance_hbase_emp(

empno int,

ename string,

job string,

mgr int,

hiredate string,

sal double,

comm double,

deptno int)

STORED BY

'org.apache.hadoop.hive.hbase.HBaseStorageHandler'

WITH SERDEPROPERTIES ("hbase.columns.mapping" =

":key,info:ename,info:job,info:mgr,info:hiredate,info:sal,info:comm,info:deptno")

TBLPROPERTIES ("hbase.table.name" = "hbase_emp_table");

hive (default)> select * from relevance_hbase_emp;

HBase详解(05) - HBase优化 整合Phoenix 集成Hive的更多相关文章

  1. 图解大数据 | 海量数据库查询-Hive与HBase详解

    作者:韩信子@ShowMeAI 教程地址:http://www.showmeai.tech/tutorials/84 本文地址:http://www.showmeai.tech/article-det ...

  2. [转帖]HBase详解(很全面)

    HBase详解(很全面) very long story 简单看了一遍 很多不明白的地方.. 2018-06-08 16:12:32 卢子墨 阅读数 34857更多 分类专栏: HBase   [转自 ...

  3. 大数据学习day11------hbase_day01----1. zk的监控机制,2动态感知服务上下线案例 3.HDFS-HA的高可用基本的工作原理 4. HDFS-HA的配置详解 5. HBASE(简介,安装,shell客户端,java客户端)

    1. ZK的监控机制 1.1 监听数据的变化  (1)监听一次 public class ChangeDataWacher { public static void main(String[] arg ...

  4. HBase详解

    1.   hbase简介 1.1.  什么是hbase HBASE是一个高可靠性.高性能.面向列.可伸缩的分布式存储系统,利用HBASE技术可在廉价PC Server上搭建起大规模结构化存储集群. H ...

  5. 大数据入门第十四天——Hbase详解(一)入门与安装配置

    一.概述 1.什么是Hbase 根据官网:https://hbase.apache.org/ Apache HBase™ is the Hadoop database, a distributed, ...

  6. Hive集成HBase详解

    摘要 Hive提供了与HBase的集成,使得能够在HBase表上使用HQL语句进行查询 插入操作以及进行Join和Union等复杂查询   应用场景 1. 将ETL操作的数据存入HBase 2. HB ...

  7. SpringMVC详解及SSM框架整合项目

    SpringMVC ssm : mybatis + Spring + SpringMVC MVC三层架构 JavaSE:认真学习,老师带,入门快 JavaWeb:认真学习,老师带,入门快 SSM框架: ...

  8. HTTP协议探究(六):H2帧详解和HTTP优化

    一 复习与目标 1 复习 HTTP1.1存在的问题 HTTP2.0要兼容HTTP1.1 HTTP2.0的重要概念 分帧层 二进制:流 消息 帧 流的状态.优先级和并发 流量控制 服务器推送 首部压缩 ...

  9. 分布式数据库hbase详解

    新霸哥注意到了在人类随着计算机技术的发展,数据的存储量发生了很大的变化,可以用海量来形容,同时,存储的数据类型也是有多种多样的,网页,图片,视频,音频,电子邮件等等,所以在这中情况下以谷歌旗下的Big ...

  10. 大数据入门第十四天——Hbase详解(三)hbase基本原理与MR操作Hbase

    一.基本原理 1.hbase的位置 上图描述了Hadoop 2.0生态系统中的各层结构.其中HBase位于结构化存储层,HDFS为HBase提供了高可靠性的底层存储支持, MapReduce为HBas ...

随机推荐

  1. Ubuntu安装错误 server64 busybox-initramfs安装失败

    因为想试试在Linux系统上爆破 所以安装了一下Ubuntu.第一次安装包报了个server64 busybox-initramfs.在安装系统那边.我一直还以为是我磁盘分配错了. 后来在网上找了资料 ...

  2. JVM中的方法区

    JVM中的方法区 方法区存储什么? 用于存储已被虚拟机加载的类型信息.常量.静态变量.即时编译器编译后的代码缓存 1.类型信息 对每个加载的类型(类class.接口interface.枚举.注解)jv ...

  3. C语言------循环结构I

    文章目录 1 .实训名称 2 .实训目的及要求 3 .源代码及运行截图 4 .小结 1 .实训名称 实训5:循环结构I 2 .实训目的及要求 1 .熟练掌握while.do-while和for语句实现 ...

  4. rabbitmq原理和应用

    0.1.索引 https://blog.waterflow.link/articles/1663772504649 RabbitMQ 是一个轻量级且易于部署的消息队列.它支持开箱即用的多种消息传递协议 ...

  5. 安装zabbix-agent2之ansible-playbook

    zabbix被监控端安装zabbix-agent2之ansible-playbook --- - name: install agent hosts: all vars: server_host: & ...

  6. JS逆向实战6-- x轴 y轴 过点触验证码

    点触验证码是一种常见的反爬手段 解决方案有两种:一种是直接解决,这需要深度学习机器学习等图像处理技术,以大量的数据训练识别模型,最终达到模型足矣识别图片中的文字提示和应该点击的区域之间的对应关系. 这 ...

  7. mitmproxy抓包工具

    中文官网 https://ptorch.com/docs/10/mitmproxy-concepts-options mitmproxy抓包工具 1. mitmproxy 介绍与安装 需要安装pyth ...

  8. Xmake v2.7.3 发布,包组件和 C++ 模块增量构建支持

    Xmake 是一个基于 Lua 的轻量级跨平台构建工具. 它非常的轻量,没有任何依赖,因为它内置了 Lua 运行时. 它使用 xmake.lua 维护项目构建,相比 makefile/CMakeLis ...

  9. Java安全之反序列化(1)

    序列化与反序列化 概述 Java序列化是指把Java对象转换为字节序列的过程:这串字符可能被储存/发送到任何需要的位置,在适当的时候,再将它转回原本的 Java 对象,而Java反序列化是指把字节序列 ...

  10. day02-实现01

    实现01 1.实现任务阶段1 编写mytomcat,该服务器能给浏览器返回"你好,我是服务器!"的简单信息. 根据之前的tomcat框架整体分析,我们将浏览器发送请求,tomcat ...