总结的高并发解决方案

高并发

Posted by 朱坤乾 on September 22, 2019

高并发解决方案&高可用&吞吐量

数据库

1.慢查询定位sql语句

从一个大项目中,迅速的定位执行速度慢的语句. (定位慢查询)

分析MySQL语句查询性能的方法除了使用 EXPLAIN 输出执行计划,还可以让MySQL记录下查询超过指定时间的语句,我们将超过指定时间的SQL语句查询称为“慢查询”。

首先我们了解mysql数据库的一些运行状态如何查询(比如想知道当前mysql运行的时间/一共执行了多少次select/update/delete.. / 当前连接)

show status(用处很多,自己看文档,在此列举常用的)

如何去定位慢查询?

默认情况下,mysql认为10秒才是一个慢查询.

show variables like ‘long_query_time’ ; //可以显示当前慢查询时间

set long_query_time=1 ;//可以修改慢查询时间

2.sql语句优化

https://www.cnblogs.com/wangzhengyu/p/10412499.html

举例::::还有很多,自己总结

1、在表中建立索引,优先考虑where、group by使用到的字段。

2、尽量避免使用select *,返回无用的字段会降低查询效率。

SELECT * FROM t

优化方式:使用具体的字段代替*,只返回使用到的字段。

3、尽量避免使用in 和not in,会导致数据库引擎放弃索引进行全表扫描。如下:

优化方式:如果是连续数值,可以用between代替。如下:

如果是子查询,可以用exists代替。如下:

4、尽量避免使用or,会导致数据库引擎放弃索引进行全表扫描。:

优化方式:可以用union代替or。

5、尽量避免在字段开头模糊查询,会导致数据库引擎放弃索引进行全表扫描。如下:()

SELECT * FROM t WHERE username LIKE ‘%li%’

优化方式:尽量在字段后面使用模糊查询。如下:

SELECT * FROM t WHERE username LIKE ‘li%’

6、尽量避免进行null值的判断,会导致数据库引擎放弃索引进行全表扫描。如下:

SELECT * FROM t WHERE score IS NULL

优化方式:可以给字段添加默认值0,对0值进行判断。如下:

SELECT * FROM t WHERE score = 0

7、尽量避免在where条件中等号的左侧进行表达式、函数操作,会导致数据库引擎放弃索引进行全表扫描。如下:

SELECT * FROM t2 WHERE score/10 = 9

SELECT * FROM t2 WHERE SUBSTR(username,1,2) = ‘li’

优化方式:可以将表达式、函数操作移动到等号右侧。如下:

SELECT * FROM t2 WHERE score = 10*9

SELECT * FROM t2 WHERE username LIKE ‘li%’

8、当数据量大时,避免使用where 1=1的条件。通常为了方便拼装查询条件,我们会默认使用该条件,数据库引擎会放弃索引进行全表扫描。如下:

SELECT * FROM t WHERE 1=1

优化方式:用代码拼装sql时进行判断,没where加where,有where加and。

3.减少全表扫描

https://www.cnblogs.com/huaxingtianxia/p/6478781.html

4.使用索引(注意索引事项)

https://www.cnblogs.com/heyonggang/p/6610526.html

索引虽然好处很多,但过多的使用索引可能带来相反的问题,索引也是有缺点的:

虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT,UPDATE和DELETE。因为更新表时,mysql不仅要保存数据,还要保存一下索引文件

建立索引会占用磁盘空间的索引文件。一般情况这个问题不太严重,但如果你在要给大表上建了多种组合索引,索引文件会膨胀很宽

  索引只是提高效率的一个方式,如果mysql有大数据量的表,就要花时间研究建立最优的索引,或优化查询语句。

5.分表分库(水平+垂直分割)

分库分表就是为了解决由于数据量过大而导致数据库性能降低的问题,将原来独立的数据库拆分成若干数据库组成 , 将数据大表拆分成若干数据表组成,使得单一数据库、单一数据表的数据量变小,从而达到提升数据库性能的目的。

分库分表包括分库和分表两个部分,在生产中通常包括:垂直分库、水平分库、垂直分表、水平分表四种方式。

垂直分表定义:将一个表按照字段分成多表,每个表存储其中一部分字段。

它带来的提升是:

