ToB企服应用市场:ToB评测及商务社交产业平台

标题: 【大数据】深入了解Hadoop [打印本页]

作者: 尚未崩坏    时间: 2024-9-26 13:58
标题: 【大数据】深入了解Hadoop
一、Hadoop

   狭义上: 分布式数据管理(存储,盘算)的体系服务
广义上: 大数据开发的一个生态体系,很多大数据开发的工具都可以接入到hadoop中
如 zk可以共同Hadoop一起实现高可用
  1.1、Hadoop发展

   Hadoop属于Apache基金会的开源项目,下载源码使用
是搜刮引擎公司开发的,Hadoop的实现原理参考谷歌的两篇论文,
GFS论文,开发了hdfs 负责存储
Mapreduce论文,开发了mapreduce 负责盘算
  1.2、Hadoop特性

   
  1.3、Hadoop三大组件


二、Hadoop—HDFS(分布式文件存储体系)

负责大数据的数据储存功能
   对海量数采用文件的方式进行存储,同一个文件的数据可能会存储在差别的服务器实现分布式存储
  2.1、hdfs服务的构成


2.2、HDFS的Shell使用

   在hadoop的2.x版本中没有web页面的使用选项,只能通过shell方式使用
  1. hdfs dfs  参数
复制代码
  1. hdfs dfs -mkdir /hdfs_data
  2. hdfs dfs -touch /hdfs_data/a.txt
  3. hdfs dfs -rm -r /hdfs_data
  4. hdfs dfs -cp /hdfs_data/a.txt  /data
  5. hdfs dfs -mv  /data/画图.pptx  /hdfs_data
  6. hdfs dfs -mv  /hdfs_data/画图.pptx  /hdfs_data/a.pptx
  7. hdfs dfs -cat  /hdfs_data/a.txt
  8. hdfs dfs -ls /
复制代码
  hdfs的文件上传下载
  1. hdfs dfs -get hdfs上的文件路径   本地的文件路径(本地指操作的当前服务器)
  2. hdfs dfs -put 本地的文件路径(本地指操作的当前服务器)   hdfs上的目录路径
复制代码
2.3、HDFS读写流程


   客户端向filesystem请求获取文件数据,
filesystem请求NN检查文件,
NN获取元数据进行检查并返回检查结果给filesystem,filesystem返回给客户端,客户端请求调用读取数据方法fsDataReadStream,
fsDataReadStream请求NN获取数据所在位置,NN返回数据所在位置(按照块存储次序返回所有块的DN数据),然后按照packet大小读取数据,存储在内存上,数据读取完成后写入文件
当读取某个DN不可用时,会陈诉给NN
  
   1.客户端通过DistributedFileSystem模块向NN请求上传文件,NN检查目的文件是否已存在,父目次是否存在并返回检查结果
2. 客户端向NN请求第一个Block上传到哪几个DN服务器上
3. NN返回3个DN节点,分别为DN1,DN2,DN3
4. 客户端通过FSDataWriteStream模块请求NN获取要存储数据的DN并向DN1上传数据,DN1收到请求会继承调用DN2,然后DN2调用DN3,将这个通讯管道建立完成
5. DN1,DN2,DN3逐级应答客户端
6. 客户端开始往 DN1 上传第一个 Block (默认128M)(先从磁盘读取数据放到一个当地内存缓存),以 Packet(64KB) 为单位,DN1 收到一个 Packet 就会传给 DN2,DN2传给 DN3;DN1每传一个 packet 会放入一个应答队列等候应答。
7. 当一个 Block 传输完成之后,客户端再次请求 NameNode 上传第二个 Block 的服务器。(重复实行3-7步)
  2.4、三副本机制

   保证每个块在差别的服务器差别机架上
  服务器数量低于副本数量,存储数据时会报错
  1-第一个副本,由NN决定找哪个DN
2-第二个副本,有NN找第一个副当所在机架的差别服务器上
3-第三个副本,找和第一个副本差别机架的服务器上
2.5、元数据先容

hdfs的元数据两个部分

  1. hdfs oiv -i fsimage_0000000000000010119 -p XML -o fsimage.xml
复制代码

   客户端发送文件使用请求给NN,NN将新的元数据同步到内存中并同时使用信息记录在edits文件中,假如edits存储1M会产生新的文件
