后端接口如何提高性能_第1页
后端接口如何提高性能_第2页
后端接口如何提高性能_第3页
后端接口如何提高性能_第4页
后端接口如何提高性能_第5页
已阅读5页,还剩11页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

后端接口如何提高性能?哪个男孩不想完成一次快速的查询?1.MySQL查询慢是什么体验?谢邀,利益相关。大多数互联网应用场景都是读多写少,业务逻辑更多分布在写上。对读的要求大概就是要快。那么都有什么原因会导致我们完成一次出色的慢查询呢?1.1索引在数据量不是很大时,大多慢查询可以用索引解决,大多慢查询也因为索引不合理而产生。MySQL索引基于B+树,这句话相信面试都背烂了,接着就可以问最左前缀索引、B+树和各种树了。说到最左前缀,实际就是组合索引的使用规则,使用合理组合索引可以有效的提高查询速度,为什么呢?因为索引下推。如果查询条件包含在了组合索引中,比如存在组合索引(a,b),查询到满足a的记录后会直接在索引内部判断b是否满足,减少回表次数。同时,如果查询的列恰好包含在组合索引中,即为覆盖索引,无需回表。索引规则估计都知道,实际开发中也会创建和使用。问题可能更多的是:为什么建了索引还慢?1.1.1什么原因导致索引失效建了索引还慢,多半是索引失效(未使用),可用explain分析。索引失效常见原因有:where中使用!=或<>或or或表达式或函数(左侧)like语句%开头字符串未加’’索引字段区分度过低,如性别未匹配最左前缀(一张嘴就知道老面试题了)为什么这些做法会导致失效,成熟的MySQL也有自己的想法。1.1.2这些原因为什么导致索引失效如果要MySQL给一个理由,还是那棵B+树。函数操作当在查询where=左侧使用表达式或函数时,如字段A为字符串型且有索引,有

wherelength(a)=6查询,这时传递一个6到A的索引树,不难想象在树的第一层就迷路了。隐式转换隐式类型转换和隐式字符编码转换也会导致这个问题。隐式类型转换对于JOOQ这种框架来说一般倒不会出现。隐式字符编码转换在连表查询时倒可能出现,即连表字段的类型相同但字符编码不同。破坏了有序性至于Like语句%开头、字符串未加’’原因基本一致,MySQL认为对索引字段的操作可能会破坏索引有序性就机智的优化掉了。不过,对于如性别这种区分度过低的字段,索引失效就不是因为这个原因。1.1.3性别字段为什么不要加索引为什么索引区分度低的字段不要加索引。盲猜效率低,效率的确低,有时甚至会等于没加。对于非聚簇索引,是要回表的。假如有100条数据,在sex字段建立索引,扫描到51个male,需要再回表扫描51行。还不如直接来一次全表扫描呢。所以,InnoDB引擎对于这种场景就会放弃使用索引,至于区分度多低多少会放弃,大致是某类型的数据占到总的30%左右时,就会放弃使用该字段的索引,有兴趣可以试一下。1.1.4有什么好用且简单的索引方法前面说到大多慢查询都源于索引,怎么建立并用好索引。这里有一些简单的规则。索引下推:性别字段不适合建索引,但确实存在查询场景怎么办?如果是多条件查询,可以建立联合索引利用该特性优化。覆盖索引:也是联合索引,查询需要的信息在索引里已经包含了,就不会再回表了。前缀索引:对于字符串,可以只在前N位添加索引,避免不必要的开支。假如的确需要如关键字查询,那交给更合适的如ES或许更好。不要对索引字段做函数操作对于确定的、写多读少的表或者频繁更新的字段都应该考虑索引的维护成本。1.1.5如何评价MySQL选错了索引有时,建立了猛一看挺正确的索引,但事情却没按计划发展。就像“为啥XXX有索引,根据它查询还是慢查询”。此刻没准要自信点:我的代码不可能有BUG,肯定是MySQL出了问题。MySQL的确可能有点问题。这种情况常见于建了一大堆索引,查询条件一大堆。没使用你想让它用的那一个,而是选了个区分度低的,导致过多的扫描。造成的原因基本有两个:信息统计不准确:可以使用

analyzetablex重新分析。优化器误判:可以

