ClickHouse集群搭建(一)

满目山河空念远,落花风雨更伤春。

java42.jpg

ClickHouse概述

什么是ClickHouse?

ClickHouse 是俄罗斯的Yandex于2016年开源的列式存储数据库(DBMS),主要用于在线分析处理查询(OLAP),能够使用SQL查询实时生成分析数据报告。

什么是列式存储 ?

以下面表为例

id website wechat
1 https://niocoder.com/ java干货
2 http://www.merryyou.cn/ javaganhuo

采用行式存储时,数据在磁盘上的组织结构为:

Row1 Row2
1 https://niocoder.com/ java干货 2 http://www.merryyou.cn/ javaganhuo

好处是想查某条记录所有的属性时,可以通过一次磁盘查找加顺序读取就可以。但是当想查所有记录wechat时,需要不停的查找,或者全表扫描才行,遍历的很多数据都是不需要的。

而采用列式存储时,数据在磁盘上的组织结构为:

col1 col2 col3
1 2 https://niocoder.com/ http://www.merryyou.cn/ java干货 javaganhuo

这时想查所有记录的wechat只需把col3那一列拿出来即可。

集群环境搭建

在 安装ClickHouse 具体开始前, 先来搭建一下环境,软件包下载见末尾。

创建虚拟机

安装虚拟机 VMWare

安装Vmware虚拟机

导入 CentOS

将下载的CentOS系统中导入到 VMWare

注意事项:windows系统确认所有的关于VmWare的服务都已经启动,

确认好VmWare生成的网关地址,另外确认VmNet8网卡已经配置好了IP地址。

更多关于VmWare网络模式参考VMware虚拟机三种网络模式详解

集群规划

IP 主机名 环境配置 安装 ClickHouse
192.168.10.100 node01 关防火墙, host映射, 时钟同步 JDK, Zookeeper clickhouse-server 9000 clickhouse-server 9001
192.168.10.110 node02 关防火墙, host映射, 时钟同步 JDK, Zookeeper clickhouse-server 9000 clickhouse-server 9001
192.168.10.120 node03 关防火墙, host映射, 时钟同步 JDK, Zookeeper clickhouse-server 9000 clickhouse-server 9001

配置每台主机

更改ip地址和HWADDR地址

vim /etc/sysconfig/network-scripts/ifcfg-eth0

[图片上传失败...(image-e9718b-1606616621682)]

HWADDR地址查看

[图片上传失败...(image-765a55-1606616621683)]

修改主机名(重启后永久生效)

[图片上传失败...(image-2653ed-1606616621683)]

vim /etc/hostname

设置hosts域名映射

image

vim /etc/hosts

关闭防火墙

三台机器执行以下命令

systemctl status firewalld.service #查看防火墙状态
systemctl stop firewalld.service #关闭防火墙
systemctl disable firewalld.service #永久关闭防火墙

免密登录

为了方便传输文件,三台机器之前配置免密登录.

  • 免密 SSH 登录的原理
    1. 需要先在 B节点 配置 A节点 的公钥
    2. A节点 请求 B节点 要求登录
    3. B节点 使用 A节点 的公钥, 加密一段随机文本
    4. A节点 使用私钥解密, 并发回给 B节点
    5. B节点 验证文本是否正确
三台机器生成公钥与私钥

在三台机器执行以下命令,生成公钥与私钥

ssh-keygen -t rsa

执行该命令之后,按下三个回车即可

[图片上传失败...(image-5111c8-1606616621683)]

拷贝公钥到node01机器

三台机器将拷贝公钥到node01机器

三台机器执行命令:

ssh-copy-id node01

复制node01机器的认证到其他机器

将第一台机器的公钥拷贝到其他机器上

node01机器上面执行以下命令

scp /root/.ssh/authorized_keys node02:/root/.ssh

scp /root/.ssh/authorized_keys node03:/root/.ssh

[图片上传失败...(image-40ba58-1606616621683)]

设置时钟同步服务

  • 为什么需要时间同步
    • 因为很多分布式系统是有状态的, 比如说存储一个数据, A节点 记录的时间是 1, B节点 记录的时间是 2, 就会出问题
## 安装
yum install -y ntp

## 启动定时任务
crontab -e

随后在输入界面键入

*/1 * * * * /usr/sbin/ntpdate ntp4.aliyun.com;

