VMware上CentOS7.0+Hadoop3.1伪分布式搭建

栏目: 服务器 · 发布时间: 6年前

内容简介:最近要搭建一个Hadoop做实验,因为版本的问题遇到不少的坑,本文记录VMware上搭建的CentOS7.0+Hadoop3.1伪分布式的整个过程。CentOS7.0安装这里不赘述。Hadoop下载3.1。

最近要搭建一个Hadoop做实验,因为版本的问题遇到不少的坑,本文记录VMware上搭建的CentOS7.0+Hadoop3.1伪分布式的整个过程。

CentOS7.0安装这里不赘述。

Hadoop下载3.1。

JDK需要安装1.8。

一、VM

网络采用NAT模式,毕竟后续搭建分布式方便。

取消DHCP,NAT里的dns设置成虚拟的网关IP(192.168.31.2,可以加上外网的解析地址114.114.114.114)

VMware上CentOS7.0+Hadoop3.1伪分布式搭建

VMware上CentOS7.0+Hadoop3.1伪分布式搭建

VMware上CentOS7.0+Hadoop3.1伪分布式搭建

二、IP设置

使用NAT模式设置IP

默认宿主机ip192.168.31.1 

#不同的PC,这里的IP不一样

,但是宿主机一般都是.1,网关机(虚拟机的)一般都是.2

宿主机的虚拟网卡VMnet8有时候IP会出问题,建议手工设置IP:192.168.31.1

默认虚拟机网关192.168.31.2 ,虚拟机自动虚拟出来的。

虚拟机ip手动设置为192.168.31.10  #这里随意设置,不要和宿主机和网关相同就可以,确保在一个网段。

以上IP和原本宿主机的局域网IP不在一个网段。

VMware上CentOS7.0+Hadoop3.1伪分布式搭建

linux的IP

vi /etc/sysconfig/network-scripts/ifcfg-ens33

#注意这里,不同的 linux 版本网卡名字可能不一样,通常可能是eth0,CentOS7.0是ens33

以下是ifcfg-ens33里的内容:

TYPE=Ethernet

PROXY_METHOD=none

BROWSER_ONLY=no

BOOTPROTO=none

DEFROUTE=yes

IPV4_FAILURE_FATAL=no

##IPV6INIT=yes

##IPV6_AUTOCONF=yes

##IPV6_DEFROUTE=yes

##IPV6_FAILURE_FATAL=no

##IPV6_ADDR_GEN_MODE=stable-privacy

NAME=ens33

UUID=45fe5552-7117-4c84-9742-c87adfa222b9

DEVICE=ens33

ONBOOT=yes

ZONE=public #这里设置ZONE方便后面设置防火墙

IPADDR=192.168.31.10

NETMASK=255.255.255.0

GATEWAY=192.168.31.2

DNS1=192.168.31.2

虚拟机ifconfig

VMware上CentOS7.0+Hadoop3.1伪分布式搭建

宿主机ipconfig

VMware上CentOS7.0+Hadoop3.1伪分布式搭建

设置到这里,宿主机可以ping通虚拟机,虚拟机可以ping通宿主机和网关。如果相互ping不同就需要检查宿主机和虚拟机的防火墙。

三、设置主机名

修改hostname

vi /etc/sysconfig/network

NETWORKING=yes  #使用网络

HOSTNAME=bigdata-senior01.home.com  #设置主机名

配置hosts

vi /etc/host

127.0.0.1  localhost localhost.localdomain localhost4 localhost4.localdomain4

::1        localhost localhost.localdomain localhost6 localhost6.localdomain6

192.168.31.10 bigdata-senior01.home.com

配置完linux的主机名,在windows的hosts里也需要配置一下192.168.31.10 bigdata-senior01.home.com

一定要设置主机名,一定要配置hosts,曾经被坑在这里。

四、关闭selinux

selinux是Linux一个子安全机制,但是,请关闭它。

vi /etc/sysconfig/selinux

# This file controls the state of SELinux on the system.

# SELINUX= can take one of these three values:

#    enforcing - SELinux security policy is enforced.

#    permissive - SELinux prints warnings instead of enforcing.

