文章导航
阿里面试官说: 请你设计一个支撑1000W并发的系统?
1.5 如何降低RT的值
继续看上面这个图,一个请求只有等到tomcat容器中的应用执行完成才能返回,而请求在执行过程中会做什么事情呢?
- 查询数据库
- 访问磁盘数据
- 进行内存运算
- 调用远程服务
这些操作每一个步骤都会消耗时间,当前客户端的请求只有等到这些操作都完成之后才能返回,所以降低RT的方法,就是优化业务逻辑的处理。
1.5.1 数据库瓶颈的优化
当18000个请求进入到服务端并且被接收后,开始执行业务逻辑处理,那么必然会查询数据库。
每个请求至少都有一次查询数据库的操作,多的需要查询3~5次以上,我们假设按照3次来计算,那么每秒会对数据库形成54000个请求,假设一台数据库服务器每秒支撑10000个请求(影响数据库的请求数量有很多因素,比如数据库表的数据量、数据库服务器本身的系统性能、查询语句的复杂度),那么需要6台数据库服务器才能支撑每秒10000个请求。
除此之外,数据库层面还有涉及到其他的优化方案。
首先是Mysql的最大连接数设置,大家可能遇到过MySQL: ERROR 1040: Too many connections
这样的问题,原因就是访问量过高,连接数耗尽了。
show variables like '%max_connections%';
如果服务器的并发连接请求量比较大,建议调高此值,以增加并行连接数量,当然这建立在机器能支撑的情况下,因为如果连接数越多,介于MySQL会为每个连接提供连接缓冲区,就会开销越多的内存,所以要适当调整该值,不能盲目提高设值。
数据表数据量过大,比如达到几千万甚至上亿,这种情况下sql的优化已经毫无意义了,因为这么大的数据量查询必然会涉及到运算。
可以缓存来解决读请求并发过高的问题,一般来说对于数据库的读写请求也都遵循2/8法则,在每秒54000个请求中,大概有43200左右是读请求,这些读请求中基本上90%都是可以通过缓存来解决。
分库分表,减少单表数据量,单表数据量少了,那么查询性能就自然得到了有效的提升•读写分离,避免事务操作对查询操作带来的性能影响
写操作本身耗费资源数据库写操作为IO写入,写入过程中通常会涉及唯一性校验、建索引、索引排序等操作,对资源消耗比较大。一次写操作的响应时间往往是读操作的几倍甚至几十倍。
锁争用写操作很多时候需要加锁,包括表级锁、行级锁等,这类锁都是排他锁,一个会话占据排它锁之后,其他会话是不能读取数据的,这会会极大影响数据读取性能。所以MYSQL部署往往会采用读写分离方式,主库用来写入数据及部分时效性要求很高的读操作,从库用来承接大部分读操作,这样数据库整体性能能够得到大幅提升。
- 不同类型的数据采用不同的存储库,
- MongoDB nosql 文档化存储
- Redis nosql key-value存储
- HBase nosql, 列式存储,其实本质上有点类似于key-value数据库。
- cassandra,Cassandra 是一个来自 Apache 的分布式数据库,具有高度可扩展性,可用于管理大量的结构化数据
- TIDB,是PingCAP公司自主设计、研发的开源分布式关系型数据库,是一款同时支持在线事务处理与在线分析处理 (Hybrid Transactional and Analytical Processing, HTAP) 的融合型分布式数据库产品
为什么把mysql数据库中的数据放redis缓存中能提升性能?
1.Redis存储的是k-v格式的数据。时间复杂度是O(1),常数阶,而mysql引擎的底层实现是B+TREE,时间复杂度是O(logn)是对数阶的。Redis会比Mysql快一点点。
2.Mysql数据存储是存储在表中,查找数据时要先对表进行全局扫描或根据索引查找,这涉及到磁盘的查找,磁盘查找如果是单点查找可能会快点,但是顺序查找就比较慢。而redis不用这么麻烦,本身就是存储在内存中,会根据数据在内存的位置直接取出。
3.Redis是单线程的多路复用IO,单线程避免了线程切换的开销,而多路复用IO避免了IO等待的开销,在多核处理器下提高处理器的使用效率可以对数据进行分区,然后每个处理器处理不同的数据。
•池化技术,减少频繁创建数据库连接的性能损耗。每次进行数据库操作之前,先建立连接然后再进行数据库操作,最后释放连接。这个过程涉及到网络通信的延时,频繁创建连接对象和销毁对象的性能开销等,当请求量较大时,这块带来的性能影响非常大。