安装JDK

上传jdk并解压然后配置环境变量

所有软件的安装路径

mkdir -p /export/servers #node01,node02,node03机器上执行

所有软件压缩包的存放路径

mkdir -p /export/softwares # 创建文件夹

安装rzsz命令

yum -y install lrzsz # 安装rz sz 命令

上传jdk安装包到/export/softwares路径下去,并解压

tar -zxvf jdk-8u141-linux-x64.tar.gz -C ../servers/

配置环境变量

vim /etc/profile

export JAVA_HOME=/export/servers/jdk1.8.0_141
export PATH=:$JAVA_HOME/bin:$PATH

执行以下命令将jdk安装包分发到node02node03节点上

scp -r /export/servers/jdk1.8.0_141/ node02:/export/servers/
scp -r /export/servers/jdk1.8.0_141/ node03:/export/servers/
scp /etc/profile node02:/etc/profile
scp /etc/profile node03:/etc/profile

刷新环境变量

source /etc/profile

安装Zookeeper

服务器IP 主机名 myid的值
192.168.10.100 node01 1
192.168.10.110 node02 2
192.168.10.120 node03 3

上传zookeeper安装包到/export/softwares路径下去,并解压

tar -zxvf zookeeper-3.4.9.tar.gz -C ../servers/

node01修改配置文件如下

cd /export/servers/zookeeper-3.4.9/conf/

cp zoo_sample.cfg zoo.cfg
# 创建数据存放节点
mkdir -p /export/servers/zookeeper-3.4.9/zkdatas/

vim zoo.cfg

dataDir=/export/servers/zookeeper-3.4.9/zkdatas
# 保留多少个快照
autopurge.snapRetainCount=3
# 日志多少小时清理一次
autopurge.purgeInterval=1
# 集群中服务器地址
server.1=node01:2888:3888
server.2=node02:2888:3888
server.3=node03:2888:3888

node01机器上

/export/servers/zookeeper-3.4.9/zkdatas/这个路径下创建一个文件,文件名为myid ,文件内容为1

echo 1 > /export/servers/zookeeper-3.4.9/zkdatas/myid

安装包分发到其他机器

node01机器上面执行以下两个命令

scp -r /export/servers/zookeeper-3.4.9/ node02:/export/servers/

scp -r /export/servers/zookeeper-3.4.9/ node03:/export/servers/

node02机器上修改myid的值为2

echo 2 > /export/servers/zookeeper-3.4.9/zkdatas/myid

node03机器上修改myid的值为3

echo 3 > /export/servers/zookeeper-3.4.9/zkdatas/myid

启动zookeeper服务

node01,node02,node03机器都要执行

/export/servers/zookeeper-3.4.9/bin/zkServer.sh start

查看启动状态

/export/servers/zookeeper-3.4.9/bin/zkServer.sh status

安装前准备

CPU是否支持SSE4.2

查看CPU是否支持SSE4.2指令集

grep -q sse4_2 /proc/cpuinfo && echo "SSE 4.2 supported" || echo "SSE 4.2 not supported"

安装必要依赖

yum install -y unixODBC libicudata

yum install -y libxml2-devel expat-devel libicu-devel

安装ClickHouse

单机模式

上传4个文件到node01机器/opt/software/
[root@node01 softwares]# ll
total 306776
-rw-r--r--. 1 root root      6384 Nov  2 22:43 clickhouse-client-20.8.3.18-1.el7.x86_64.rpm
-rw-r--r--. 1 root root  69093220 Nov  2 22:48 clickhouse-common-static-20.8.3.18-1.el7.x86_64.rpm
-rw-r--r--. 1 root root  36772044 Nov  2 22:51 clickhouse-server-20.8.3.18-1.el7.x86_64.rpm
-rw-r--r--. 1 root root     14472 Nov  2 22:43 clickhouse-server-common-20.8.3.18-1.el7.x86_64.rpm
分别安装这4个rpm安装包
[root@node01 softwares]# rpm -ivh clickhouse-common-static-20.8.3.18-1.el7.x86_64.rpm 
Preparing...                          ################################# [100%]
Updating / installing...
   1:clickhouse-common-static-20.8.3.1################################# [100%]
[root@node01 softwares]# rpm -ivh clickhouse-server-common-20.8.3.18-1.el7.x86_64.rpm 
Preparing...                          ################################# [100%]
Updating / installing...
   1:clickhouse-server-common-20.8.3.1################################# [100%]