#    disabled - No SELinux policy is loaded.

SELINUX=disabled

# SELINUXTYPE= can take one of these two values:

#    targeted - Targeted processes are protected,

#    mls - Multi Level Security protection.

SELINUXTYPE=targeted

 五、Hadoop的用户设置

1、 创建hadoop的普通用户

useradd hadoop

passwd hadoop

2、 给hadoop用户sudo权限

vi /etc/sudoers

设置权限(非生产环境可以随意点)

root    ALL=(ALL)      ALL

hadoop ALL=(root) NOPASSWD:ALL

3、 切换到hadoop用户

su - hadoop

4、 创建存放hadoop文件的目录

sudo mkdir /opt/modules

5、 将hadoop文件夹的所有者指定为hadoop用户

如果存放hadoop的目录的所有者不是hadoop,之后hadoop运行中可能会有权限问题。

sudo chown -R hadoop:hadoop /opt/modules

六、解压Hadoop目录文件

自行百度hadoop下载

1、 复制hadoop-3.1.0.tar.gz到/opt/modules目录下。

2、 解压hadoop-3.1.0.tar.gz

cd /opt/modules

tar -zxvf hadoop-3.1.0.tar.gz

七、配置hadoop环境变量

1、环境变量

vi /etc/profile

java的配置这里也提一下:

#set java environment

JAVA_HOME=/home/java/jdk1.8.0_172

JRE_HOME=/home/java/jdk1.8.0_172/jre

CLASS_PATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib

PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin

export JAVA_HOME JRE_HOME CLASS_PATH PATH

hadoop追加配置:

export HADOOP_HOME="/opt/modules/hadoop-3.1.0"

export PATH=$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$PATH

执行:source /etc/profile 使得配置生效

验证HADOOP_HOME参数:

echo $HADOOP_HOME

/opt/modules/hadoop-3.1.0

或者使用env检查一下所有的配置情况。

2、 配置 hadoop-env.sh文件的JAVA_HOME参数

sudo vi  ${HADOOP_HOME}/etc/hadoop/hadoop-env.sh

修改JAVA_HOME参数为:

export JAVA_HOME="/opt/modules/jdk1.8.0_172" #这里一定要使用绝对路径

3、 配置core-site.xml

vi ${HADOOP_HOME}/etc/hadoop/core-site.xml

(1) fs.defaultFS参数配置的是HDFS的地址。

<property>

<name>fs.defaultFS</name>

<value>hdfs://bigdata-senior01.home.com:9000</value>

</property>

(2) hadoop.tmp.dir配置的是Hadoop临时目录,比如HDFS的NameNode数据默认都存放这个目录下,查看core-default.xml等默认配置文件,就可以看到很多依赖${hadoop.tmp.dir}的配置。

创建临时目录:

sudo mkdir -p /opt/data/tmp

将临时目录的所有者修改为hadoop:

sudo chown –R hadoop:hadoop /opt/data/tmp

修改hadoop.tmp.dir

<property>

<name>hadoop.tmp.dir</name>

<value>/opt/data/tmp</value>

</property>

最后core-site.xml

<configuration>

<property>

<name>fs.defaultFS</name>

<value>hdfs://bigdata-senior01.home.com:9000</value>

<description>HDFS的URI,文件系统://namenode标识:端口号</description>

</property>

<property>

<name>hadoop.tmp.dir</name>

<value>/opt/data/tmp</value>

<description>namenode上本地的hadoop临时文件夹</description>

</property>

</configuration>

八、配置HDFS,启动HDFS

1、 配置hdfs-site.xml

vi ${HADOOP_HOME}/etc/hadoop/hdfs-site.xml

<property>

<name>dfs.replication</name>

<value>1</value>

<description>副本个数,配置默认是3,应小于datanode机器数量</description>

</property>

</property>

dfs.replication配置的是HDFS存储时的备份数量,因为这里是伪分布式环境只有一个节点,所以这里设置为1。

其他配置,如果不配置以下属性,hadoop将会在之前配置的临时文件下面创建name和data目录

<property>

<name>dfs.name.dir</name>