forceindex强制指定。或修改语句引导优化器,增加或删除索引绕过。但根据我浅薄的经验来看,更可能是因为你建了些没必要的索引导致的。不会真有人以为MySQL没自己机灵吧?除了上面这些索引原因外,还有下面这些不常见或者说不好判断的原因存在。搜索公众号后端架构师后台回复“架构整洁”,获取一份惊喜礼包。1.2等MDL锁在MySQL5.5版本中引入了MDL,对一个表做CRUD操作时,自动加MDL读锁;对表结构做变更时,加MDL写锁。读写锁、写锁间互斥。当某语句拿MDL写锁就会阻塞MDL读锁,可以使用showprocesslist命令查看处于Waitingfortablemetadatalock状态的语句。1.3等flushflush很快,大多是因为flush命令被别的语句堵住,它又堵住了select。通过showprocesslist命令查看时会发现处于Waitingfortableflush状态。1.4等行锁某事物持有写锁未提交。1.5当前读InnoDB默认级别是可重复读。设想一个场景:事物A开始事务,事务B也开始执行大量更新。B率先提交,A是当前读,就要依次执行undolog,直到找到事务B开始前的值。1.6大表场景在未二次开发的MYSQL中,上亿的表肯定算大表,这种情况即使在索引、查询层面做到了较好实现,面对频繁聚合操作也可能会出现IO或CPU瓶颈,即使是单纯查询,效率也会下降。且Innodb每个B+树节点存储容量是16KB,理论上可存储2kw行左右,这时树高为3层。我们知道,innodb_buffer_pool用来缓存表及索引,如果索引数据较大,缓存命中率就堪忧,同时innodb_buffer_pool采用LRU算法进行页面淘汰,如果数据量过大,对老或非热点数据的查询可能就会把热点数据给挤出去。所以对于大表常见优化即是分库分表和读写分离了。1.6.1分库分表方案是分库还是分表呢?这要具体分析。如果磁盘或网络有IO瓶颈,那就要分库和垂直分表。如果是CPU瓶颈,即查询效率偏低,水平分表。水平即切分数据,分散原有数据到更多的库表中。垂直即按照业务对库,按字段对表切分。工具方面有sharding-sphere、TDDL、Mycat。动起手来需要先评估分库、表数,制定分片规则选key,再开发和数据迁移,还要考虑扩容问题。问题实际运行中,写问题不大,主要问题在于唯一ID生成、非partitionkey查询、扩容。唯一ID方法很多,DB自增、Snowflake、号段、一大波GUID算法等。非partitionkey查询常用映射法解决,映射表用到覆盖索引的话还是很快的。或者可以和其他DB组合。扩容要根据分片时的策略确定,范围分片的话就很简单,而随机取模分片就要迁移数据了。也可以用范围+取模的模式分片,先取模再范围,可以避免一定程度的数据迁移。当然,如果分库还会面临事务一致性和跨库join等问题。1.6.2读写分离为什么要读写分离分表针对大表解决CPU瓶颈,分库解决IO瓶颈,二者将存储压力解决了。但查询还不一定。如果落到DB的QPS还是很高,且读远大于写,就可以考虑读写分离,基于主从模式将读的压力分摊,避免单机负载过高,同时也保证了高可用,实现了负载均衡。问题主要问题有过期读和分配机制。过期读,也就是主从延时问题,这个对于。分配机制,是走主还是从库。可以直接代码中根据语句类型切换或者使用中间件。1.7小结以上列举了MySQL常见慢查询原因和处理方法,介绍了应对较大数据场景的常用方法。分库分表和读写分离是针对大数据或并发场景的,同时也为了提高系统的稳定和拓展性。但也不是所有的问题都最适合这么解决。2.如何评价ElasticSearch前文有提到对于关键字查询可以使用ES。那接着聊聊ES。2.1可以干什么ES是基于Lucene的近实时分布式搜索引擎。使用场景有全文搜索、NoSQLJson文档数据库、监控日志、数据采集分析等。对非数据开发来说,常用的应该就是全文检索和日志了。ES的使用中,常和Logstash,Kibana结合,也成为ELK。先来瞧瞧日志怎么用的。下面是我司日志系统某检索操作:打开Kibana在Discover页面输入格式如“xxx”查询。该操作可以在DevTools的控制台替换为:GET

yourIndex/_search

{

"from"

:

0,

"size"

:

10,

"query"

:

{

"match_phrase"

:

{

"log"

:

"xxx"

}

}

}

什么意思?Discover中加上“”和console中的match_phrase都代表这是一个短语匹配,意味着只保留那些包含全部搜索词项,且位置与搜索词项相同的文档。2.2ES的结构在ES7.0之前存储结构是Index->Type->Document,按MySQL对比就是database-table-id(实际这种对比不那么合理)。7.0之后Type被废弃了,就暂把index当做table吧。在DevTools的Console可以通过以下命令查看一些基本信息。也可以替换为crul命令。GET/_cat/health?v&pretty:查看集群健康状态GET/_cat/shards?v:查看分片状态GET

yourindex/_mapping

:index

mapping结构GET

yourindex/_settings

:index

setting结构GET

/_cat/indices?v

:查看当前节点所有索引信息重点是mapping和setting,mapping可以理解为MySQL中表的结构定义,setting负责控制如分片数量、副本数量。以下是截取了某日志index下的部分mapping结构,ES对字符串类型会默认定义成text,同时为它定义一个叫做keyword的子字段。这两的区别是:text类型会进行分词,keyword类型不会进行分词。"******":

