mysql性能诊断的那些事儿
一、基准测试
在做mysql性能压测前,我们需要根据相应的业务情况 对mysql做一个基准性测试。
目的:就是分析在当前的配置下(包括硬件配置、OS、数据库设置等),数据库的性能表现,从而找出MySQL的性能阈值,并根据实际系统的要求调整配置。
说明:sysbench的测试只是基准测试,并不能代表实际企业环境下的性能指标。
测试工具:sysbench
安装部署:
unzip sysbench-master.zip #解压源码
yum -y install make automake libtool pkgconfig libaio-devel #下载依赖包
cd sysbench-master
sh autogen.sh
编译:
./configure --with-mysql-includes=/usr/local/mysql/include --with-mysql-libs=/usr/local/mysql/lib #根据安装的MySQL的位置,设置目录位置
make
make install
这样安装之后使用sysbench命令时会报错。
[root@test3 sysbench-master]# sysbench --version
sysbench: error while loading shared libraries: libmysqlclient.so.20: cannot open shared object file: No such file or directory
解决办法:
在/etc/profile文件中加入一行:
export LD_LIBRARY_PATH=/usr/local/mysql/lib
source /etc/profile
命令可以正常使用
[root@test3 sysbench-master]# sysbench --version
使用说明:
sysbench --help
Usage:
sysbench [options]... [testname] [command]
Commands implemented by most tests: prepare run cleanup help
General options:
--threads=N number of threads to use [1] #线程的数量,默认是1
--events=N limit for total number of events [0] #限制的最大事件数量,默认是0,不限制
--time=N limit for total execution time in seconds [10] #整个测试执行的时间
--warmup-time=N #在进行基准测试多少秒之后启用统计信息--forced-shutdown=STRING #超过--time时间限制后,强制中断,默认是【off】
--thread-stack-size=SIZE size of stack per thread [64K]
--thread-init-timeout=N wait time in seconds for worker threads to initialize [30]
--rate=N average transactions rate. 0 for unlimited rate [0]
--report-interval=N #打印出中间的信念,N表示每隔N秒打印一次,0表示禁用--report-checkpoints=[LIST,...] #转储完全统计信息并在指定时间点复位所有计数器,参数是逗号分隔值的列表,表示从必须执行报告检查点的测试开始所经过的时间(以秒为单位)。 默认情况下,报告检查点处于关闭状态[off]。--debug[=on|off] print more debugging info [off]
--validate[=on|off] #在可能情况下执行验证检查,默认是[off]
--help[=on|off] print help and exit [off]
--version[=on|off] print version and exit [off]
--config-file=FILENAME File containing command line options
--luajit-cmd=STRING perform LuaJIT control command. This option is equivalent to 'luajit -j'. See LuaJIT documentation for more information
帮助菜单
Compiled-in tests:
fileio - File I/O test
cpu - CPU performance test
memory - Memory functions speed test
threads - Threads subsystem performance test
mutex - Mutex performance test
测试oltp命令帮助:
[root@db-master ~]# sysbench --test=oltp help
测试IO
sysbench fileio help #查看IO测试的文档
fileio options:
--file-num=N number of files to create [128]
--file-block-size=N block size to use in all IO operations [16384]
--file-total-size=SIZE total size of files to create [2G]
--file-test-mode=STRING test mode {seqwr, seqrewr, seqrd, rndrd, rndwr, rndrw}
--file-io-mode=STRING file operations mode {sync,async,fastmmap,slowmmap} [sync]
--file-async-backlog=N number of asynchronous operatons to queue per thread [128]
--file-extra-flags=STRING additional flags to use on opening files {sync,dsync,direct} []
--file-fsync-freq=N do fsync() after this number of requests (0 - don't use fsync()) [100]
--file-fsync-all=[on|off] do fsync() after each write operation [off]
--file-fsync-end=[on|off] do fsync() at the end of test [on]
--file-fsync-mode=STRING which method to use for synchronization {fsync, fdatasync} [fsync]
--file-merged-requests=N merge at most this number of IO requests if possible (0 - don't merge) [0]
--file-rw-ratio=N reads/writes ratio for combined test [1.5]
参数详解:
--file-num=N 代表生成测试文件的数量,默认为128。
--file-block-size=N 测试时所使用文件块的大小,如果想磁盘针对innodb存储引擎进行测试,可以将其设置为16384,即innodb存储引擎页的大小。默认为16384。
--file-total-size=SIZE 创建测试文件的总大小,默认为2G大小。
--file-test-mode=STRING 文件测试模式,包含:seqwr(顺序写), seqrewr(顺序读写), seqrd(顺序读), rndrd(随机读), rndwr(随机写), rndrw(随机读写)。
--file-io-mode=STRING 文件操作的模式,sync(同步),async(异步),fastmmap(快速mmap),slowmmap(慢速mmap),默认为sync同步模式。
--file-async-backlog=N 对应每个线程队列的异步操作数,默认为128。
--file-extra-flags=STRING 打开文件时的选项,这是与API相关的参数。
--file-fsync-freq=N 执行fsync()函数的频率。fsync主要是同步磁盘文件,因为可能有系统和磁盘缓冲的关系。 0代表不使用fsync函数。默认值为100。
--file-fsync-all=[on|off] 每执行完一次写操作,就执行一次fsync。默认为off。
--file-fsync-end=[on|off] 在测试结束时执行fsync函数。默认为on。
--file-fsync-mode=STRING文件同步函数的选择,同样是和API相关的参数,由于多个操作系统对于fdatasync支持不同,因此不建议使用fdatasync。默认为fsync。
--file-merged-requests=N 大多情况下,合并可能的IO的请求数,默认为0。
--file-rw-ratio=N 测试时的读写比例,默认时为1.5,即可3:2
sysbench fileio --file-num=10 --file-total-size=50G prepare
10 files, 5242880Kb each, 51200Mb total
Creating files for the test...
Extra file open flags: (none)
Creating file test_file.0
Creating file test_file.1
Creating file test_file.2
Creating file test_file.3
Creating file test_file.4
Creating file test_file.5
Creating file test_file.6
Creating file test_file.7
Creating file test_file.8
Creating file test_file.9
53687091200 bytes written in 489.55 seconds (104.59 MiB/sec).
#这里给出一个每秒写入的数据量104.59MB/s, 这里的写入是顺序写入的,表示磁盘的吞吐量为104.59MB/s。
【一般对顺序的读写称为吞吐量,对随机的IO使用IOPS来表示】
#这里进行随机读写测试
sysbench fileio --file-num=10 --file-total-size=50G --file-block-size=16384 --file-test-mode=rndrw --file-io-mode=sync --file-extra-flags=direct --time=100 --threads=16 --report-interval=10 run
输出结果:
[ 10s ] reads: 3.24 MiB/s writes: 2.16 MiB/s fsyncs: 34.08/s latency (ms,95%): 80.025 #每隔10s输出一次报告
[ 20s ] reads: 3.49 MiB/s writes: 2.32 MiB/s fsyncs: 36.70/s latency (ms,95%): 73.135
[ 30s ] reads: 3.45 MiB/s writes: 2.29 MiB/s fsyncs: 37.00/s latency (ms,95%): 75.817
[ 40s ] reads: 3.43 MiB/s writes: 2.29 MiB/s fsyncs: 36.00/s latency (ms,95%): 75.817
[ 50s ] reads: 3.57 MiB/s writes: 2.38 MiB/s fsyncs: 37.40/s latency (ms,95%): 73.135
[ 60s ] reads: 3.08 MiB/s writes: 2.06 MiB/s fsyncs: 32.30/s latency (ms,95%): 86.002
[ 70s ] reads: 3.41 MiB/s writes: 2.27 MiB/s fsyncs: 36.40/s latency (ms,95%): 75.817
[ 80s ] reads: 3.47 MiB/s writes: 2.31 MiB/s fsyncs: 36.20/s latency (ms,95%): 73.135
[ 90s ] reads: 3.46 MiB/s writes: 2.31 MiB/s fsyncs: 36.20/s latency (ms,95%): 77.194
[ 100s ] reads: 3.10 MiB/s writes: 2.07 MiB/s fsyncs: 33.50/s latency (ms,95%): 75.817
Throughput:
read: IOPS=215.57 3.37 MiB/s (3.53 MB/s) #通常的机械磁盘随机IOPS也就是200多一点。
write: IOPS=143.72 2.25 MiB/s (2.35 MB/s) #随机写入的速度明显要低很多。
fsync: IOPS=37.13
Latency (ms):
min: 0.08
avg: 40.51
max: 1000.31
95th percentile: 77.19
sum: 1601329.71
#随机写大概是2.10M/s,文件块的大小为16KB,可以大概估计磁盘转速: 2.10*1024KB*60s/16KB=7560n/m, 大概就是7500转每分
清理数据:
sysbench fileio --file-num=10 --file-total-size=50 cleanup
对mysql事务型OLTP的测试:
prepare准备阶段
对于mysql的OLTP测试,和file一样,同样需要经历prepare,run,cleanup三个阶段。prepare阶段会在数据库中产生一张指定行数的表,默认表在sbtest架构下,表名为
sbtest(sysbench默认生成表的存储引擎为innodb),如创建一张6000万条记录的表:
[root@db-master sysbench]# sysbench --test=oltp --oltp-table-size=60000000 --db-driver=mysql --mysql-socket=/data/mysqlsoft3307/mysql.sock --mysql-user=dba_manager --mysql-password='111111' --mysql-db=test prepare
接下来对上面产生的表进行oltp的测试:
[root@db-master sysbench]# sysbench --test=oltp --oltp-table-size=80000000 --oltp-read-only=off --init-rng=on --num-threads=16 --max-requests=0 --oltp-dist-type=uniform --max-time=3600 --mysql-user=dba_manager --mysql-password='111111' --db-driver=mysql --mysql-socket=/data/mysqlsoft3307/mysql.sock run > result.log
参数说明:
--max-time=3600 指定测试时长为1小时
--mysql-db=test 指定测试的数据库名
[root@db-master sysbench]# cat result.log
OLTP test statistics:
queries performed:
read: 137346874
write: 49052449
other: 19620980
total: 206020303
transactions: 9810489 (2725.13 per sec.)
deadlocks: 2 (0.00 per sec.)
read/write requests: 186399323 (51777.50 per sec.)
other operations: 19620980 (5450.26 per sec.)
transactions代表测试结果的评判标准即TPS,上述测试结果是 2725.13 per sec.
二、Mysql参数
查看 mysql的配置文件 my.ini
Mysql的 几个重要参数:
nnodb_buffer_pool_size(缓冲池大小) 小于等于1GB时默认1GB,大于1GB时 默认为8GB。
innodb_buffer_pool_chunk_size(定义InnoDB缓冲池大小调整操作的块大小)
innodb_buffer_pool_instances(InnoDB缓冲池划分为的区域数)
innodb_buffer_pool_size必须为innodb_buffer_pool_instances的倍数
innodb_buffer_pool_instances参数的作用,要启用多个缓冲池实例,将innodb_buffer_pool_instances配置选项设置为大于1(默认)的值,最大为64(最大)
pool-size可以缓存索引和行数据,值越大,IO读写就越少;单纯的做数据库服务,该参数可以设置到电脑物理内存的80%。
innodb_buffer_pool_size=2G
innodb_buffer_pool_instances=1
三、Mysql性能需要监控的指标:
|
类型 |
监控参数项 |
解析 |
|
资源监控 |
磁盘空间 |
单位:MByte。 |
|
IOPS |
实例的每秒I/O请求次数,单位:次/秒。 |
|
|
连接数 |
实例当前总连接数,包括活跃连接数和总连接数。 |
|
|
CPU内存使用率 |
实例的CPU和内存使用率(不含操作系统占用)。 |
|
|
网络流量 |
实例每秒钟的输入、输出流量,单位:KB。 |
|
|
引擎监控 |
TPS |
平均每秒事务数 |
|
QPS |
平均每秒SQL语句执行次数 |
|
|
InnoDB缓存读命中率、使用率、脏块率 |
InnoDB缓冲池的读命中率、使用率以及缓冲池脏块的百分率。 |
|
|
InnoDB读写量 |
InnoDB每秒读取和写入的数据量,单位:KB。 |
|
|
InnoDB缓存请求次数 |
InnoDB每秒钟的读取和写入的次数。 |
|
|
InnoDB日志读/写/fsync |
InnoDB每秒向日志文件的物理写入次数、日志写请求、向日志文件完成的fsync写数量。 |
|
|
临时表数量 |
数据库执行SQL语句时在硬盘上自动创建的临时表的数量。 |
|
|
MySQL_COMDML |
数据库每秒SQL语句执行次数,包括的类型如下:
|
|
|
MySQL_RowDML |
InnoDB每秒钟操作执行次数,包括:
|
|
|
MyISAM读写次数 |
MyISAM每秒从缓冲池中的读、写次数和每秒钟从硬盘上的读、写次数。 |
|
|
MyISAM Key Buffer读/写/利用率 |
MyISAM每秒的Key Buffer读命中率、写命中率、使用率。 |
|
|
MySQL_ThreadStatus线程状态 |
包括活跃线程(Threads_running)和线程连接数(Threads_connected)。 |
|
|
InnoDB每秒写入redo log日志量 |
记录了每秒写入到redo log的日志量。单位:bytes。 |
慢SQL定位的 sql语句:
① 定位效率低的查询:
show processlist;
show full processlist;
② QPS高导致CPU使用率高定位 的执行语句:
查询执行时间通常比较短,show processlist;命令或实例会话中可能会不容易捕捉到当前执行的查询。
explain [$SQL]
说明:[$SQL]为有性能问题的SQL查询语句。
四、Mysql可能存在的问题汇总
1. MySQL慢SQL问题
(1) SQL异常
SQL异常的原因很多,例如库表结构设计不合理、索引缺失、扫描行数太多等
定位:“可查看慢SQL的执行耗时、执行次数等信息
(2) 实例瓶颈
u 业务量持续增长而没有扩容。
u 硬件老化,性能有损耗。
u 数据量一直增加,数据结构也有变化,导致原来不慢的SQL变成慢SQL。
判断实例是否到达瓶颈,较好的方法是先测试出实例的性能基准值,例如用SysBench进行基准测试,复杂场景下的QPS和TPS很少会超过基准值。
在资源监控内可以查看实例的资源使用情况。如果资源使用率各项指标都接近100%,可能是实例到达了瓶颈。
(3) 版本升级
实例升级版本可能会导致SQL执行计划发生改变,可参考官方文档:https://dev.mysql.com/doc/refman/5.6/en/explain-output.html?spm=a2c4g.11186623.0.0.53a9380byLdcTq#explain-join-types
根据执行计划分析索引使用情况、扫描的行数等,预估查询效率,重构SQL语句、调整索引,提升查询效率。
explain [$SQL]
说明:[$SQL]为有性能问题的SQL查询语句。
索引:
从最好到最差依次是:
system>const>eq_ref>ref>range>index>ALL
(4) 参数设置不当
参数innodb_buffer_pool_instances、join_buffer_size等设置不当会导致性能变慢。
(5) 缓存失效
缓存可以很好地承担大量查询,但是并不能保证缓存命中率100%,如果缓存失效,也会有大量的查询路由到数据库端,导致性能下降。
定位方法:在引擎监控内可以查看实例的缓存命中率、QPS、TPS等。
可以使用Thread Pool、Fast Query Cache、自动SQL限流等功能提高性能。
(6) 批量操作
如果有大批量的数据导入、删除、查询操作,会导致SQL执行变慢。
定位方法:可以从磁盘空间、SQL洞察或者慢查询里找到对应语句。例如查看Binlog大小,正常情况单个Binlog大小是500 MB,如果有超过500 MB的,可以查看是否有异常。
在资源监控和引擎监控内可以查看实例的磁盘空间、IOPS、事务等情况。
(7) 未关闭事务
如果某个任务突然变慢,查看CPU和IOPS的使用率并不高,而且活跃会话持续增多,通常是因为存在未关闭的事务。
定位方法:检查导致事务冲突的锁并中止对应的SQL语句。
(8) 定时任务
如果实例负载随时间有规律性变化,可能是存在定时任务。
处理方法:调整定时任务的执行时间,建议在业务低峰期执行。
2. 内存使用问题
实例内存使用率和缓冲池命中率是MySQL的关键指标。
如果内存使用率过高,会有内存耗尽风险;
如果缓冲池命中率低,大量的数据页无法命中缓冲池的数据页,需要从磁盘读取数据,造成I/O吞吐增加和延迟增加。
定位问题方法:performance_schema
n 要在实例启动时开启内存检测,请修改my.cnf文件,添加performance_schema = on,然后重启实例即生效。
n 要在实例运行中开启内存检测,请执行如下命令:
update performance_schema.setup_instruments set enabled = 'yes' where name like 'memory%';。
内存高的常见原因:
通常InnoDB Buffer Pool的内存占用是最大的,Buffer Pool的内存占用上限受到Buffer Pool配置参数的限制,但是还有很多内存是在请求执行中动态分配和调整的,例如内存临时表消耗的内存、prefetch cache、table cache、哈希索引、行锁对象等。
(1) 多语句问题
MySQL支持将多个SQL语句用英文分号(;)分隔,然后一起发给MySQL,MySQL会逐条处理SQL,但是某些内存需要等到所有的SQL执行结束才释放。
这种multiple statements的发送方式,如果一次性发送的SQL非常多,例如达到数百兆,SQL实际执行过程中各种对象分配累积消耗的内存非常大,很有可能导致MySQL进程内存耗尽。
(2) 缓冲池(Buffer Pool)问题
所有表的数据页都存放在缓冲池中,查询执行的时候如果需要的数据页直接命中缓冲池,就不会发生物理I/O,SQL执行的效率较高,缓冲池采用LRU算法管理数据页,所有的脏页放到Flush List链表中。
Buffer Pool相关的常见问题:
l 数据页预热不足导致查询的延迟较高。通常发生在实例重启、冷数据读取或缓冲池命中率较低的场景,建议升级实例规格或大促前预热数据。
l 脏页累积太多。当未刷新脏页的最旧LSN和当前LSN的距离超过76%时,会触发用户线程同步刷新脏页,导致实例性能严重下降。优化方式是均衡写入负载、避免写入吞吐过高、调整刷新脏页参数或升级实例规格等。
l 高内存实例的参数innodb_buffer_pool_instances设置较小。高QPS负载情况下,缓冲池的锁竞争会比较激烈。建议高内存的实例将参数innodb_buffer_pool_instances设置为8或16,甚至更高。
(3) 临时表
内存临时表大小受到参数tmp_table_size和max_heap_table_size限制,超过限制后将转化为磁盘临时表,如果瞬间有大量的连接创建大量的临时表,可能会造成内存突增。MySQL 8.0实现了新的temptable engine,所有线程分配的内存临时表大小之和必须小于参数temptable_max_ram,temptable_max_ram默认为1 GB,超出后转换为磁盘临时表。
(4) 其他原因
如果实例内表特别多或QPS很高,Table Cache可能也会消耗内存,建议实例避免创建太多表或设置参数table_open_cache过大。
自适应哈希索引占用的内存默认是Bufffer Pool的1/64。如果查询或写入长度非常大的Blob大字段,会对大字段动态分配内存,也会造成内存增加。
3. MYSQL空间不足问题
登录数据库后执行命令show table status like '<表名>';查看表空间
(1) 索引太多导致空间不足
通常表上除了主键索引,还存在二级索引,二级索引越多,整个表空间越大。
处理方法:优化数据结构,减少二级索引数量。
(2) 大字段导致空间不足
如果表结构定义中有blob、text等大字段或很长的varchar字段,也会占用更大的表空间。
处理方法:将数据压缩以后再插入。
(3) 空闲表空间太多导致空间不足
空闲表空间太多是指InnoDB表的碎片率高。InnoDB是按页(Page)管理表空间的,如果Page写满记录,然后部分记录又被删除,后续这些删除的记录位置又没有新的记录插入,就会产生很多空闲空间。
定位:可以通过命令show table status like '<表名>';查看表上空闲的空间。
处理方法:如果空闲空间过大,可以执行命令optimize table <表名>;整理表空间。
(4) 临时表空间过大导致空间不足
u 半连接(Semi-join)、去重(distinct)、不走索引的排序等操作,会创建临时表,如果涉及的数据量过多,可能导致临时表空间特别大。
u DDL操作重建表空间时,如果表特别大,创建索引排序时产生的临时文件也会特别大。RDS MySQL 5.6和5.7不支持即时增加字段,很多DDL是通过创建新表实现的,DDL执行结束再删除旧表,DDL过程中会同时存在两份表。
处理方法:
u 可以查看执行计划,确认是否包含Using Temporary。
u 大表DDL需要注意实例的空间是否足够,不足的话需要提前升级存储空间。
4. MySQL I/O高问题
(1) 高吞吐导致实例I/O高
如果表上有很多索引或大字段,频繁地更新、删除、插入,读取数据和刷新脏页时会有大量的I/O。
建议降低读写频率或升级实例规格、优化刷新脏页相关的参数来解决高吞吐问题。和刷新脏页相关的参数如下:
- innodb_max_dirty_pages_pct:缓冲池中允许的脏页百分比,默认值为75。
- innodb_max_dirty_pages_pct_lwm:脏页比例的低水位线。当缓冲池里的脏页比例超过这个低水位线时,能够触发脏页预刷功能,逐步控制脏页比例。默认值为0,表示禁用该功能。
说明 innodb_max_dirty_pages_pct_lwm的值不能大于innodb_max_dirty_pages_pct的值,否则会强制修改为与innodb_max_dirty_pages_pct相同。
- innodb_io_capacity:设置InnoDB后台任务每秒执行的I/O操作数的上限,影响刷新脏页和写入缓冲池的速率。默认值为20000。
- innodb_io_capacity_max:如果刷新操作过于落后,InnoDB可以超过innodb_io_capacity的限制进行刷新,但是不能超过本参数的值。默认值为40000。
(2) 临时表导致实例I/O高
如果临时目录很大,可能存在慢SQL排序、去重等操作导致创建很大的临时表。临时表写入也会造成I/O增加。
利用 mysqladmin 来监控此项
如果用了阿里云的mysql 则在 自治服务 > 性能趋势页面,单击性能趋势页签,查看tmp或other目录大小。
(3) 读取冷数据导致实例I/O高
如果SQL查询或修改的数据不在缓冲池(Buffer Pool),则需要从存储中读取,可能会产生大量的I/O吞吐。
阿里云控制台的自治服务 > 性能趋势页面,单击性能趋势页签,查看Buffer Pool命中率。
(4) DDL语句导致实例I/O高
DDL语句可能会重建表空间,期间会扫描全表数据、创建索引排序、刷新新表产生的脏页,这些都会导致大量的I/O吞吐。另外一种场景是删除大表造成的I/O抖动。


处理方法:异步删除大文件。
(5) 大事务写Binlog导致实例I/O高
事务只有在提交时才会写Binlog文件,如果存在大事务,例如一条Delete语句删除大量的行,可能会产生几十GB的Binlog文件,Binlog文件刷新到磁盘时,会造成很高的I/O吞吐。
处理方法:建议尽量将事务拆分,避免大事务和降低刷新磁盘频率。
5. MySQL活跃线程数高
活跃线程数或活跃连接数是衡量MySQL负载状态的关键指标,通常来说一个比较健康的实例活跃连接数应该低于10,高规格和高QPS的实例活跃连接数可能20、30,如果出现几百、上千的活跃连接数,说明出现了SQL堆积和响应变慢,严重时会导致实例停止响应,无法继续处理SQL请求。
(1) 活跃线程数
如果线程数过高,说明实例会话有阻塞。
(2) 慢SQL堆积问题
如果通过监控发现活跃线程数升高,首先通过show processlist;命令查看是否有慢SQL。如果有很多扫描行数太多的SQL,容易导致活跃连接数升高。
处理方法:使用SQL限流 或结束会话,降低慢SQL的影响。
(3) 表缓存(Table Cache)问题
Table Cache不足时,会导致大量SQL处于Opening table状态,在QPS过高或者表很多的场景容易出现。
处理方法:
将参数table_open_cache(不需要重启实例)和table_open_cache_instances(需要重启实例)调大
(4) 元数据锁(MDL)问题
出现MDL锁时,会导致大量SQL处于Waiting for table metadata lock的状态,在DDL prepare和commit阶段,DDL语句需要获取MDL锁,如果表上有未提交事务或慢SQL,会阻塞DDL操作,DDL操作又会阻塞其他的SQL,最终导致活跃线程数升高。
处理方法:中止未提交事务、慢SQL或正在执行的DDL都可以解决问题。
行锁冲突表现为Innodb_row_lock_waits和Innodb_row_lock_time监控项的指标升高。
定位与处理:show engine innodb status;
命令查看是否有大量会话处于Lock wait状态,如果有,说明行锁冲突比较严重,需要通过优化热点更新、降低事务大小、及时提交事务等方法避免行锁冲突。

浙公网安备 33010602011771号