[root@node01 softwares]# rpm -ivh clickhouse-server-20.8.3.18-1.el7.x86_64.rpm 
Preparing...                          ################################# [100%]
Updating / installing...
   1:clickhouse-server-20.8.3.18-1.el7################################# [100%]
Create user clickhouse.clickhouse with datadir /var/lib/clickhouse
[root@node01 softwares]# rpm -ivh clickhouse-client-20.8.3.18-1.el7.x86_64.rpm 
Preparing...                          ################################# [100%]
Updating / installing...
   1:clickhouse-client-20.8.3.18-1.el7################################# [100%]
Create user clickhouse.clickhouse with datadir /var/lib/clickhouse
rpm安装完毕后,clickhouse-serverclickhouse-client配置目录如下
[root@node01 softwares]# ll /etc/clickhouse-server/
total 44
-rw-r--r--. 1 root root 33738 Oct  6 06:05 config.xml
-rw-r--r--. 1 root root  5587 Oct  6 06:05 users.xml
[root@node01 softwares]# ll /etc/clickhouse-client/
total 4
drwxr-xr-x. 2 clickhouse clickhouse    6 Nov 28 22:19 conf.d
-rw-r--r--. 1 clickhouse clickhouse 1568 Oct  6 04:44 config.xml

/etc/clickhouse-server/config.xmlClickHouse核心配置文件,主要内容如下
<?xml version="1.0"?>
<yandex>
   <!-- 日志 -->
   <logger>
       <level>trace</level>
       <log>/data1/clickhouse/log/server.log</log>
       <errorlog>/data1/clickhouse/log/error.log</errorlog>
       <size>1000M</size>
       <count>10</count>
   </logger>

   <!-- 端口 -->
   <http_port>8123</http_port>
   <tcp_port>9000</tcp_port>
   <interserver_http_port>9009</interserver_http_port>

   <!-- 本机域名 -->
   <interserver_http_host>这里需要用域名,如果后续用到复制的话</interserver_http_host>

   <!-- 监听IP -->
   <listen_host>0.0.0.0</listen_host>
   <!-- 最大连接数 -->
   <max_connections>64</max_connections>

   <!-- 没搞懂的参数 -->
   <keep_alive_timeout>3</keep_alive_timeout>

   <!-- 最大并发查询数 -->
   <max_concurrent_queries>16</max_concurrent_queries>

   <!-- 单位是B -->
   <uncompressed_cache_size>8589934592</uncompressed_cache_size>
   <mark_cache_size>10737418240</mark_cache_size>

   <!-- 存储路径 -->
   <path>/data1/clickhouse/</path>
   <tmp_path>/data1/clickhouse/tmp/</tmp_path>

   <!-- user配置 -->
   <users_config>users.xml</users_config>
   <default_profile>default</default_profile>

   <log_queries>1</log_queries>

   <default_database>default</default_database>

   <remote_servers incl="clickhouse_remote_servers" />
   <zookeeper incl="zookeeper-servers" optional="true" />
   <macros incl="macros" optional="true" />

   <!-- 没搞懂的参数 -->
   <builtin_dictionaries_reload_interval>3600</builtin_dictionaries_reload_interval>

   <!-- 控制大表的删除 -->
   <max_table_size_to_drop>0</max_table_size_to_drop>

   <include_from>/data1/clickhouse/metrika.xml</include_from>
</yandex>
启动ClickHouse
[root@node01 softwares]# service clickhouse-server start
Start clickhouse-server service: Path to data directory in /etc/clickhouse-server/config.xml: /var/lib/clickhouse/
DONE
[root@node01 softwares]# 

使用client链接server

[root@node01 softwares]# clickhouse-client -m
ClickHouse client version 20.8.3.18.
Connecting to localhost:9000 as user default.
Connected to ClickHouse server version 20.8.3 revision 54438.

node01 :) show databases;

SHOW DATABASES

┌─name───────────────────────────┐
│ _temporary_and_external_tables │
│ default                        │
│ system                         │
└────────────────────────────────┘

3 rows in set. Elapsed: 0.007 sec. 

node01 :) select 1;

SELECT 1

┌─1─┐
│ 1 │
└───┘

1 rows in set. Elapsed: 0.005 sec. 

