分享嘉宾
叶正盛,玖章算术科技公司CEO,原阿里云资深技术与产品专家,数据库产品治理与解决方案部总经理。20年软件研发教训,曾主导过多个工业控制软件、ERP、大型电力计费零碎研发,见证与实际了阿里巴巴去IOE、异地多活、云计算屡次技术改革。
分享内容
正当的设计数据架构是程序员的外围竞争力,也是一般程序员走向技术专家的必修课。数据库始终是计算机外围根底软件,经验了40年的倒退,从关系型数据库,到数据仓库、NoSQL、大数据以及云原生数据库,体系越来越简单。
本次主题重点介绍应用软件到底层数据库全链路的外围原理,心愿帮忙宽广序员更好的了解并应用好数据库。
数据库简介
数据库管理系统(DBMS)是治理数据库的大型软件,能够建设、应用和保护数据库,其提供了数据采集、存储、查问和剖析的性能。
在没有数据库之前,如果咱们要做库存治理,以小超市、夫妻店为例,咱们能够用手工记账,但随着数据越来越多,咱们能够用Excel治理,如果是大型超市或大型库存核心,Excel就不能应答了,须要应用数据库来治理。那么,数据库和Excel有什么区别呢?
第一,治理的数据量不同,Excel能够治理上万条数据,而数据库能够轻松治理数亿条数据;
第二,多用户,高性能,Excel个别是集体操作,数据库系统须要解决互联网平台上可能是数亿用户同时申请;
第三,平安治理的不同,Excel只能设置密码保护,数据库反对用户的简单权限管制;
第四,开发接口不同,Excel开发接口比拟多,但根本是利用在内置单机开发,数据库有面向应用软件的开发接口,适宜大型应用软件或者互联网平台业务。
支流的数据库有几十种,这张图形容了以后数据库主流产品定位,通过治理数据量大小和SQL性能强弱把各个产品分为四大类:
OLTP:在线事务处理平台,个别都是关系型数据库来撑持,常见的数据库有:SQLite、MySQL、PostgreSQL、PolarDB、TiDB、OceanBase
OLAP:在线剖析业务,个别是数据仓库,常见的产品有:Teradata、Clickhouse、Doris、Greenplum、Snowflake、AWS Redshift
NoSQL:新数据模型,互联网行业用得十分多,代表产品有:Redis、Neo4j、InfluxDB、MongoDB、Cassandra、AWS DynamoDB
BigData:大数据业务,和数据仓库比拟相似,然而更善于解决大规模数据分析业务,主流产品有:HBase、Hadoop、ElasticSearch、Spark
另外DB2、SQLServer、Oracle这几款产品在OLTP和OLAP畛域都比拟强,有时称为HTAP产品,也是目前数据库的领导者。
不是说治理的数据量越大和SQL性能越强就越好,每一种数据库它是在特定的场景可能开展它的劣势,这里只是把它划分在不同的区域。
依据数据库计算节点和存储节点部署整体架构分为几大品种:
单机: 计算节点和存储节点个别在同一台机器上,通常存储节点是本地硬盘,如单机版的MySQL、Oracle。单机模式没有高可用保障,罕用于长期开发测试或者集体学习场景,生产环境不倡议应用。
主备读写拆散: 在单机模式上减少了备用节点,备用节点既能够作为高可用保障,也能够承当只读业务申请,主备之间通过数据库的log实时传输实现。比拟常见的有MySQL的Master-Slave,Oracle的Active Dataguard,SQL Server的Always on,主备模式也是以后生产环境最常见的部署架构。
随着数据量或者负载的减少,主备模式曾经无奈满足业务需要,因而诞生了分布式的软件架构,数据仓库和大数据产品通常都是分布式架构,次要由两种模式:
分布式(Share everything): Share everything架构通常存储节点采纳分布式的共享存储,比方业余的EMC存储设备或者是云存储OSS/S3。因为数据共享问题解决了,计算节点就能扩大多个,从而承当更多业务负载。典型代表有Oracle RAC、阿里云PolarDB、Snowflake、AWS Redshift(RA3)。IBM DB2也是典型的分布式架构,它同时还采纳了集中式共享缓存的模式。
分布式(Share nothing): 在没有共享存储的状况下,通常会采纳Share Nothing的架构设计。这类架构是存储数据分片存储在不同的节点,因而计算和存储节点都是独立运行,通过MPP计算引擎实现集群资源的调度运算。
数据库内部结构
数据库引擎次要包含以下组件:
存储引擎: 负责数据的存储管理,包含数据、索引、日志等数据的治理;
缓存治理: 负责数据库的缓存治理,包含数据缓存、SQL缓存、会话缓存、运算缓存等等;
计算引擎: 也称为查问引擎,负责业务申请的逻辑运算,包含SQL解析、执行打算生成、执行算子下发到存储引擎等等;
事务处理: 负责数据库的事务管理,ACID、锁等个性的实现;
分布式治理: 分布式数据库的外围组件,用于协调数据库各个节点通信、事务状态一致性协调、分布式计算等等;
平安治理: 数据库的平安拜访根底,包含根本的用户、角色认证,加密解密,以及高级的数据脱敏个性;
会话治理: 数据库连贯和连接池状态、配置等治理;
内部接口: 负责对外提供规范的数据库拜访接口,反对应用软件通过JDBC、ODBC、Socket等形式拜访数据库。
每种数据库都有本人的实现计划和技术架构,但通常都会包含以上组件性能。
存储引擎最根底的是HEAP构造,这也是表数据文件通常的保留格局。
常见的数据库,像Oracle,SQL Server,MySQL(ISAM),PostgreSQL表的根底构造都是堆表引擎。能够了解为一条记录过去,就把它按先后顺序堆进去。数据库由多个文件形成,一个文件由多个Extent/Segment形成,每个Extent蕴含多个Block/Page,OLTP通常在4K~32K大小,Block外面就是具体的行数据信息。
B-TREE是数据库索引最罕用的数据结构,MySQL(InnoDB)的表数据也间接采纳了B-TREE的存储构造。
B-TREE的外围特点是对数据排序,能够从根节点到叶子节点再定位到数据,叶子节点能够有多层,就像一棵树的树枝一样。
我最喜爱的例子还是用新华字典来形容,大家小时候常常查字典,其实就是B树的原理,要查一个字,首先要找索引,如果晓得它的拼音,依据拼音索引外面的地位去找到页码,再找到数据,查问效率还是十分高的。
字典可能有很多种目录索引,常见的有拼音、部首、笔划,这样就能够按不同的形式疾速找到要须要的字。数据库B-TREE原理跟查字典基本上是一样的,很多文章介绍不等于、大于、小于等条件能不能应用上索引,其实想想这个逻辑,用字典目录能不能查,就能大略判断进去能不能做,原理是齐全一样的,没有什么特别之处。
HEAP和BTREE通常是OLTP数据库应用,而OLAP通常数据量十分大,COLUMN-STORE(列存)是更常见的存储构造,因为按列存储数据能够做到更好的编码压缩,并且当SQL只是须要申请大宽表的局部字段时,COLUMN-STORE就十分有劣势。
开源的ORC和PARQUET是列式存储的典型模型,都比拟常见。Greenplum、ClickHouse等数据仓库都反对列式存储。
在咱们生存中也有这样的例子,比如说大超市的货架,通常都是按品类摆放的,电器、水果、零食都是放在不同的地位,这就是一种列式分类管理的概率,查问效率也比拟高,也能够摆放更多的货物。
再谈谈LSM-TREE,下面是阿里外部X-DB的技术架构图,很好的形容LSM-TREE模型。业务往里面写数据时,先写日志,同时放在内存外面,内存积攒到肯定的数据,就排好序往底下磁盘刷盘,按同样的逻辑一层一层刷盘,这是典型的分层存储的概念。
它在写方面十分强,尤其是程序写,像日志这种数据比拟适宜。它的毛病是读性能比B树差,尤其是按范畴读取数据。大量的传统OLTP商业数据库仍然用B树去做,因为实际下来综合读写会更高效。LSM-Tree在日志存储场景比拟适合,如Hbase,另外咱们也会看到一些分布式数据库存储用LSM构造,如TiDB、OceanBase,这个还有待验证。LSM-Tree在面向传统硬盘上有程序写入劣势,对SSD写磨损也更敌对,但在SSD硬盘上的整体性能晋升收益没有传统硬盘突出,因为SSD的随机IO性能也不错。
用一个表格汇总各种存储引擎的优劣势和利用场景。
数据库缓存分为几大板块,第一是数据缓存,一般来说是全局性的,所有的会话都在对立的数据缓存里读取和写入数据。框的大小代表着占用内存的大小,比方数据块,这是占用最多的,其次是索引块,另外是日志,比方REDO LOG。
也有一些开发者会问,这个缓存为什么数据库独自去治理?用操作系统不行吗?如果说不深度了解这个问题,的确操作系统缓存也做得很好,有些数据库的确没有缓存,然而咱们看到十分弱小的数据库都有本人的缓存治理模块,比方Oracle、SQLServer等等。
数据库本人做缓存治理能够做得十分精密,比如说有全表扫描和按索引扫描,如果不做精细化的缓存,有可能一个大表的查问就把以前无效的缓存都给清进来了,对于数据库来讲是不能承受的,所以须要本人做治理,因为能够判断这个缓存的重要性。Oracle,MySQL(InnoDB)这方面都做了很多细的工作,这是操作系统不肯定能解决好的问题。
当然也会存在肯定问题,数据库有缓存,操作系统还有缓存,会不会导致缓存重复使用,效率不高?因而有些数据库就把操作系统的缓存给旁路了,操作系统会提供DirectIO这样的接口。
图中右上角是SQL与对象的缓存,有两个比拟重要的,一个是SQL的文本和执行打算,第二是元数据,比如说表构造定义信息。SQL文本和执行打算缓存比拟大,尤其像Oracle这些成熟的商业数据库,因为须要反对非常复杂的SQL最优执行打算制订,所以缓存治理就更加重要。反而开源的数据库执行打算缓存会做得十分弱,比方MySQL,能够说是简直没有。如果有执行打算缓存,像Oracle这种数据库,效率是齐全不一样的,每次执行,效率有可能会有10倍以上的晋升。
而后是会话缓存,这块比拟好了解。还有是运算缓存,在数仓里十分重要,OLTP零碎,个别数据缓存很重要,OLAP运算缓存会更重要,次要起因是OLAP零碎的Hash与排序运算量比拟大。
数据库事务处理的外围是ACID:
Atomicity:原子性,示意数据库一个事务操作要么胜利,要么失败,不能呈现局部胜利或者局部失败的状况。通常采纳WAL(Write Ahead Log)来实现,同时利用了硬件的原子写接口。
Consistency:一致性,示意数据库要能保障定义的束缚有效性,包含定义的主键、惟一束缚、外键、NOT NULL等束缚,在每个事务提交后都要确保束缚无效。在事务过程中没有强制束缚,因而不同数据库对束缚的实现会有些区别,比方插入惟一束缚反复的数据是立刻失败,还是等事务commit再查看惟一束缚?
Isolation:隔离性,这个是事务最简单的中央,国际标准定义了4种事务隔离级别。对于OLTP零碎,大部分都采纳了Read Committed的隔离级别,唯独MySQL(InnoDB)默认采纳了Repeatable Read的隔离级别,这个也是因为历史起因,MySQL的主备同步应用了Statement模式导致的。当初MySQL根本都是采纳ROW格局的Binlog格局,所以倡议改为Read Committed隔离级别更好,也能缩小Repeatable Read带来的各种锁和死锁问题。我在第一次应用MySQL就踩了一个坑,过后应用Create table as select备份一张线上表,而后表就被锁定了,导致业务故障,这个也是十分坑的中央。阿里巴巴团体外部和阿里云RDS也默认把事务隔离级别改为了Read Committed,零碎也更加稳固。
Durability:持久性,意思是事务提交后,数据库肯定要确保失效,即便操作系统重启或者是服务器掉电。数据库通常也是应用WAL加硬件的持久性来实现,这里须要保障commit后刷盘立刻写入,不能长期缓存在内存中,否则服务器掉电就失落数据。
查问引擎是数据库最简单的模块,外围是解决业务申请逻辑,如SQL怎么解析、执行,能够称为数据库的大脑。
每种数据库应用的查询语言不太一样。关系型数据库通常应用SQL语言,KV数据库个别应用get/set语义,文档数据库个别是用JSON模型表白,图数据库比较复杂,有OpenCypher、Gremiln、SPARQL等。时序数据库,也大部分是类SQL的模型,它在SQL的根底上减少了一些时序计算窗口类的表白模型。
SQL是数据库最罕用的语言,也是数据库的外围资源开销,因而SQL优化是程序员的必备技能。
SQL优化通常分3个阶段,咱们常称为SQL优化三板斧,这三板斧上来,90%的问题都能够解决。
第一是先找到问题SQL,有两种状况,如果是当初零碎有问题,咱们能够去看沉闷的连贯在干什么,把正在运行的SQL取出来。每种数据库通常都提供了查问以后沉闷会话的接口,比方MySQL应用show processlist,Oracle能够查问v$session视图信息。如果说问题曾经过来了,没有现场,能够通过Slow Log,或者TOP SQL,找到问题,这个须要数据库开启历史SQL记录性能。
第二是剖析问题SQL,最次要先看SQL的执行打算,再去看整个数据库的IO访问量是不是合乎预期,缓冲命中率怎么样,如果不是99%以上,可能都有问题,有些程序员看到内存都用完了,其实也不是什么问题,比方有10G的内存,如果你的数据量超过10GB,那内存很快都会用满,要害要看缓存命中率。另外是网络IO,多集群的话,须要关注网络传输的提早和带宽容量。如果有锁,要剖析SQL锁的模型。CPU重点要看一下排序、函数计算等操作。
最初是解决问题,就是优化SQL,能够批改SQL晋升性能,如果没有索引就要减少索引,如果缓存命中率有问题就要调整内存配置。数据整顿也是比拟常见的,有些数据库历史数据十分多,影响了效率,要思考怎么把历史数据归档,晋升数据拜访效率。
再有是晋升硬件性能,最初是分布式革新,分布式革新比拟艰难,如果后面几个步骤能解决最好,切实不行再去思考比较复杂的分布式革新。
接下来重点讲一下执行打算。有些高级程序员往往漠视这个问题,SQL执行打算是形容SQL具体执行门路和算法。
数据库通常反对应用EXPLAIN语法来查看SQL的执行打算,会展现出SQL具体的执行门路和算法,包含拜访表的程序,每张表应用索引拜访还是全表扫描,每次执行预计返回的行数等等,信息会比拟具体。
SQL拜访单表次要有几种形式,包含:
主键:示例SQL:select * from t where id=?
惟一索引:select * from t where uk=?
一般索引:select * from t where name=?
索引范畴扫描:select * from t where create_time>?
全表扫描:select * from t
对于多表连贯,通常有以下几种JOIN算法:
Nested loop join:适宜两张表有十分好的索引拜访门路,如:select * from t1 inner join t2 where t1.id=t2.id and t1.id=?
Hash Join:适宜两张表都没有好的索引,须要全表扫描,并且是等值关联查问,如:select * from t1 inner join t2 where t1.id=t2.id
Hash Join须要把一张表加载到内存后,另外一张表再通过Hash匹配到对应的记录,所以会须要长期内存,当长期内存不够时会产生长期磁盘转储的开销。为了解决Hash Join在分布式场景的问题,也诞生了Shuffle Hash Join和Broadcast Hash Join算法。
Merge Join:适宜两张表都没有好的索引,须要全表扫描,反对非等值关联查问,关联字段最好是有排序,因为Merge Join算法是须要把两边数据排序再Merge。
数据库如何生成SQL执行打算,如何抉择最优的执行门路,通常是外部有个优化器的组件来实现。优化器类型有RBO和CBO两种。
RBO:Rule Base Optimizer,意思是基于规定的优化器逻辑,晚期数据库都是采纳RBO,实现比较简单,但很依附程序员对数据库的逻辑了解,在SQL非常复杂的状况下很容易走到蹩脚的执行打算。
CBO:Cost Base Optimizer,意思是基于老本的逻辑,优化器会计算各种不同的门路老本,最初抉择一条最优的门路来执行。
举个例子,咱们通常的交通计划有飞机、火车、汽车、轮船、步行,每种计划的速度都不同。如果咱们要从杭州去北京,那么该抉择那种交通形式?
对于RBO来说,它总是会抉择飞机,不论是否产生交通管制,以及去机场的交通是否顺畅。
对于CBO来说,它会评估从出发点到杭州机场/火车站,北京火车站/机场到目的地的交通工夫,综合评估一个最短时间的交通计划。
CBO是目前数据库支流的优化器模型,实现难度也更大,须要收集很多统计信息,如每张表的存储空间大小和记录数,字段的区分度等等,在数据常常变动时须要保障统计信息的准确性。
RBO和CBO通常都是在生成执行打算后就不能再批改,即便执行过程中发现重大偏差也不会扭转,因而起初有些数据库在CBO的根底上实现了更智能的Adaptive的逻辑,意思是在执行过程中,如果发现有更优门路,那优化器能够调整执行打算。就如同原本抉择坐飞机从杭州去北京,然而到了机场,发现航班大量延误,起飞时间齐全不确定,这个时候能够调整计划,抉择做火车登程。
开源数据库的优化器绝对比拟弱,商业数据库更当先。国内在这块技术相比国内落后很多。
接下来讲一下数据库的设计,基础知识是要把握范式,在教科书外面十分多,这里不多讲 。反范式我感觉是比拟有意思,尤其是表设计外面,有十分多的反范式的案例。比如说标记组合是比拟常见的,如果有多个标记状态位,可能会用bit的数据类型去存储,这其实就曾经违反了第一范式,因为第一范式要求字段的内容要原子性,不能拆分。实际上数据库内核外面,它用了很多bit类型这种反范式来设计元数据,从而晋升存储和查问效率。
另外一个是日常习惯字段,拿身份证号码来举例,也是违反了第一范式,因为身份证号码曾经包含所在的地区、出生年月、注销程序以及校验码这4个信息。然而咱们理论的表结构设计,还是会把身份证号码当做一个字段,不会说把身份证号码拆成4个字段,否则浏览习惯会不太不便。
还有计算列,典型的违反了第三范式,如商品的金额=单价*数量,订单总金额,咱们个别都会冗余去存储。
数仓外面就更多的反范式的案例,历史数据快照,会把相干的信息都保留下来,也是违反范式,但咱们根本都这么干。
拆表也是一种常见设计,比如说一张表外面有罕用和不罕用的字段,如有个字段是大字段,咱们就会把它拆成另外一张表。
这些其实都是比拟常见的反范式设计的场景。所以局部场景下咱们不必去特地纠结肯定要遵循范式,如果说你感觉正当,业务逻辑实现可控,适当的冗余数据其实也没什么问题。
对于主键抉择,比拟举荐两种,一种是自增字段,比拟适宜外部零碎的表,如果说是对外的互联网利用须要留神,有被猜想攻打的隐患。咱们公司比拟喜爱用雪花模型,依据工夫序列加上顺序号产生主键,性能比拟好,比拟平安,实现绝对简单,须要应用程序产生。
接下来介绍几个常见的数据模型:
首先是平台型互联网数据模型,像淘宝、微信公众号、美团、BOSS直聘、滴滴等等,他们的数据模型都比拟相似,次要包含以下对象。
会员信息:买家(淘宝、美团)、乘客(滴滴)、读者(公众号)、求职人(BOSS直聘)。
服务提供者信息:卖家(淘宝、美团)、博主(公众号)、司机(滴滴)、主播(抖音)、公司(BOSS直聘)
服务内容信息:商品、文章、微博、用车、视频、职位
库存信息:电商的概念
互联网平台依据以上几张表信息,通过搜寻、举荐等各种匹配算法,最初产生订单信息,接着是付款信息、物流/配送信息,最初是服务反馈信息。
方才是互联网的模型,企业软件不太一样,企业软件考究两个货色,一个是平安,一个是流程标准。
平安外围是权限模型设计,比拟规范的是RBAC(Role Base Access Control),咱们能够参考这套模型演进。外围是了解用户、权限、角色三个重要的对象。依照RBAC设计问题不会太大,有可能会有扩大的货色。比方面向公司的用户,会有组织和部门的关系。权限会扩大出权限分组,角色会有继承等。另外一个是数据域权限,同样的权限与角色,然而能拜访的是不同范畴的数据,就会有数据域等高级定义。
咱们再看企业软件里比拟常见的流程标准,最常见的是工作流引擎。
首先有工单表,不论是销假、权限申请还是生产变更,都有一个工单来存储你做什么事件。
而后是流程模型定义表,例如数据库产生变更的流程,当初做生产公布,变更表构造,要提交变更申请,主管要审批,如果高风险还须要DBA的审批,这就是一个业务流程模型。
流程模型会包含根本定义信息,有哪几个节点,流转门路,依据什么条件流转,哪些人受理等等。
针对每个工单的流程解决,都有工单流转表,音讯告诉表,再加上用户权限零碎,这样就能够造成工作流的待办工作表,基本上就是这么一个套路,大家了解这个概念,在企业级软件里就能够蛟龙得水了,不会那么纠结。
数据传输和平安治理
后面是数据库架构和 SQL优化板块,最初一个板块我要讲一下数据传输和平安治理,这个也是咱们开发者其实常常会遇到的问题。
数据传输是一个统称,包含数据迁徙、数据同步、数据散发等,也称为数据复制。
比拟常见的几个场景:数据库上云、更换数据库、数据同步到备库、异地数据多活、数据ETL等等。
通常包含构造迁徙、全量数据复制、增量数据复制几个外围模块,为了保障数据复制的正确性,还须要数据比照模块。这外面最难的增量数据复制模块,市场上很多产品会采纳按日期增量抽取简化解决,只能做到定时复制,要做到实时数据复制须要应用CDC技术,要精通数据库的外部原理,适配各种支流数据库产品和版本,技术难度和工程难度都是十分有挑战。
我在这个畛域做了10年,从晚期的去IOE、异地多活到公布阿里云DTS,外面有十分多的问题,尤其是在生产环境下,源端常常会有各种DDL变更的状况很容易链路中断或者数据错乱。目前市场上举荐的三款代表产品:
- 阿里云DTS:性能齐备,与阿里云集成度很好
- NineData(重点举荐):玖章算术公司研发的SaaS产品(www.ninedata.cloud),反对阿里云、华为云、腾讯云、AWS等多个云平台,技术指标上更当先,易用性也更好,免装置应用
- Canal:阿里开源的产品,影响力很大,不算是残缺的产品,个别须要二次开发。
数据安全治理,太重要了,我把这个独自列出来讲。
先说软硬件的故障,比方服务器,磁盘必定会坏,过保机器坏的可能性更高了,所以肯定要做好灾备工作。再有是机房也有可能产生劫难,业界每个月都会有机房出问题,像火灾,地震,或者是断电、光缆断了等,都是机房故障。另外是软件Bug,个别是指数据库自身的软件Bug,成熟的数据库Oracle、MySQL每次公布都会说修复了几十个Bug,一般数据库的bug可能更多。
如果用云平台会好一些,比人工治理更平安,云很重视服务器的故障检测,及时降级数据库最新的安全补丁,大型云厂商都有业余的团队去做这个事件。
第二大类是人为故障,比方黑客入侵会造成数据泄露或者勒索,黑客通常会利用软件外面SQL注入,只有有注入的危险,黑客是全网扫描的,一旦扫到就进来了。
还有是明码泄露,如果是弱明码就必定能被黑客发现,只是等黑客啥工夫要搞你。另外是如果有系统漏洞,黑客一般来说提前就晓得了,会去看能不能攻破你。明天还有一点十分重要,就是外部数据泄露,还有删库跑路。在明天员工和公司对抗的状况下,还是时常产生的,尤其是和主管关系不好,迟早都会产生删库跑路的事件,管数据库的员工还是要比拟谨慎。
最初是数据误操作,比如说做软件的降级公布,不小心写错了,我做DBA的时候就碰到过十分多,每个月都会碰到程序员将提交的SQL给搞错了,须要复原数据,这些都是人为的问题。数据备份是肯定要做的,如果没有备份肯定是不虚浮的,总会产生问题。
如果是十分重要的数据,要思考异地容灾。如果是敏感的数据,要思考数据加密,包含数据传输的加密。
另外一点,流程标准十分重要,尤其是对生产零碎的数据操作,最好有零碎来撑持,靠人监督是没有用的。肯定要通过平台来管控,不要把数据库账号密码放出去,包含只读权限的账号密码,这些都是零碎隐患,说不准哪天你家公司的敏感数据就在网上被黑客贩卖…
最初,心愿让每个人用好数据和云,这个也是咱们玖章算术公司的使命。NineData 是咱们研发的产品,心愿能够帮忙你解决相干的问题,欢送拜访www.ninedata.cloud,它提供了企业级的SQL开发流程治理,数据复制、数据备份、数据比照等性能。