{

"mappings":

{

"doc":

{

"properties":

{

"appname":

{

"type":

"text",

"fields":

{

"keyword":

{

"type":

"keyword",

"ignore_above":

256

}

}

2.3ES查询为什么快?分词是什么意思?看完ES的索引原理你就get了。ES基于倒排索引。嘛意思?传统索引一般是以文档ID作索引,以内容作为记录。倒排索引相反,根据已有属性值,去找到相应的行所在的位置,也就是将单词或内容作为索引,将文档ID作为记录。下图是ES倒排索引的示意图,由Termindex,TeamDictionary和PostingList组成。图片图中的Ada、Sara被称作term,其实就是分词后的词了。如果把图中的TermIndex去掉,是不是有点像MySQL了?TermDictionary就像二级索引,但MySQL是保存在磁盘上的,检索一个term需要若干次的randomaccess磁盘操作。而ES在TermDictionary基础上多了层TermIndex,它以FST形式保存在内存中,保存着term的前缀,借此可以快速的定位到Termdictionary的本term的offset。而且FST形式和Termdictionary的block存储方式都很节省内存和磁盘空间。到这就知道为啥快了,就是因为有了内存中的TermIndex,它为term的索引TermDictionary又做了一层索引。不过,也不是说ES什么查询都比MySQL快。检索大致分为两类。2.3.1分词后检索ES的索引存储的就是分词排序后的结果。比如图中的Ada,在MySQL中%da%就扫全表了,但对ES来说可以快速定位2.3.2精确检索该情况其实相差是不大的,因为TermIndex的优势没了,却还要借此找到在termdictionary中的位置。也许由于MySQL覆盖索引无需回表会更快一点。2.4什么时候用ES如前所述,对于业务中的查询场景什么时候适合使用ES?我觉得有两种。2.4.1全文检索在MySQL中字符串类型根据关键字模糊查询就是一场灾难,对ES来说却是小菜一碟。具体场景,比如消息表对消息内容的模糊查询,即聊天记录查询。但要注意,如果需要的是类似广大搜索引擎的关键字查询而非日志的短语匹配查询,就需要对中文进行分词处理,最广泛使用的是ik。Ik分词器的安装这里不再细说。搜索公众号顶级架构师后台回复“offer”,获取一份惊喜礼包。什么意思呢?分词开头对日志的查询,键入“我可真是个机灵鬼”时,只会得到完全匹配的信息。而倘若去掉“”,又会得到按照“我”、“可”,“真”….分词匹配到的所有信息,这明显会返回很多信息,也是不符合中文语义的。实际期望的分词效果大概是“我”、“可”、“真是”,“机灵鬼”,之后再按照这种分词结果去匹配查询。这是ES默认的分词策略对中文的支持不友善导致的,按照英语单词字母来了,可英语单词间是带有空格的。这也是不少国外软件中文搜索效果不nice的原因之一。对于该问题,你可以在console使用下方命令,测试当前index的分词效果。POST

yourindex/_analyze

{

"field":"yourfield",

"text":"我可真是个机灵鬼"

}

2.4.2组合查询如果数据量够大,表字段又够多。把所有字段信息丢到ES里创建索引是不合理的。使用MySQL的话那就只能按前文提到的分库分表、读写分离来了。何不组合下。1.ES+MySQL将要参与查询的字段信息加上id,放入ES,做好分词。将全量信息放入MySQL,通过id快速检索。2.ES+HBASE如果要省去分库分表什么的,或许可以抛弃MySQL,选择分布式数据库,比如HBASE,对于这种NOSQL来说,存储能力海量,扩容easy,根据rowkey查询也很快。以上思路都是经典的索引与数据存储隔离的方案了。当然,摊子越大越容易出事,也会面临更多的问题。使用ES作索引层,数据同步、时序性、mapping设计、高可用等都需要考虑。毕竟和单纯做日志系统对比,日志可以等待,用户不能。2.5小结本节简单介绍了ES为啥快,和这个快能用在哪。现在你可以打开Kibana的控制台试一试了。如果想在Java项目中接入的话,有SpringBoot加持,在ES环境OK的前提下,完全是开箱即用,就差一个依赖了。基本的CRUD支持都是完全OK的。3.HBASE前面有提到HBASE,什么是HBASE,鉴于篇幅这里简单说说。3.1存储结构关系型数据库如MySQL是按行来的。姓名小学中学大学李某XX小学YY中学NULLHBASE是按列的(实际是列族)。列式存储上表就会变成:姓名学校名称李某XX小学李某YY中学下图是一个HBASE实际的表模型结构。Rowkey是主键,按照字典序排序。TimeStamp是版本号。info和area都是列簇(columnFamily),列簇将表进行横向切割。name、age叫做列,属于某一个列簇,可进行动态添加。Cell是具体的Value。3.2OLTP和OLAP数据处理大致可分成两大类:联机事务处理OLTP(on-linetransactionprocessing)、联机分析处理OLAP(On-LineAnalyticalProcessing)。OLTP是传统的关系型数据库的主要应用,主要是基本的、日常的事务处理。OLAP是数据仓库系统的主要应用,支持复杂分析,侧重决策支持

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论