1.为了避免IO争抢并减少锁表的几率,查看详情的用户与商品信息浏览互不影响

2.充分发挥热门数据的操作效率,商品信息的操作的高效率不会被商品描述的低效率所拖累。

通常我们按以下原则进行垂直拆分:

把不常用的字段单独放在一张表;
把text,blob等大字段拆分出来放在附表中;
经常组合查询的列放在一张表中;

通过垂直分表性能得到了一定程度的提升,但是还没有达到要求,并且磁盘空间也快不够了,因为数据还是始终限制在一台服务器,库内垂直分表只解决了单一表数据量过大的问题,但没有将表分布到不同的服务器上,因此每个表还是竞争同一个物理机的CPU、内存、网络IO、磁盘

垂直分库是指按照业务将表进行分类,分布到不同的数据库上面,每个库可以放在不同的服务器上,它的核心理念是专库专用。

它带来的提升是:

解决业务层面的耦合,业务清晰

能对不同业务的数据进行分级管理、维护、监控、扩展等

高并发场景下,垂直分库一定程度的提升IO、数据库连接数、降低单机硬件资源的瓶颈

垂直分库通过将表按业务分类,然后分布在不同数据库,并且可以将这些数据库部署在不同服务器上,从而达到多个服务器共同分摊压力的效果,但是依然没有解决单表数据量过大的问题。

水平分库是把同一个表的数据按一定规则拆到不同的数据库中,每个库可以放在不同的服务器上。

垂直分库是把不同表拆到不同数据库中,它是对数据行的拆分,不影响表结构

它带来的提升是:

解决了单库大数据,高并发的性能瓶颈。
提高了系统的稳定性及可用性。

水平分库是把同一个表的数据按一定规则拆到不同的数据库中,每个库可以放在不同的服务器上。

垂直分库是把不同表拆到不同数据库中,它是对数据行的拆分,不影响表结构

它带来的提升是:

解决了单库大数据,高并发的性能瓶颈。
提高了系统的稳定性及可用性。

https://blog.csdn.net/weixin_44062339/article/details/100491744

6.水平 取摸算法

https://blog.csdn.net/zhongxu_yuan/article/details/95112825

对于整型数a,b来说,取模运算是: 1.求 整数商: c = a/b; 2.计算模: a%b = a - c*b.

      例如:         9 % 4  = 9 - ( 9 / 4) * 4 = 1

                           9 %-4  =  9 - (  9 /-4) * -4  = 1

                          -9 %  4  = -9 - ( -9 / 4) * 4  =-1

                          -9 % -4  = -9 -( 9 / 4)  * -4  =-1
						 
						 java 为取余,而python则为取模。

7.主从复制 (mysql集群) 二进制日志文件

数据库自身提供的主从复制功能可以方便的实现数据的多处自动备份,实现数据库的拓展。多个数据备份不仅可以加强数据的安全性,通过实现读写分离还能进一步提升数据库的负载性能。

https://blog.csdn.net/zhangsanjie888/article/details/83652439

MySQL之间数据复制的基础是二进制日志文件(binary log file)。一台MySQL数据库一旦启用二进制日志后, 其作为master,它的数据库中所有操作都会以“事件”的方式记录在二进制日志中,其他数据库作为slave通过一个I/O线程与主服务器保持通信, 并监控master的二进制日志文件的变化,如果发现master二进制日志文件发生变化,则会把变化复制到自己的中继日志中, 然后slave的一个SQL线程会把相关的“事件”执行到自己的数据库中,以此实现从数据库和主数据库的一致性,也就实现了主从复制。

实现MySQL主从复制需要进行的配置:

主服务器:

开启二进制日志 配置唯一的server-id 设置需要同步的数据库 获得master二进制日志文件名及位置 创建一个用于slave和master通信的用户账号

从服务器:

配置唯一的server-id  使用master分配的用户账号读取master二进制日志 启用slave服务

8.读写分离(mycat)

读写分离,简单地说是把对数据库的读和写操作分开,以对应不同的数据库服务器。主数据库提供写操作,从数据库提供读操作,这样能有效地减轻单台数据库的压力。主数据库进行写操作后,数据及时同步到所读的数据库,尽可能保证读、写数据库的数据一致,比如MySQL的主从复制、Oracle的data guard、SQL Server的复制订阅等。