SNN向NN发送checkpoint请求,时间间隔是一小时,当发生checkpoint时会创建新的edits文件,checkpoint后的请求使用信息会被记录在新的edits中,SNN实行edits文件中的使用,使用后的数据加载内存中,将元数据保存在fsimage中,将fsimage文件传递给NN并修改文件名
  
   1-时间间隔达到1小时
2-文件使用次数达到100万次
两个条件只要满意一个就是实行checkpoint进行元数据文件保存
  1. # Checkpoint操作受两个参数控制,可以通过hdfs-site.xml进行配置:
  2. <property>
  3.   <name> dfs.namenode.checkpoint.period</name>
  4.    <value>3600</value>
  5.         <description>
  6. # 两次连续的checkpoint之间的时间间隔。默认1小时
  7. </description>
  8. </property>
  9. <property>
  10.   <name>dfs.namenode.checkpoint.txns</name>
  11.   <value>1000000</value>
  12.   <description>
  13. # 最大的没有执行checkpoint事务的数量,满足将强制执行紧急checkpoint,即使尚未达到检查点周期。默认设置为100万。  
  14. </description>
  15. </property>
复制代码
2.6、HDFS的归档

   重要解决内存元数据数据量过大
文件数据量非常多时,内存上或存储大量的文件元数据,此时内存占用资源比较大,可以对文件进行归档,类似对文件进行打包合成一个打包文件
一般归档是针对大量小文件
  
  1. hadoop archive -archiveName data.har -p /data  /hdfs_data
复制代码

  1. hdfs dfs -ls har:///hdfs_data/data.har
复制代码

  1. hdfs dfs -cp har:///hdfs_data/data.har/a.txt  /hdfs_data
复制代码
归档注意点
归档后并不会删除原有数据
原有数据依然会占用内存空间
要节流内存空就必要删除原有文件
2.7、HDFS垃圾桶机制

   删除hdfs文件时,可以将文件临时存在垃圾桶中,存储时间可以进行设置
可以core-site.xml中设置 时间单位是分钟
  1. <property>
  2.         <name>fs.trash.interval</name>
  3.         <value>1440</value>
  4. </property>
复制代码
  1. [root@node1 hadoop]  hdfs dfs -rm /hdfs_data/a.txt
  2. 2023-06-18 18:01:34,332 INFO fs.TrashPolicyDefault: Moved: 'hdfs://node1:8020/hdfs_data/a.txt' to trash at: hdfs://node1:8020/user/root/.Trash/Current/hdfs_data/a.txt
  3. [root@node1 hadoop]  hdfs dfs -rm -skipTrash /hdfs_data/a.pptx
  4. Deleted /hdfs_data/a.pptx
复制代码

2.8、HDFS安全机制

   保证文件使用的安全性
在hdfs启动时,会进行安全机制检查,检查块信息和datanode信息
检查通过了,可以进行文件的增删改查使用
检查未通过 只能读取文件,不能进行文件的写入修改删除使用
  
   1-保证每个块至少有一个副本,没有出现块的丢失
2-保证数据块占整个块的比例不能低于0.999f,不能低于99.999%
3-保证至少有0个datanode运行
4-满意以上3个条件之后等候30秒退出安全模式
  




三、Hadoop—MapReduce(分布式盘算引擎)

MapReduce 是hadoop负责盘算的服务功能,采用的盘算方式是分布式盘算,就算头脑’分而治之’
   传统盘算方式是移动数据盘算
分布式盘算,移动盘算到数据所在位置进行盘算
  3.1、MapReudce简朴使用

   hadoop提供测试代码
/export/server/hadoop/share/hadoop/mapreduce
  1. hadoop jar hadoop-mapreduce-examples-3.3.0.jar pi 5 100
复制代码

  1. hadoop jar hadoop-mapreduce-examples-3.3.0.jar wordcount  /input  /output
复制代码
3.2、MapReduce 盘算流程

3.3、MapReduce盘算历史服务


  1. mapred --daemon start historyserver
复制代码


四、Hadoop—Yarn(资源调度体系)

