HBase配置

数据库 Quarterback 19℃ 0评论

本文主要讨论这几个问题:

  1. HBase配置文件
    1. backup-masters
    2. hadoop-metrics2-hbase.properties
    3. hbase-env.cmd and hbase-env.sh
    4. hbase-policy.xml
    5. hbase-site.xml
    6. log4j.properties
    7. regionservers
  2. 系统环境配置
    1. JDK
    2. SSH
    3. DNS
    4. NTP
    5. 文件和进程数限制(ulimit)
    6. Linux Shell
    7. 不建议在Windows上部署运行生产环境
  3. Hadoop
    1. Hadoop与HBase版本兼容性
    2. 更换hbase lib目录中依赖的hadoop jar
    3. hdfs-site.xml: dfs.datanode.max.transfer.threads
  4. Zookeeper
  5. HBase不同部署模式配置
    1. Standalone
    2. 分布式部署
  6. HDFS客户端配置
  7. HBase默认配置参数详解(hbase-default.xml -> hbase-site.xml)

1. HBase配置文件

  • backup-masters
    • 默认情况下该文件不存在。这是一个纯文本文件,其中列出了主服务器应在其上启动备份主进程的主机,每行一台主机
  • regionservers
    • 包含应该在 HBase 集群中运行 RegionServer 的主机列表的纯文本文件。默认情况下,这个文件包含单个条目localhostt。它应该包含主机名或 IP 地址列表,每行一个,如果集群中的每个节点将在其localhost接口上运行 RegionServer 的话,则只应包含localhost
  • hadoop-metrics2-hbase.properties

    • 用于连接 HBase Hadoop 的 Metrics2 框架
  • hbase-env.cmd 和 hbase-env.sh
    • 用于 Windows 和 Linux/Unix 环境的脚本,以设置 HBase 的工作环境,包括 Java、Java 选项和其他环境变量的位置。该文件包含许多注释示例来提供指导。
  • hbase-policy.xml
    • RPC 服务器使用默认策略配置文件对客户端请求进行授权决策。仅在启用 HBase安全模式下使用。
  • hbase-site.xml
    • 主要的 HBase 配置文件。该文件指定覆盖 HBase 的默认配置的配置选项。您可以在 docs/hbase-default.xml 中查看(但不要编辑)默认配置文件。您还可以在 HBase Web UI 的 HBase 配置选项卡中查看群集的整个有效配置(默认和覆盖)。
  • log4j.properties
    • 通过log4j进行 HBase 日志记录的配置文件。
  • 当在分布式模式下运行时, 在对 HBase 配置进行编辑后,请确保将 conf/目录的内容复制到群集的所有节点。HBase 不会为你这么做的。请使用 rsync, scp或其他安全机制将配置文件复制到你的节点。对于大多数配置, 服务器需要重新启动才能成功更改。动态配置是这方面的一个例外
 

2. 系统环境配置

  • JDK
    • 安装JDK主要注意配置JAVA_HOME等环境变量,以及HBase版本对JDK版本的兼容性。