缓存机制

1.使用redis 缓存数据库内容

2.redis集群(主从复制)

主从复制可以把主节点的数据复制给从节点。从节点可以备份主节点的数据,起到主节点down调,顶上来接替主节点工作的作用。也可以起到分担主节点读压力的作用。

	1.一个master可以有多个slave
	2.除了多个slave连到相同的master外,slave也可以连接其他slave形成图状结构
	3.主从复制不会阻塞master。也就是说当一个或多个slave与master进行初次同步数据时,master可以继续处理client发来的请求。相反slave在初次同步数据时则会阻塞不能处理client的请求。
	4.主从复制可以用来提高系统的可伸缩性,我们可以用多个slave 专门用于client的读请求,比如sort操作可以使用slave来处理。也可以用来做简单的数据冗余
	5.可以在master禁用数据持久化,只需要注释掉master 配置文件中的所有save配置,然后只在slave上配置数据持久化。
	6.可以用于读写分离和容灾恢复。

3.redis读写分离

数据在【从服务器】里【读】,在【主服务器】里【写】。

这样就实现了redis数据库的读写分离功能。

4.使用redis哨兵机制监听

 为了实现redis故障转移的自动化。自动发现,自动转移。不需要人工参与。

服务器

反向代理

反向代理实际运行方式是指以代理服务器来接受连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给请求连接的客户端,此时代理服务器对外就表现为一个服务器。

反向代理的作用:

保证内网的安全。隐藏后端服务器的信息,屏蔽黑名单中的 IP,限制每个客户端的连接数。
提高可扩展性和灵活性。客户端只能看到反向代理服务器的 IP,这使你可以增减服务器或者修改它们的配置。
缓存。直接返回命中的缓存结果
静态内容直接返回: 
负载均衡,通过反向代理服务器来优化网站的负载

配置负载均衡

客户端将请求发送至服务器,然而一台服务器是无法承受很高的并发量的,我们就会将请求转发到其他服务器,当然真正的负载均衡架构并不是由一台server转发的另一台server,而在客户端与服务器端中间加入了一个负责分配请求的负载均衡硬件(软件)。

集群

多个服务器搭建一个集群

CDN加速

宽带传输也是有速度的,越近的访问速度越快,CDN加速就是多个地区进行部署 从进访问,减轻宽带的压力,从而加速

例子:上海的用户访问上海的服务器比广州的块

客户端

减少请求

用户体验好,最好使用ajax异步加载

动静分离

项目优化

代码重构

重构目的

重构的目的是使软件更容易被理解和修改 与之形成对比的是性能优化 和重构一样 性能优化通常不会改变组件的行为(除了执行速度) 只会改变其内部结构 但是两者出发点不同 性能优化往往使代码较难理解 但为了得到所需的性能你不得不那么做 重构不会改变软件可观察的行为 重构之后软件功能一如以往

为何重构

重构改进软件设计 重构使软件更容易理解 重构帮助找到bug 重构提高编程速度

JVM调优

一、JVM内存模型及垃圾收集算法

1.根据Java虚拟机规范,JVM将内存划分为:

New(年轻代)
Tenured(年老代)
永久代(Perm)

2.垃圾回收算法

垃圾回收算法可以分为三类,都基于标记-清除(复制)算法:

Serial算法(单线程)
并行算法
并发算法

二、内存泄漏及解决方法

三、性能调优

线程池:解决用户响应时间长的问题
连接池
JVM启动参数:调整各代的内存比例和垃圾回收算法,提高吞吐量
程序算法:改进程序逻辑算法提高性能

四.JVM参数

调优方法

一切都是为了这一步,调优,在调优之前,我们需要记住下面的原则:

1、多数的Java应用不需要在服务器上进行GC优化;

2、多数导致GC问题的Java应用,都不是因为我们参数设置错误,而是代码问题;

3、在应用上线之前,先考虑将机器的JVM参数设置到最优(最适合);

4、减少创建对象的数量;

5、减少使用全局变量和大对象;

6、GC优化是到最后不得已才采用的手段;

7、在实际使用中,分析GC情况优化代码比优化GC参数要多得多;