Yarn是hadoop中负责资源调度的服务功能,mapreduce盘算时使用的资源都必要找yarn申请,申请成功后才能进行盘算。
   yarn是hadoop2.x版本之后引入的服务,在之前盘算及时都是使用各自服务器上的资源,有了yarn可以协调分配多台服务器的资源。
  4.1、Yarn服务的构成


4.2、Yarn的资源调度流程

   1.客户端提交盘算任务给RM
2. RM找到NM创建ApplicantionMaster
3. ApplicationMater和RM保持通讯并申请盘算资源
4.申请成功,RM返回资源富足的NM信息,App通知对应的NM创建container资源空间
5.在对应的资源空间上运行MapTask,读取block数据转为kv(mr盘算时有一个combine机制在map端进行聚合盘算)
6.map通过shuffle将数据传递给reduce盘算
7.盘算完成后释放所有盘算资源
  4.3、Yarn资源调度方案

   当有多个盘算任务提交时,资源分配给哪个盘算任务使用?
此时必要指定资源调度策略
1-先进先出(FIFO) 谁先申请先给谁分配
2-容量调度(Capacity) 将资源划分多份,交给多个任务分开使用 默认采用
3-公平调度 (Fair) 盘算任务部分完成后,释放资源给其他任务使用 map盘算完成后就可以释放资源不必等所有盘算完成再释放
在yarn-site.xml文件下可以设置调度侧率
  1. # 容量调度  默认
  2. yarn.resourcemanager.scheduler.class=        org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler
  3. # 公平调度
  4. yarn.resourcemanager.scheduler.class=org.apache.hadoop.yarn.server.resourcemanager.reservation.FairSchedulerPlanFollower
复制代码
  当采用容量调度时必要单独对分配的容量进行指定
在hadoop的设置文件目次下指定capacity-scheduler.xml文件
  1. <configuration>
  2.    
  3. <property>
  4.     <name>yarn.scheduler.capacity.root.queues</name>
  5.     <value>prod,dev</value>   # 将资源分成两份一个叫prod一个dev
  6.   </property>
  7.    
  8. <property>
  9.     <name>yarn.scheduler.capacity.root.dev.queues</name>
  10.     <value>mapreduce,spark</value>  # 将dev分成两份 一个叫mapreduce一个spark
  11.   </property>
  12.    
  13.   <property>
  14.     <name>yarn.scheduler.capacity.root.prod.capacity</name>
  15.     <value>40</value>  # 分配prod资源空间占比为40%
  16.   </property>
  17.    
  18.   <property>
  19.     <name>yarn.scheduler.capacity.root.dev.capacity</name>
  20.     <value>60</value>  # 分配dev资源空间占比为60%
  21.   </property>
  22.    
  23.   <property>
  24.     <name>yarn.scheduler.capacity.root.dev.maximum-capacity</name>
  25.     <value>75</value> # 动态调整dev的大小  最大为75%
  26.   </property>
  27.    
  28.   <property>
  29.     <name>yarn.scheduler.capacity.root.dev.mapreduce.capacity</name>
  30.     <value>50</value>  # 指定dev下的mapreduce 占用dev的空间的50%
  31.   </property>
  32.    
  33.    
  34.    <property>
  35.     <name>yarn.scheduler.capacity.root.dev.spark.capacity</name>
  36.     <value>50</value>  # 指定dev下的spark 占用dev的空间的50%
  37.   </property>
  38.    
  39. </configuration>
复制代码
  在使用时可以在代码中指定采用哪个资源,指定资源名称
root.dev.mapreduce
  五、Hadoop集群搭建

   Hadoop摆设方式分三种:
Standalone mode(独立模式)、
Pseudo-Distributed mode(伪分布式模式)、
Cluster mode(集群模式)
其中前两种都是在单机摆设。
独立模式又称为单机模式,仅1个呆板运行1个java进程,重要用于调试。
伪分布模式也是在1个呆板上运行HDFS的NameNode和DataNode、YARN的 ResourceManger和NodeManager,但分别启动单独的java进程,重要用于调试。
集群模式重要用于生产环境摆设。会使用N台主机组成一个Hadoop集群。这种摆设模式下,主节点和从节点会分开摆设在差别的呆板上。
  

5.1、搭建步骤