<value>/opt/hadoop/hdfs/name</value>

<description>namenode上存储hdfs名字空间元数据 </description>

</property>

<property>

<name>dfs.data.dir</name>

<value>/opt/hadoop/hdfs/data</value>

<description>datanode上数据块的物理存储位置</description>

</property>

2、 格式化HDFS

hdfs namenode –format #只需要在第一次的时候执行

格式化是对HDFS这个分布式文件系统中的DataNode进行分块,统计所有分块后的初始元数据的存储在NameNode中。

格式化后,查看core-site.xml里hadoop.tmp.dir(/opt/data目录)指定的目录下是否有了dfs目录,如果有,说明格式化成功。

注意权限设置,最好把Hadoop设置成/opt/data目录的所有者

sudo chown -R hadoop:hadoop /opt/data

查看NameNode格式化后的目录。

ll /opt/data/tmp/dfs/name/current

3、 启动NameNode

${HADOOP_HOME}/sbin/hadoop-daemon.sh start namenode

系统会告警,建议采用:hdfs --daemon start namenode

4、 启动DataNode

${HADOOP_HOME}/sbin/hadoop-daemon.sh start datanode

系统会告警,建议采用:hdfs --daemon start datanode

5、 启动SecondaryNameNode

${HADOOP_HOME}/sbin/hadoop-daemon.sh start secondarynamenode

系统会告警,建议采用:hdfs --daemon start secondarynamenode

6、 JPS命令查看是否已经启动成功,有结果就是启动成功了。

jps

1267 NameNode

1380 DataNode

1559 Jps

1528 SecondaryNameNode

7、 HDFS上测试创建目录、上传、下载文件

HDFS上创建目录

hdfs dfs -mkdir /demo

上传本地文件到HDFS上

hdfs dfs -put ${HADOOP_HOME}/etc/hadoop/core-site.xml /demo

读取HDFS上的文件内容

hdfs dfs -cat /demo/core-site.xml

从HDFS上下载文件到本地

hdfs dfs -get /demo/core-site.xml

查看目录

$ hdfs dfs -ls /demo

也可以使用hadoop fs -mkdir /mydata这样的命令

VMware上CentOS7.0+Hadoop3.1伪分布式搭建

九、配置和启动YARN

1、 配置mapred-site.xml

vi ${HADOOP_HOME}/etc/hadoop/mapred-site.xml

添加配置如下:

<property>

<name>mapreduce.framework.name</name>

<value>yarn</value>

</property>

指定mapreduce运行在yarn框架上。

2、 配置yarn-site.xml

vi ${HADOOP_HOME}/etc/hadoop/yarn-site.xml

添加配置如下:

<property>

<name>yarn.nodemanager.aux-services</name>

<value>mapreduce_shuffle</value>

</property>

<property>

<name>yarn.resourcemanager.hostname</name>

<value>bigdata-senior01.home.com</value>

</property>

yarn.nodemanager.aux-services配置了yarn的默认混洗方式,选择为mapreduce的默认混洗算法。

yarn.resourcemanager.hostname指定了Resourcemanager运行在哪个节点上。

3、 启动Resourcemanager

${HADOOP_HOME}/sbin/yarn-daemon.sh start resourcemanager

系统会告警,建议采用:yarn --daemon start resourcemanager

4、 启动nodemanager

[hadoop@bigdata-senior01 hadoop-3.1.0]$ ${HADOOP_HOME}/sbin/yarn-daemon.sh start nodemanager

系统会告警,建议采用:yarn --daemon start nodemanager

5、 查看是否启动成功

[hadoop@localhost sbin]$ jps

1395 DataNode

1507 SecondaryNameNode

2150 Jps

2075 NodeManager

1292 NameNode

1628 ResourceManager

6、YARN的Web页面

YARN的Web客户端端口号是8088,通过http://192.168.31.10:8088/可以查看。

如果防火墙没有关闭,还需要添加端口:

firewall-cmd --zone=public --add-port=8088/tcp --permanent

HDFS的web页面:

http://192.168.31.10:9870/

firewall-cmd --zone=public --add-port=9870/tcp --permanent