HBase 版本
JDK7 JDK8 JDK9(Non-LTS) JDK10(Non-LTS) JDK11
2.1+ 不支持 支持 不支持(HBASE-20264 不支持(HBASE-20264 不支持(HBASE-21110
2.0 不支持 支持 不支持(HBASE-20264
不支持(HBASE-20264
不支持(HBASE-21110
1.3+ 支持 支持 不支持(HBASE-20264 不支持(HBASE-20264
不支持(HBASE-21110
1.2 支持 支持 不支持(HBASE-20264
不支持(HBASE-20264
不支持(HBASE-21110
  • SSH
    • HBase 广泛使用安全 Shell(ssh)命令和实用程序在集群节点之间进行通信。集群中的每台服务器都必须运行ssh,以便可以管理 Hadoop 和 HBase 后台进程。您必须能够使用共享密钥而不是密码(配置ssh免密登录),通过 SSH(包括本地节点)从主服务器和任何备份主服务器连接到所有节点。
  • DNS
    • HBase 使用本地的主机名hostname来自我报告其IP地址
  • NTP
    • 群集节点上的时钟应该同步。少量的变化是可以接受的,但是大量的不同步会导致不稳定和意外的行为。如果在群集中看到无法解释的问题,则时间同步是首先要检查的事项之一。
    • 应该在群集上运行网络时间协议(NTP)服务或其他时间同步机制,并且所有节点都查找相同的服务以进行时间同步。
  • 文件和进程数限制(ulimit)
    • 打开文件数(open files, ulimit -n)
      • HBase 是一个数据库。它需要能够一次打开大量的文件。许多 Linux 发行版限制了允许单个用户打开的文件数量1024(或者256,在旧版本的 OS X 上)。当以运行 HBase 的用户身份登录时,您可以通过在服务器上运行ulimit -n 命令来检查服务器上的限制。限制太低会产生一些 故障 您也可能会注意到以下错误:
2010-04-06 03:04:37,542 INFO org.apache.hadoop.hdfs.DFSClient: Exception increateBlockOutputStream java.io.EOFException
2010-04-06 03:04:37,542 INFO org.apache.hadoop.hdfs.DFSClient: Abandoning block blk_-6935524980745310745_1391901
      • 建议将 ulimit 提高到至少 10,000,但更可能是 10,240,因为该值通常以 1024 的倍数表示。每个 ColumnFamily 至少有一个 StoreFile,如果该Region处于加载状态,则可能有多于六个的 StoreFile。所需的打开文件的数量取决于 ColumnFamilies 的数量和Region的数量。以下是计算 RegionServer 上打开的文件的潜在数量的粗略公式。
(StoreFiles per ColumnFamily) x (regions per RegionServer)
      • 假设一个模式的每个Region有 3 个 ColumnFamilies,每个 ColumnFamily 平均有 3 个 StoreFiles,每个 RegionServer 有 100 个Region,则 JVM 将打开3 * 3 * 100 = 900文件描述符,不包括打开的 JAR 文件、配置文件等等。打开一个文件不需要很多资源,而且允许用户打开太多文件的风险很小。
    • 用户最大进程数(max user processes,ulimit -u)
      • 另一个相关设置是允许用户同时运行的进程数量。在 Linux 和 Unix 中,使用该ulimit -u 命令设置进程的数量。这不应与nproc命令混淆,该命令控制给定用户可用的 CPU 数量。在负载下,ulimit -u太低会导致 OutOfMemoryError 异常。
      • 为运行 HBase 进程的用户配置文件描述符和进程的最大数量是操作系统配置,而不是 HBase 配置。确保为实际运行 HBase 的用户更改设置也很重要。要查看哪个用户启动了 HBase,以及该用户的 ulimit 配置,请查看该实例的 HBase 日志的第一行。
  • Linux Shell
    • 所有 HBase 附带的 shell 脚本都依赖于GNU Bash shell.
  • 不建议在windows上部署生产环境

3. Hadoop

  • Hadoop与HBase版本兼容性:
  HBase-1.2.x HBase-1.3.x
HBase-1.4.x
HBase-1.5.x
HBase-2.1.x
HBase-2.2.x
Hadoop-2.4.x 支持 支持
不支持
不支持
不支持
不支持
Hadoop-2.5.x
支持 支持
不支持
不支持
不支持
不支持
Hadoop-2.6.0
不支持 不支持
不支持
不支持
不支持
不支持
Hadoop-2.6.1+
支持
支持
不支持
不支持
不支持
不支持
Hadoop-2.7.0
不支持
不支持
不支持
不支持
不支持
不支持
Hadoop-2.7.1+
不支持
支持
支持
不支持
支持
不支持
Hadoop-2.8.[0-2]
不支持
不支持
不支持
不支持
不支持
不支持
Hadoop-2.8.[3-4]
未测试
未测试 未测试
不支持
支持
不支持
Hadoop-2.8.5+
不支持
未测试
未测试
支持
支持
支持
Hadoop-2.9.[0-1]
不支持
不支持
不支持
不支持
不支持
不支持
Hadoop-2.9.2+
不支持
未测试
未测试
支持
未测试
支持
Hadoop-3.0.[0-2]
不支持
不支持
不支持
不支持
不支持
不支持
Hadoop-3.0.3+
不支持
不支持
不支持
不支持
支持
不支持
Hadoop-3.1.0
不支持
不支持
不支持
不支持
不支持
不支持
Hadoop-3.1.1+
不支持
不支持
不支持
不支持
支持
支持
    • 一些已知的hadoop与hbase版本兼容性问题:
      • Hadoop Pre-2.6.1 和 JDK 1.8 Kerbero
        • 在 Kerberos 环境中使用 pre-2.6.1 Hadoop 版本和 JDK 1.8 时,HBase 服务器可能因 Kerberos keytab relogin 错误而失败并中止。JDK 1.7 (1.7. 0_80) 的后期版本也有问题HADOOP-10786。在这种情况下考虑升级到 Hadoop 2.6.1+。
      • Hadoop 2.6.
        • 如果您计划在 HDFS 加密区域的顶部运行 HBase,则基于 2.6.x 行的 Hadoop 发行版必须具有 HADOOP-11710 应用。如果不这样做,将导致群集故障和数据丢失。此修补程序存在于 Apache Hadoop 2.6.1+版本中。
      • Hadoop 2.y.0
        • Hadoop 2.7.0 开始两个版本未经测试或不受支持,因为 Hadoop PMC 明确将该版本标记为不稳定.因此,HBase 明确建议用户避免在这些版本之上运行。另外,Hadoop PMC 也给出了同样的警告。有关参考,请参见 Apache Hadoop 2.7.0, Apache Hadoop 2.8.0, Apache Hadoop 2.8.1, and Apache Hadoop 2.9.0.
      • Hadoop 3.0.x
        • 包含应用程序时间服务特性的 Hadoop 集群可能会导致出现意外的 HBase 类版本.用户要确保YARN-7190 存在于 yarn 服务中 (目前已修复 2.9.1+ , 3.1.0+).
      • Hadoop 3.1.0
        • Hadoop PMC 声称 3.1.0 不稳定且不能用于生产.因此,HBase 建议用户避免使用本版本.详情: release announcement for Hadoop 3.1.0.
  • 更换hbase lib目录中依赖的hadoop jar
    • 因为 hbase 依赖于 hadoop,并且 hadoop jar 存在 lib 目录下。这些的 jar 仅在独立模式下使用。在分布式模式下,集群上的 Hadoop 版本与 HBase 下的版本匹配是 至关重要的。将 hbase lib 目录中的 hadoop jar 替换为集群上运行的版本中的 hadoop jar,以避免版本不匹配问题。确保在整个集群中替换 hbase 下的 jar。Hadoop 版本不匹配问题有多种表现形式。如果 HBase 出现挂起,请检查是否不匹配。
  • hdfs-site.xml:dfs.datanode.max.transfer.threads
    • HDFS DataNode 在任何时候都会有一个文件数上限。在进行任何加载之前,请确保您已经配置了 Hadoop 的 conf/hdfs-site.xml,并将该dfs.datanode.max.transfer.threads值设置为至少如下的值(修改配置后,需重启HDFS):
<property>
  <name>dfs.datanode.max.transfer.threads</name>
  <value>4096</value>
</property>
    • 没有这个配置就会造成奇怪的故障。其中一种表现是缺失区块。例如:
10/12/08 20:10:31 INFO hdfs.DFSClient: Could not obtain block
          blk_XXXXXXXXXXXXXXXXXXXXXX_YYYYYYYY from any node: java.io.IOException: No live nodes
          contain current block. Will get new block locations from namenode and retry...

4. Zookeeper

  • 必须Zookeeper 3.4.x或兼容版本

5. HBase不同部署模式配置

  • 无论您的模式如何,您都需要通过编辑 HBase conf 目录中的文件来配置 HBase 。至少,您必须编辑 conf/hbase-env.sh 来告诉 HBase 要使用哪个 java。在这个文件中,你设置了 HBase 环境变量,比如JVM的 heapsize 和其他选项,日志文件的首选位置等等。设置 JAVA_HOME 以指向你的 java 安装的根目录
  • Standalone部署(本地文件系统):
    • 在独立模式下,HBase 不使用 HDFS,而是使用本地文件系统,是在同一个 JVM 中运行所有 HBase 守护进程和本地 ZooKeeper。ZooKeeper 绑定到一个众所周知的端口,通过该端口,客户端可以和 HBase 进行通信。
  • Standalone部署(HDFS):
    •  配置hbase-site.xml,设置 hbase.rootdir 以指向 HDFS 实例中的某个目录,然后将 hbase.cluster.distributed 设置为 false。例如:
<configuration>
  <property>
    <name>hbase.rootdir</name>
    <value>hdfs://namenode.example.org:8020/hbase</value>
  </property>
  <property>
    <name>hbase.cluster.distributed</name>
    <value>false</value>
  </property>
</configuration>
  • 分布式部署(伪分布式):
    • 伪分布式模式的 HBase 就是在单个主机上运行的完全分布式模式(所有服务进程都在单个节点上运行)。使用此 HBase 配置仅进行测试和原型设计。
    • 伪分布式模式可以针对本地文件系统运行,也可以针对 Hadoop 分布式文件系统(HDFS) 的实例运行。完全分布式模式只能在 HDFS 上运行。
    • 配置hbase-site.xml,将hbase.cluster.distributed 设置为true
  <property>
    <name>hbase.cluster.distributed</name>
    <value>true</value>
  </property>
  • 分布式部署(完全分布式):
    • 对于生产环境,建议使用分布式模式。在分布式模式下,HBase 守护进程的多个实例在集群中的多个服务器上运行。
    • 修改hbase-site.xml,完全分布式的配置要求您将hbase.cluster.distributed 属性设置为 true。通常情况下,hbase.rootdir被配置为指向高可用性的 HDFS。此外,集群还配置了以多个群集节点成为 RegionServer、ZooKeeper QuorumPeers 和备份 HMaster 服务器:
<configuration>
  <property>
    <name>hbase.rootdir</name>
    <value>hdfs://namenode.example.org:8020/hbase</value>
  </property>
  <property>
    <name>hbase.cluster.distributed</name>
    <value>true</value>
  </property>
  <property>
    <name>hbase.zookeeper.quorum</name>
    <value>node-a.example.com,node-b.example.com,node-c.example.com</value>
  </property>
</configuration>
    • 修改conf/regionservers,配置regionserver节点列表,这些节点需要安装HBase,并且与主服务器相同的conf目录配置内容:
node-a.example.com
node-b.example.com
node-c.example.com
    • 修改conf/backup-masters,配置运行备份master实例的节点列表
node-b.example.com

6. HDFS客户端配置

  • 值得注意的是,如果您在 Hadoop 集群上进行了 HDFS 客户端配置更改(例如,HDFS 客户端的配置指令),而不是服务器端配置,则必须使用以下方法之一来启用 HBase 以查看和使用这些配置更改:
    • 在 hbase-env.sh 中添加一个指向你HADOOP_CONF_DIR的HBASE_CLASSPATH环境变量
    • 在 ${HBASEHOME}/conf 下添加一个 hdfs-site.xml(或 hadoop-site.xml)或软链接
    • 只有一小部分 HDFS 客户端配置,请将它们添加到 hbase-site.xml
  • 这种 HDFS 客户端配置的一个例子是dfs.replication。例如,如果希望以 5 的复制因子运行,则 HBase 将创建缺省值为 3 的文件,除非您执行上述操作以使配置可用于 HBase。

7. HBase默认配置参数详解(hbase-default.xml -> hbase-site.xml)

  • 这些配置修改需要重启HBase集群
  • hbase.tmp.dir

    • 这是配置本地文件系统上的临时目录。将此设置更改为指向比“/tmp”更持久的位置,这是 java.io.tmpdir 的常见解决方案,因为在重新启动计算机时清除了“/tmp”目录
    • 默认: ${java.io.tmpdir}/hbase-${user.name}
  • hbase.rootdir

    • 这个目录是region servers共享的目录,用于HBase数据持久化存储。
    • 该 URL 应该是“完全限定的”以包括文件系统的 scheme。例如,要指定 HDFS 实例的”/hbase”目录,namenode 运行在 namenode.example.org 的 9000 端口,请将此值设置为:hdfs://namenode.example.org:9000 / hbase。默认$ {hbase.tmp.dir},但通常会修改这个配置,否则所有的数据在计算机重启后会丢失
    • 默认: ${hbase.tmp.dir}/hbase
  • hbase.cluster.distributed

    • 群集部署模式是否为分布式。对于standalone,值为 false,对于分布式模式,值为 true。如果为 false,启动将在一个 JVM 中一起运行所有 HBase 和 ZooKeeper 守护程序
    • 默认: false
  • hbase.zookeeper.quorum

    • 使用逗号分隔的 ZooKeeper 集群服务器列表(这个配置应该被命名为 hbase.zookeeper.ensemble)。例如,“host1.mydomain.com,host2.mydomain.com,host3.mydomain.com”。默认情况下,对于本地standalone和伪分布式部署模式,将其设置为 localhost。对于完全分布式安装,应将其设置为 ZooKeeper 集成服务器的完整列表。如果在 hbase-env.sh 中设置了 HBASE_MANAGES_ZK参数为true, hbase 将ZooKeeper作为集群的一部分进行启动停止管理。对于客户端,我们将把这个集合成员的列表,并把它与 hbase.zookeeper.property.clientPort 配置放在一起。并将其作为 connectString 参数传递给 zookeeper 构造函数。
    • 默认: localhost
  • zookeeper.recovery.retry.maxsleeptime

    • 用于设置在重试zooKeeper的某些操作时的最大等待时间,似乎是出于某些原因zooKeeper的某些操作失败了,在一段时间以后zooKeeper会有重试该操作的机制,并且这个重试等待时间并不是恒定的,而是随着失败的次数逐渐增长的。HBASE为了防止这个时间无限制地增长,就设置了这个最大等待时间。即zooKeeper操作重试等待时间最长不超过这个项设置的时间。其单位是毫秒。
    • 默认: 60000(1分钟)
  • hbase.local.dir

    • 将本地文件系统上的目录用作本地存储
    • 默认: ${hbase.tmp.dir}/local/
  • hbase.master.port

    • HBase Master绑定端口
    • 默认: 16000
  • hbase.master.info.port

    • HBase Master Web UI绑定端口,如果不想运行web ui,将其设置为-1
    • 默认: 16010
  • hbase.master.info.bindAddress

    • HBase Master Web UI绑定地址
    • 默认: 0.0.0.0
  • hbase.master.logcleaner.plugins

    • 清理WAL预写日志的插件列表,逗号分隔,被LogsCleaner服务调用的BaseLogCleanerDelegate,可以自定义,顺序执行,因此将能清理掉最多文件的放在前面。要实现您自己的 BaseLogCleanerDelegate,只需将其放入 HBase 的classpath中,并在此添加完全限定的类名。应该始终将默认的日志清理插件添加上。
    • 默认: org.apache.hadoop.hbase.master.cleaner.TimeToLiveLogCleaner, org.apache.hadoop.hbase.master.cleaner.TimeToLiveProcedureWALCleaner
  • hbase.master.logcleaner.ttl

    • WAL预写日志 在归档({hbase.rootdir} / oldWALs)目录中保留多久,之后将由Master线程清除。该值以毫秒为单位。
    • 默认: 600000(10分钟)
  • hbase.master.procedurewalcleaner.ttl

    • WAL保留在{hbase.rootdir}/oldWALs/masterProcedureWALs目录中的时间,过期后会被Master线程清除。该值以毫秒为单位。
    • 默认: 604800000(7天)
  • hbase.master.hfilecleaner.plugins

    • 由 HFileCleaner 服务调用的 BaseHFileCleanerDelegate 的逗号分隔列表。这些 HFile 清理器按顺序调用,因此将能清理掉最多文件的放在前面。要实现您自己的 BaseHFileCleanerDelegate,只需将其放入 HBase 的类路径中,并在此添加完全限定的类名。应该始终将默认的日志清理插件添加上。
    • 默认: org.apache.hadoop.hbase.master.cleaner.TimeToLiveHFileCleaner
  • hbase.master.infoserver.redirect

    • 控制Master主机是否监听Master主机上的网页端口并将来自该端口的请求共享给集群上的所有主机。
    • 默认: true
  • hbase.master.fileSplitTimeout

    • 表示region分割时,做文件分割操作时最大等待时间,超过这一时间设定后若分割仍未完成,则会放弃分割操作。这条属性是HBASE1.x版本上的 ‘hbase.regionserver.fileSpliTimeout’属性,出于该分割操作目前是在Master主机侧完成的,因此将这条属性改名成 ‘hbase.master.fileSplitTimeout’。如果在HBASE系统上同时设定了这两条属性,则以 ‘hbase.master.fileSplitTimeout’ 属性为准。
    • 默认: 600000
  • hbase.regionserver.port

    • HBase RegionServer 绑定的端口。
    • 默认: 16020
  • hbase.regionserver.info.port

    • HBase RegionServer Web UI 的端口,如果不希望 RegionServer UI 运行,请将其设置为-1
    • 默认: 16030
  • hbase.regionserver.info.bindAddress

    • HBase RegionServer Web UI 的绑定访问地址
    • 默认: 0.0.0.0
  • hbase.regionserver.info.port.auto

    • Master 或 RegionServer UI 是否应搜索要绑定的端口。如果 hbase.regionserver.info.port 已被使用,则启用自动端口搜索。对于测试很有用,默认关闭
    • 默认: false
  • hbase.regionserver.handler.count

    • 在 RegionServers 上启动 RPC Listener 实例的数量(RegionServer处理读写RPC请求的线程数?)。Master 使用相同的属性来处理master handler的数量。太多的handler可能会适得其反。使其成为 CPU 数量的倍数。如果主要是只读的,handler的数量接近 CPU数量表现的更好。可以从 CPU 数量的两倍开始,并从这个量开始调整
    • response time = queue time + service time,如果用户请求排队时间很长,就要适当调大hbase.regionserver.handler.count
    • 当请求内容很大(上MB,比如大的put、使用缓存的scans)的时候,如果该值设置过大则会占用过多的内存,导致频繁的GC,或者出现OutOfMemory,因此该值不是越大越好。如果单次请求内存消耗低,并且TPS要求高的场景,可以将其适当调大。
    • 默认: 30
  • hbase.ipc.server.callqueue.handler.factor

    • 确定handler对应任务队列数量的因子。0为所有的handler共用一个queue; 1为一个handler一个queue; 0-1之间,比如0.5为两个handler共享一个queue… ,计算公式为:handler.count * 0.1 = 30 * 0.1 = 3个队列
    • 影响:如果配置一个handler一个queue,一个handler只处理他负责的queue,则有长时间运行task的队列,即使有空闲的handler也无法处理,只能由负责他的handler独自处理
    • 默认: 0.1
  • hbase.ipc.server.callqueue.read.ratio

    • 服务器端设置读写业务分别占用的队列百分比以及handler百分比。假如该值为0.5,表示读写各占一半队列,同时各占一半handler。小于 0.5 的值意味着读取队列将比写入队列更少,大于0.5表示读取队列比写入队列更多。值为0表示不分割调用队列,这意味着读取和写入请求将被推送到相同的一组队列中。值为1.0表示只有1个写入队列,其他都为读取队列。
    • 示例:假设调用队列的总数为 10,则 read.ratio 为 0 意味着:10 个队列将同时包含读/写请求。0.3 的比例意味着:3 个队列将只包含读取请求,7 个队列将只包含写入请求。0.5 的 read.ratio 表示:5 个队列将只包含读取请求,5 个队列将只包含写入请求。0.8 的 read.ratio 意味着:8 个队列将只包含读取请求,2 个队列将只包含写入请求。1 的 read.ratio 表示:9 个队列将只包含读取请求,1 个队列将只包含写入请求。
    • 默认: 0
  • hbase.ipc.server.callqueue.scan.ratio

    • 服务器端为了将get和scan隔离设置了该参数。
    • 考虑到读取的调用队列的数量(根据调用队列的总数乘以 callqueue.read.ratio 计算),scan.ratio 属性将把读取的调用队列拆分为小读取和长读取队列。低于 0.5 的值意味着长读队列比短读队列少。值为 0.5 意味着将有相同数量的短读取和长读取队列。大于 0.5 的值意味着将会有比长读取队列更多的长读取队列。值 0 或 1 表示使用同一组队列进行获取和扫描。示例:给定读取调用队列的总数为 8,scan.ratio 为 0 或 1 意味着:8 个队列将包含长读请求和短读请求。0.3 的 scan.ratio 表示:2 个队列只包含长读请求,6 个队列只包含短读请求。0.5 的 scan.ratio 表示:4 个队列只包含长读请求,4 个队列只包含短读请求。0.8 的 scan.ratio 意味着:6 个队列只包含长读请求,2 个队列只包含短读请求。
    • 默认: 0
  • hbase.regionserver.msginterval

    • Master 或 RegionServer UI 是否应搜索要绑定的端口。如果 hbase.regionserver.info.port 已被使用,则启用自动端口搜索。对于测试很有用,默认关闭
    • 默认: false


/* 本文属于原创文章,转载请注明作者和出处 quarterback.cn,请勿用于任何商业用途 */




喜欢 (0)or分享 (0)
Quarterback.cn 打赏作者
发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址