1.上传hadoop压缩包(hadoop-3.3.0-Centos7-64-with-snappy.tar.gz)解压,注意:上传文件位置为 /export/server目次
  1. cd /export/server
  2. tar  zxvf /export/server/hadoop-3.3.0-Centos7-64-with-snappy.tar.gz
复制代码
2.设置环境变量
  1. echo 'export HADOOP_HOME=/export/server/hadoop-3.3.0' >> /etc/profile
  2. echo 'export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin' >> /etc/profile
  3. source /etc/profile
复制代码
3.手动修改设置文件(3和4二选一)
   进入/export/server/hadoop-3.3.0/etc/hadoop目次下进行修改
  ① hadoop-env.sh文件
  1. export JAVA_HOME=/export/server/jdk
  2. #文件最后添加
  3. export HDFS_NAMENODE_USER=root
  4. export HDFS_DATANODE_USER=root
  5. export HDFS_SECONDARYNAMENODE_USER=root
  6. export YARN_RESOURCEMANAGER_USER=root
  7. export YARN_NODEMANAGER_USER=root
复制代码
② core-site.xml文件
  1. <!-- 设置默认使用的文件系统 Hadoop支持file、HDFS、GFS、ali|Amazon云等文件系统 -->
  2. <property>
  3.     <name>fs.defaultFS</name>
  4.     <value>hdfs://node1:8020</value>
  5. </property>
  6. <!-- 设置Hadoop本地保存数据路径 -->
  7. <property>
  8.     <name>hadoop.tmp.dir</name>
  9.     <value>/export/data/hadoop-3.3.0</value>
  10. </property>
  11. <!-- 设置HDFS web UI用户身份 -->
  12. <property>
  13.     <name>hadoop.http.staticuser.user</name>
  14.     <value>root</value>
  15. </property>
  16. <!-- 整合hive 用户代理设置 -->
  17. <property>
  18.     <name>hadoop.proxyuser.root.hosts</name>
  19.     <value>*</value>
  20. </property>
  21. <property>
  22.     <name>hadoop.proxyuser.root.groups</name>
  23.     <value>*</value>
  24. </property>
复制代码
③ hdfs-site.xml文件
  1. <!-- 设置SNN进程运行机器位置信息 -->
  2. <property>
  3.     <name>dfs.namenode.secondary.http-address</name>
  4.     <value>node2:9868</value>
  5. </property>
复制代码
④ mapred-site.xml文件
  1. <!-- 设置MR程序默认运行模式: yarn集群模式 local本地模式 -->
  2. <property>
  3.   <name>mapreduce.framework.name</name>
  4.   <value>yarn</value>
  5. </property>
  6. <!-- MR程序历史服务器端地址 -->
  7. <property>
  8.   <name>mapreduce.jobhistory.address</name>
  9.   <value>node1:10020</value>
  10. </property>
  11. <!-- 历史服务器web端地址 -->
  12. <property>
  13.   <name>mapreduce.jobhistory.webapp.address</name>
  14.   <value>node1:19888</value>
  15. </property>
  16. <property>
  17.   <name>yarn.app.mapreduce.am.env</name>
  18.   <value>HADOOP_MAPRED_HOME=${HADOOP_HOME}</value>
  19. </property>
  20. <property>
  21.   <name>mapreduce.map.env</name>
  22.   <value>HADOOP_MAPRED_HOME=${HADOOP_HOME}</value>
  23. </property>
  24. <property>
  25.   <name>mapreduce.reduce.env</name>
  26.   <value>HADOOP_MAPRED_HOME=${HADOOP_HOME}</value>
  27. </property>