node01 :) 

分布式集群安装

node02node03上面执行之前的所有的操作
node01机器修改配置文件config.xml
[root@node01 softwares]# vim /etc/clickhouse-server/config.xml
<!-- 打开这个 -->
 <listen_host>::</listen_host>
    <!-- Same for hosts with disabled ipv6: -->
    <!-- <listen_host>0.0.0.0</listen_host> -->
    <!-- 新增外部配置文件metrika.xml  -->
<include_from>/etc/clickhouse-server/metrika.xml</include_from>

将修改后的配置分发到node02,node03机器上

scp config.xml node02:/etc/clickhouse-server/config.xml

scp config.xml node03:/etc/clickhouse-server/config.xml

node01机器/etc/clickhouse-server/目录下创建metrika.xml文件
<yandex>
<!-- 集群配置 -->
<clickhouse_remote_servers>
    <!-- 3分片1备份 -->
    <cluster_3shards_1replicas>
        <!-- 数据分片1  -->
        <shard>
            <replica>
                <host>node01</host>
                <port>9000</port>
            </replica>
        </shard>
        <!-- 数据分片2  -->
        <shard>
            <replica>
                <host>node02</host>
                <port> 9000</port>
            </replica>
        </shard>
        <!-- 数据分片3  -->
        <shard>
            <replica>
                <host>node03</host>
                <port>9000</port>
            </replica>
        </shard>
    </cluster_3shards_1replicas>
</clickhouse_remote_servers>
</yandex>

配置说明

  • cluster_3shards_1replicas 集群名称,可随意定义
  • 共设置3个分片,每个分片只有1个副本;

metrika.xml配置文件分发到node02,node03机器上

scp metrika.xml node02:/etc/clickhouse-server/metrika.xml

scp metrika.xml node03:/etc/clickhouse-server/metrika.xml

重启ClickHouse-server 打开client查看集群
[root@node01 clickhouse-server]# service clickhouse-server restart
Stop clickhouse-server service: DONE
Start clickhouse-server service: Path to data directory in /etc/clickhouse-server/config.xml: /var/lib/clickhouse/
DONE
[root@node01 clickhouse-server]# clickhouse-client -m
ClickHouse client version 20.8.3.18.
Connecting to localhost:9000 as user default.
Connected to ClickHouse server version 20.8.3 revision 54438.

node01 :) select * from system.clusters;

SELECT *
FROM system.clusters

┌─cluster───────────────────────────┬─shard_num─┬─shard_weight─┬─replica_num─┬─host_name─┬─host_address───┬─port─┬─is_local─┬─user────┬─default_database─┬─errors_count─┬─estimated_recovery_time─┐
│ cluster_3shards_1replicas         │         1 │            1 │           1 │ node01    │ 192.168.10.100 │ 9000 │        1 │ default │                  │            0 │                       0 │
│ cluster_3shards_1replicas         │         2 │            1 │           1 │ node02    │ 192.168.10.110 │ 9000 │        0 │ default │                  │            0 │                       0 │
│ cluster_3shards_1replicas         │         3 │            1 │           1 │ node03    │ 192.168.10.120 │ 9000 │        0 │ default │                  │            0 │                       0 │
│ test_cluster_two_shards           │         1 │            1 │           1 │ 127.0.0.1 │ 127.0.0.1      │ 9000 │        1 │ default │                  │            0 │                       0 │
│ test_cluster_two_shards           │         2 │            1 │           1 │ 127.0.0.2 │ 127.0.0.2      │ 9000 │        0 │ default │                  │            0 │                       0 │
│ test_cluster_two_shards_localhost │         1 │            1 │           1 │ localhost │ ::1            │ 9000 │        1 │ default │                  │            0 │                       0 │
│ test_cluster_two_shards_localhost │         2 │            1 │           1 │ localhost │ ::1            │ 9000 │        1 │ default │                  │            0 │                       0 │
│ test_shard_localhost              │         1 │            1 │           1 │ localhost │ ::1            │ 9000 │        1 │ default │                  │            0 │                       0 │
│ test_shard_localhost_secure       │         1 │            1 │           1 │ localhost │ ::1            │ 9440 │        0 │ default │                  │            0 │                       0 │
│ test_unavailable_shard            │         1 │            1 │           1 │ localhost │ ::1            │ 9000 │        1 │ default │                  │            0 │                       0 │
│ test_unavailable_shard            │         2 │            1 │           1 │ localhost │ ::1            │    1 │        0 │ default │                  │            0 │                       0 │
└───────────────────────────────────┴───────────┴──────────────┴─────────────┴───────────┴────────────────┴──────┴──────────┴─────────┴──────────────────┴──────────────┴─────────────────────────┘