#注意这里,hadoop3.0以前hdfs的端口号不是9870

以后类似需要端口访问的web管理页面,都需要在防火墙里添加端口,也可以直接关闭防火墙。

移除端口:firewall-cmd --zone=public --remove-port=8088/tcp --permanent

VMware上CentOS7.0+Hadoop3.1伪分布式搭建

十、运行MapReduce Job

在Hadoop的share目录里,自带了一些jar包,里面带有一些mapreduce实例小例子,位置在$HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.0.jar,可以运行这些例子体验刚搭建好的Hadoop平台,我们这里来运行最经典的WordCount实例。版本不同,这个jar包的名字也有点区别。

1、添加类库路径

因为运行的是hadoop自带的例子,所以例子里的类库要加入

编辑 Hadoop 安装目录下 etc/hadoop/mapred-site.xml 文件,在  <configuration> 标签和 </configuration> 标签之间添加如下配置:

<property>

<description>CLASSPATH for MR applications. A comma-separated list

of CLASSPATH entries. If mapreduce.application.framework is set then this

must specify the appropriate classpath for that archive, and the name of

the archive must be present in the classpath.

If mapreduce.app-submission.cross-platform is false, platform-specific

environment vairable expansion syntax would be used to construct the default

CLASSPATH entries.

For Linux:

$HADOOP_MAPRED_HOME/share/hadoop/mapreduce/*,

$HADOOP_MAPRED_HOME/share/hadoop/mapreduce/lib/*.

For Windows:

%HADOOP_MAPRED_HOME%/share/hadoop/mapreduce/*,

%HADOOP_MAPRED_HOME%/share/hadoop/mapreduce/lib/*.

If mapreduce.app-submission.cross-platform is true, platform-agnostic default

CLASSPATH for MR applications would be used:

{{HADOOP_MAPRED_HOME}}/share/hadoop/mapreduce/*,

{{HADOOP_MAPRED_HOME}}/share/hadoop/mapreduce/lib/*

Parameter expansion marker will be replaced by NodeManager on container

launch based on the underlying OS accordingly.

</description>

<name>mapreduce.application.classpath</name>

<value>/opt/modules/hadoop-3.1.0/share/hadoop/mapreduce/*, /opt/modules/hadoop-3.1.0/share/hadoop/mapreduce/lib-examples/*</value>

</property>

注意,这一点非常重要,必须填写完整的路径,即必须是绝对路径,不能包含变量。

2、内存配置:

-----

安装虚拟机的时候内存原本是1G,运行job一直出错,各种修改配置文件里的内存都不行,最后把虚拟机内存调整成2G以运行成功。

关于内存这块,要非常熟悉hadoop的各类配置才好下手,新手入门还是先不折腾。

-----

3、 创建测试用的Input文件

创建输入目录:

hdfs dfs -mkdir -p /wordcountdemo/input

创建原始文件:

在本地/opt/data目录创建一个文件mydata.input,内容如下:

cat /opt/data/mydata.input

abc def kkk

abc kkk sss

ddd abc sss

abc abc sss

将wc.input文件上传到HDFS的/wordcountdemo/input目录中:

hdfs dfs -put /opt/data/mydata.input /wordcountdemo/input

运行WordCount MapReduce Job

yarn jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.0.jar wordcount /wordcountdemo/input /wordcountdemo/output

2018-05-29 22:18:34,201 INFO client.RMProxy: Connecting to ResourceManager at bigdata-senior01.home.com/192.168.31.10:8032

2018-05-29 22:18:35,314 INFO mapreduce.JobResourceUploader: Disabling Erasure Coding for path: /tmp/hadoop-yarn/staging/hadoop/.staging/job_1527603486527_0001

2018-05-29 22:18:36,437 INFO input.FileInputFormat: Total input files to process : 1

2018-05-29 22:18:37,402 INFO mapreduce.JobSubmitter: number of splits:1

2018-05-29 22:18:37,472 INFO Configuration.deprecation: yarn.resourcemanager.system-metrics-publisher.enabled is deprecated. Instead, use yarn.system-metrics-publisher.enabled

2018-05-29 22:18:37,834 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_1527603486527_0001

2018-05-29 22:18:37,845 INFO mapreduce.JobSubmitter: Executing with tokens: []

2018-05-29 22:18:38,124 INFO conf.Configuration: resource-types.xml not found

2018-05-29 22:18:38,124 INFO resource.ResourceUtils: Unable to find 'resource-types.xml'.

2018-05-29 22:18:38,671 INFO impl.YarnClientImpl: Submitted application application_1527603486527_0001

2018-05-29 22:18:38,737 INFO mapreduce.Job: The url to track the job: http://bigdata-senior01.home.com:8088/proxy/application_1527603486527_0001/

2018-05-29 22:18:38,738 INFO mapreduce.Job: Running job: job_1527603486527_0001

2018-05-29 22:18:51,002 INFO mapreduce.Job: Job job_1527603486527_0001 running in uber mode : false

2018-05-29 22:18:51,003 INFO mapreduce.Job:  map 0% reduce 0%

2018-05-29 22:18:57,124 INFO mapreduce.Job:  map 100% reduce 0%

2018-05-29 22:19:04,187 INFO mapreduce.Job:  map 100% reduce 100%

2018-05-29 22:19:06,209 INFO mapreduce.Job: Job job_1527603486527_0001 completed successfully

2018-05-29 22:19:06,363 INFO mapreduce.Job: Counters: 53

File System Counters

FILE: Number of bytes read=94

FILE: Number of bytes written=425699

FILE: Number of read operations=0

FILE: Number of large read operations=0

FILE: Number of write operations=0

HDFS: Number of bytes read=202

HDFS: Number of bytes written=60

HDFS: Number of read operations=8

HDFS: Number of large read operations=0

HDFS: Number of write operations=2

Job Counters

Launched map tasks=1

Launched reduce tasks=1

Data-local map tasks=1

Total time spent by all maps in occupied slots (ms)=4455

Total time spent by all reduces in occupied slots (ms)=4530

Total time spent by all map tasks (ms)=4455

Total time spent by all reduce tasks (ms)=4530

Total vcore-milliseconds taken by all map tasks=4455

Total vcore-milliseconds taken by all reduce tasks=4530

Total megabyte-milliseconds taken by all map tasks=4561920

Total megabyte-milliseconds taken by all reduce tasks=4638720

Map-Reduce Framework

Map input records=4

Map output records=11

Map output bytes=115

Map output materialized bytes=94

Input split bytes=131

Combine input records=11

Combine output records=7

Reduce input groups=7

Reduce shuffle bytes=94

Reduce input records=7

Reduce output records=7

Spilled Records=14

Shuffled Maps =1

Failed Shuffles=0

Merged Map outputs=1

GC time elapsed (ms)=172

CPU time spent (ms)=1230

Physical memory (bytes) snapshot=388255744

Virtual memory (bytes) snapshot=5476073472

Total committed heap usage (bytes)=165810176

Peak Map Physical memory (bytes)=242692096

Peak Map Virtual memory (bytes)=2733621248

Peak Reduce Physical memory (bytes)=145563648

Peak Reduce Virtual memory (bytes)=2742452224

Shuffle Errors

BAD_ID=0

CONNECTION=0

IO_ERROR=0

WRONG_LENGTH=0

WRONG_MAP=0

WRONG_REDUCE=0

File Input Format Counters

Bytes Read=71

File Output Format Counters

Bytes Written=60

查看输出结果目录

hdfs dfs -ls /wordcountdemo/output

--用命令:hadoop fs -cat /wordcountdemo/output/part-r-00000,也可以,上面也一样

Found 2 items

-rw-r--r--  1 hadoop supergroup          0 2018-05-29 22:19 /wordcountdemo/output/_SUCCESS

-rw-r--r--  1 hadoop supergroup        60 2018-05-29 22:19 /wordcountdemo/output/part-r-00000

output目录中有两个文件,_SUCCESS文件是空文件,有这个文件说明Job执行成功。

part-r-00000文件是结果文件,其中-r-说明这个文件是Reduce阶段产生的结果,mapreduce程序执行时,可以没有reduce阶段,但是肯定会有map阶段,如果没有reduce阶段这个地方有是-m-。

一个reduce会产生一个part-r-开头的文件。

查看输出文件内容。

hdfs dfs -cat /wordcountdemo/output/part-r-00000

在虚拟机上,因为内存不足这里经常会出现的情况就是内存溢出,然后hadoop的运行容器被kill。

十一、开启历史服务

Hadoop开启历史服务可以在web页面上查看Yarn上执行job情况的详细信息。可以通过历史服务器查看已经运行完的Mapreduce作业记录,比如用了多少个Map、用了多少个Reduce、作业提交时间、作业启动时间、作业完成时间等信息。

mr-jobhistory-daemon.sh start historyserver、

此命令已经被弃用,建议使用:mapred --daemon start historyserver

开启后,可以通过Web页面查看历史服务器:

http://bigdata-senior01.home.com:19888/

历史服务器的Web端口默认是19888,可以查看Web界面。

VMware上CentOS7.0+Hadoop3.1伪分布式搭建

十二、节点免密登录

是指通过证书认证的方式登陆,使用一种被称为"公私钥"认证的方式来进行ssh登录

如果我们需要使用hadoop目录sbin/下的便捷脚本运行hadoop,就需要配置免密登录

root用户下:

ssh-keygen -t rsa 一路回车下去

cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys #.ssh这个隐藏目录的权限要求是700。

chmod 600 ~/.ssh/authorized_keys #这个文件需要特殊的权限要求。

这样就可以运行诸如:start-all.sh,start-dfs.sh这些脚本。

最后,说说hadoop3.0后端口的变化:

Namenode 端口:

50470 --> 9871

50070 --> 9870

8020 --> 9820

Secondary NN 端口:

50091 --> 9869

50090 --> 9868

Datanode 端口:

50020 --> 9867

50010 --> 9866

50475 --> 9865

50075 --> 9864

Hadoop2.3-HA高可用集群环境搭建 https://www.linuxidc.com/Linux/2017-03/142155.htm

Hadoop项目之基于CentOS7的Cloudera 5.10.1(CDH)的安装部署  https://www.linuxidc.com/Linux/2017-04/143095.htm

Hadoop2.7.2集群搭建详解(高可用)  https://www.linuxidc.com/Linux/2017-03/142052.htm

使用Ambari来部署Hadoop集群(搭建内网HDP源)  https://www.linuxidc.com/Linux/2017-03/142136.htm

Ubuntu 14.04下Hadoop集群安装  https://www.linuxidc.com/Linux/2017-02/140783.htm

CentOS 6.7安装Hadoop 2.7.2  https://www.linuxidc.com/Linux/2017-08/146232.htm

Ubuntu 16.04上构建分布式Hadoop-2.7.3集群  https://www.linuxidc.com/Linux/2017-07/145503.htm

CentOS 7 下 Hadoop 2.6.4 分布式集群环境搭建  https://www.linuxidc.com/Linux/2017-06/144932.htm

Hadoop2.7.3+Spark2.1.0完全分布式集群搭建过程  https://www.linuxidc.com/Linux/2017-06/144926.htm

更多Hadoop相关信息见 Hadoop 专题页面 http://www.linuxidc.com/topicnews.aspx?tid=13

Linux公社的RSS地址https://www.linuxidc.com/rssFeed.aspx

本文永久更新链接地址: https://www.linuxidc.com/Linux/2018-06/152680.htm


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Web性能优化

Web性能优化

Patrick Killelea 谢 / 谢文亮 / 清华大学出版社 / 2003-11-01 / 49.00元

本书讲述如何将Web性能调至最佳状态。书中不仅谈到了Web服务器软件的优化,而且还涉及到如何流水化处理Web内容,如何从浏览器端着手优化性能,如何调校客户端和服务器的硬件,以及如何最大限度地使用网络本身的特性。 书中的内容涉及到影响性能好坏的本质,并为得到立竿见影的效果提供了具体建议。本书向您娓娓道出评价计算性能高低的准则,并在后半部分讲述从客户端、网络直到服务器这一链条中每个环节的薄弱之一起来看看 《Web性能优化》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码