复制代码
⑤ yarn-site.xml文件
  1. <!-- 设置YARN集群主角色运行机器位置 -->
  2. <property>
  3.         <name>yarn.resourcemanager.hostname</name>
  4.         <value>node1</value>
  5. </property>
  6. <property>
  7.     <name>yarn.nodemanager.aux-services</name>
  8.     <value>mapreduce_shuffle</value>
  9. </property>
  10. <!-- 是否将对容器实施物理内存限制 -->
  11. <property>
  12.     <name>yarn.nodemanager.pmem-check-enabled</name>
  13.     <value>false</value>
  14. </property>
  15. <!-- 是否将对容器实施虚拟内存限制。 -->
  16. <property>
  17.     <name>yarn.nodemanager.vmem-check-enabled</name>
  18.     <value>false</value>
  19. </property>
  20. <!-- 开启日志聚集 -->
  21. <property>
  22.   <name>yarn.log-aggregation-enable</name>
  23.   <value>true</value>
  24. </property>
  25. <!-- 设置yarn历史服务器地址 -->
  26. <property>
  27.     <name>yarn.log.server.url</name>
  28.     <value>http://node1:19888/jobhistory/logs</value>
  29. </property>
  30. <!-- 保存的时间7天 -->
  31. <property>
  32.   <name>yarn.log-aggregation.retain-seconds</name>
  33.   <value>604800</value>
  34. </property>
复制代码
⑥ workers文件
  1. node1
  2. node2
  3. node3