11 rows in set. Elapsed: 0.008 sec.                │            0 │                      

可以看到cluster_3shards_1replicas就是我们定义的集群名称,一共有三个分片,每个分片有一份数据。剩下的为配置文件默认自带的集群配置.

测试分布式集群

node01,node02,node03上分别创建本地表cluster3s1r_local

CREATE TABLE default.cluster3s1r_local
(
    `id` Int32,
    `website` String,
    `wechat` String,
    `FlightDate` Date,
    Year UInt16
)
ENGINE = MergeTree(FlightDate, (Year, FlightDate), 8192);

node01节点上创建分布式表

CREATE TABLE default.cluster3s1r_all AS cluster3s1r_local
ENGINE = Distributed(cluster_3shards_1replicas, default, cluster3s1r_local, rand());

往分布式表cluster3s1r_all插入数据,cluster3s1r_all会随机插入到三个节点的cluster3s1r_local

插入数据

INSERT INTO default.cluster3s1r_all (id,website,wechat,FlightDate,Year)values(1,'https://niocoder.com/','java干货','2020-11-28',2020);
INSERT INTO default.cluster3s1r_all (id,website,wechat,FlightDate,Year)values(2,'http://www.merryyou.cn/','javaganhuo','2020-11-28',2020);
INSERT INTO default.cluster3s1r_all (id,website,wechat,FlightDate,Year)values(3,'http://www.xxxxx.cn/','xxxxx','2020-11-28',2020);

查询分布式表和本地表

node01 :) select * from cluster3s1r_all; # 查询总量查分布式表

SELECT *
FROM cluster3s1r_all

┌─id─┬─website─────────────────┬─wechat─────┬─FlightDate─┬─Year─┐
│  2 │ http://www.merryyou.cn/ │ javaganhuo │ 2020-11-28 │ 2020 │
└────┴─────────────────────────┴────────────┴────────────┴──────┘
┌─id─┬─website──────────────┬─wechat─┬─FlightDate─┬─Year─┐
│  3 │ http://www.xxxxx.cn/ │ xxxxx  │ 2020-11-28 │ 2020 │
└────┴──────────────────────┴────────┴────────────┴──────┘
┌─id─┬─website───────────────┬─wechat───┬─FlightDate─┬─Year─┐
│  1 │ https://niocoder.com/ │ java干货 │ 2020-11-28 │ 2020 │
└────┴───────────────────────┴──────────┴────────────┴──────┘

3 rows in set. Elapsed: 0.036 sec. 

node01 :) select * from cluster3s1r_local; # node01本地表

SELECT *
FROM cluster3s1r_local

┌─id─┬─website─────────────────┬─wechat─────┬─FlightDate─┬─Year─┐
│  2 │ http://www.merryyou.cn/ │ javaganhuo │ 2020-11-28 │ 2020 │
└────┴─────────────────────────┴────────────┴────────────┴──────┘

1 rows in set. Elapsed: 0.012 sec.

node02 :) select * from cluster3s1r_local; # node02本地表

SELECT *
FROM cluster3s1r_local

Ok.

0 rows in set. Elapsed: 0.016 sec. 

node03 :) select * from cluster3s1r_local; ## node03 本地表

SELECT *
FROM cluster3s1r_local

┌─id─┬─website──────────────┬─wechat─┬─FlightDate─┬─Year─┐
│  3 │ http://www.xxxxx.cn/ │ xxxxx  │ 2020-11-28 │ 2020 │
└────┴──────────────────────┴────────┴────────────┴──────┘
┌─id─┬─website───────────────┬─wechat───┬─FlightDate─┬─Year─┐
│  1 │ https://niocoder.com/ │ java干货 │ 2020-11-28 │ 2020 │
└────┴───────────────────────┴──────────┴────────────┴──────┘

2 rows in set. Elapsed: 0.006 sec. 

下载

[图片上传失败...(image-6fd8de-1606616746222)]

关注微信公众号java干货回复 【clickhouse】

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容