复制代码
4.使用设置文件替换(3和4二选一)
   上传设置文件压缩包(hadoop-config.tar)解压,注意:上传文件位置为 /export/server目次
  1. tar  xvf /export/server/hadoop-config.tar
  2. mv -f /export/server/hadoop-config/* /export/server/hadoop-3.3.0/etc/hadoop/
  3. rm  /export/server/hadoop-config*  -rf
复制代码
5.集群搭建说明
   必要将node1中的Hadoop文件复制到node2和node3的对应位置
  1. scp可以进行主机的文件复制拷贝
  2. scp -r /export/server/hadoop-3.3.0  root@node2:/export/server/
复制代码
6.hadoop集群启动
① 数据初始化
   注意: 初始化使用必须在node1中实行
  1. hdfs namenode -format
复制代码
② 脚本启动和关闭
  1. start-all.sh
  2. stop-all.sh
复制代码
  http://192.168.88.100:9870
题目:
无法在HDFS上传文件,原因是当地windows下没有进行IP地址的域名解析
解决:windows下进入C:\Windows\System32\drivers\etc
192.168.88.100 node1.jinking.cn node1
192.168.88.101 node2.jinking.cn node2
192.168.88.102 node3.jinking.cn node3
  5.2、高可用搭建步骤

   重要解决服务的单点故障题目,进步服务的使用效率
使用zk实现多服务状态管理,选举产生主备
   三台服务器都要安装
  1. yum install psmisc -y  # 实现多个服务的通讯 zkfc和nn及zk的通讯
  2. rpm -ivh   psmisc-22.20-17.el7.x86_64.rpm
复制代码
  1. tar cvf hadoop.tar /export/server/hadoop-3.3.0
复制代码
  1. rm -rf /export/data/hadoop-3.3.0
复制代码

  1. # 在文件最后添加下面两行
  2. export HDFS_JOURNALNODE_USER=root
  3. export HDFS_ZKFC_USER=root                        
复制代码

  1. <configuration>
  2.         <!-- HA集群名称,该值要和hdfs-site.xml中的配置保持一致 -->
  3.         <property>
  4.                 <name>fs.defaultFS</name>
  5.                 <value>hdfs://cluster1</value>
  6.         </property>
  7.         <!-- hadoop本地磁盘存放数据的公共目录 -->
  8.         <property>
  9.                 <name>hadoop.tmp.dir</name>
  10.                 <value>/export/data/ha-hadoop</value>
  11.         </property>
  12.         <!-- ZooKeeper集群的地址和端口-->
  13.         <property>
  14.                 <name>ha.zookeeper.quorum</name>
  15.                 <value>node1:2181,node2:2181,node3:2181</value>
  16.         </property>
  17. </configuration>
复制代码

  1. <configuration>
  2.         <!--指定hdfs的nameservice为cluster1,需要和core-site.xml中的保持一致 -->
  3.         <property>
  4.                 <name>dfs.nameservices</name>
  5.                 <value>cluster1</value>
  6.         </property>
  7.        
  8.         <!-- cluster1下面有两个NameNode,分别是nn1,nn2 -->
  9.         <property>
  10.                 <name>dfs.ha.namenodes.cluster1</name>
  11.                 <value>nn1,nn2</value>
  12.         </property>
  13.         <!-- nn1的RPC通信地址 -->
  14.         <property>
  15.                 <name>dfs.namenode.rpc-address.cluster1.nn1</name>
  16.                 <value>node1:8020</value>
  17.         </property>
  18.         <!-- nn1的http通信地址 -->
  19.         <property>
  20.                 <name>dfs.namenode.http-address.cluster1.nn1</name>
  21.                 <value>node1:50070</value>
  22.         </property>
  23.         <!-- nn2的RPC通信地址 -->
  24.         <property>
  25.                 <name>dfs.namenode.rpc-address.cluster1.nn2</name>
  26.                 <value>node2:8020</value>
  27.         </property>
  28.        
  29.         <!-- nn2的http通信地址 -->
  30.         <property>
  31.                 <name>dfs.namenode.http-address.cluster1.nn2</name>
  32.                 <value>node2:50070</value>
  33.         </property>
  34.         <!-- 指定NameNode的edits元数据在JournalNode上的存放位置 -->
  35.         <property>
  36.                 <name>dfs.namenode.shared.edits.dir</name>
  37.                 <value>qjournal://node1:8485;node2:8485;node3:8485/cluster1</value>
  38.         </property>
  39.        
  40.         <!-- 指定JournalNode在本地磁盘存放数据的位置 -->
  41.         <property>
  42.                 <name>dfs.journalnode.edits.dir</name>
  43.                 <value>/export/data/journaldata</value>
  44.         </property>
  45.         <!-- 开启NameNode失败自动切换 -->
  46.         <property>
  47.                 <name>dfs.ha.automatic-failover.enabled</name>
  48.                 <value>true</value>
  49.         </property>
  50.         <!-- 指定该集群出故障时,哪个实现类负责执行故障切换 -->
  51.         <property>
  52.                 <name>dfs.client.failover.proxy.provider.cluster1</name>
  53.                 <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
  54.         </property>
  55.         <!-- 配置隔离机制方法-->
  56.         <property>
  57.                 <name>dfs.ha.fencing.methods</name>
  58.                 <value>sshfence</value>
  59.         </property>
  60.        
  61.         <!-- 使用sshfence隔离机制时需要ssh免登陆 -->
  62.         <property>
  63.                 <name>dfs.ha.fencing.ssh.private-key-files</name>
  64.                 <value>/root/.ssh/id_rsa</value>
  65.         </property>
  66.        
  67.         <!-- 配置sshfence隔离机制超时时间 -->
  68.         <property>
  69.                 <name>dfs.ha.fencing.ssh.connect-timeout</name>
  70.                 <value>30000</value>
  71.         </property>
  72. </configuration>
复制代码

  1. <configuration>
  2.     <!-- 开启RM高可用 -->
  3.     <property>
  4.         <name>yarn.resourcemanager.ha.enabled</name>
  5.         <value>true</value>
  6.     </property>
  7.     <!-- 指定RM的cluster id -->
  8.     <property>
  9.         <name>yarn.resourcemanager.cluster-id</name>
  10.         <value>yrc</value>
  11.     </property>
  12.     <!-- 指定RM的名字 -->
  13.     <property>
  14.         <name>yarn.resourcemanager.ha.rm-ids</name>
  15.         <value>rm1,rm2</value>
  16.     </property>
  17.     <!-- 分别指定RM的地址 -->
  18.     <property>
  19.         <name>yarn.resourcemanager.hostname.rm1</name>
  20.         <value>node1</value>
  21.     </property>
  22.     <property>
  23.         <name>yarn.resourcemanager.hostname.rm2</name>
  24.         <value>node2</value>
  25.     </property>
  26.     <!-- 指定zk集群地址 -->
  27.     <property>
  28.         <name>yarn.resourcemanager.zk-address</name>
  29.         <value>node1:2181,node2:2181,node3:2181</value>
  30.     </property>
  31.     <property>
  32.         <name>yarn.nodemanager.aux-services</name>
  33.         <value>mapreduce_shuffle</value>
  34.     </property>
  35. </configuration>
复制代码
  注意: 将hadoop设置信息拷贝到node2和node3
注意: 将hadoop设置信息拷贝到node2和node3
注意: 将hadoop设置信息拷贝到node2和node3
  

5.启动

注意
   搭建高可用后,之前的SNN会被QJM代替
  



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4