什么是高并发?
高并发(High Concurrency)是一种系统运行过程中遇到的一种“短时间内遇到大量操作请求”的情况,主要发生在web系统集中大量访问收到大量请求(例如:12306的抢票情况;天猫双十一活动)。该情况的发生会导致系统在这段时间内执行大量操作,例如对资源的请求,数据库的操作等。
高并发的处理指标?
高并发相关常用的一些指标有:
1.响应时间(Response Time)
响应时间:系统对请求做出响应的时间。例如系统处理一个HTTP请求需要200ms,这个200ms就是系统的响应时间
2.吞吐量(Throughput)
吞吐量:单位时间内处理的请求数量。
3.每秒查询率QPS(Query Per Second)
QPS:每秒响应请求数。在互联网领域,这个指标和吞吐量区分的没有这么明显。
4.并发用户数
并发用户数:同时承载正常使用系统功能的用户数量。例如一个即时通讯系统,同时在线量一定程度上代表了系统的并发用户数。
高并发和多线程的关系和区别
“高并发和多线程”总是被一起提起,给人感觉两者好像相等,实则 高并发 ≠ 多线程
多线程并发技术
多线程是java的特性,因为现在cpu都是多核多线程的,可以同时执行几个任务,为了提高jvm的执行效率,java提供了这种多线程的机制,以增强数据处理效率。多线程对应的是cpu,高并发对应的是访问请求,可以用单线程处理所有访问请求,也可以用多线程同时处理访问请求。
在过去单CPU时代,单任务在一个时间点只能执行单一程序。之后发展到多任务阶段,计算机能在同一时间点并行执行多任务或多进程。虽然并不是真正意义上的“同一时间点”,而是多个任务或进程共享一个CPU,并交由操作系统来完成多任务间对CPU的运行切换,以使得每个任务都有机会获得一定的时间片运行。
再后来发展到多线程技术,使得在一个程序内部能拥有多个线程并行执行。一个线程的执行可以被认为是一个CPU在执行该程序。当一个程序运行在多线程下,就好像有多个CPU在同时执行该程序。
总之,多线程是处理高并发的一种编程方法,java多线程并发编程一般会涉及到如下技术点:
1.并发编程三要素
- 原子性原子,即一个不可再被分割的颗粒。在Java中原子性指的是一个或多个操作要么全部执行成功要么全部执行失败。
- 有序性程序执行的顺序按照代码的先后顺序执行。(处理器可能会对指令进行重排序)
- 可见性当多个线程访问同一个变量时,如果其中一个线程对其作了修改,其他线程能立即获取到最新的值。
2. 线程的五大状态
- 创建状态当用 new 操作符创建一个线程的时候
- 就绪状态调用 start 方法,处于就绪状态的线程并不一定马上就会执行 run 方法,还需要等待CPU的调度
- 运行状态CPU 开始调度线程,并开始执行 run 方法
- 阻塞状态线程的执行过程中由于一些原因进入阻塞状态比如:调用 sleep 方法、尝试去得到一个锁等等
- 死亡状态run 方法执行完 或者 执行过程中遇到了一个异常
3.悲观锁与乐观锁
- 悲观锁:每次操作都会加锁,会造成线程阻塞。
- 乐观锁:每次操作不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止,不会造成线程阻塞。
4.线程之间的协作:wait/notify/notifyAll等
5.synchronized 关键字
6.CAS
CAS全称是Compare And Swap,即比较替换,是实现并发应用到的一种技术。操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。 如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值 。否则,处理器不做任何操作。
7.线程池
如果我们使用线程的时候就去创建一个线程,虽然简单,但是存在很大的问题。如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。线程池通过复用可以大大减少线程频繁创建与销毁带来的性能上的损耗。
高并发
高并发不是JAVA的专有的东西,是语言无关的广义的,为提供更好互联网服务而提出的概念。
典型的场景,例如:12306抢火车票,天猫双十一秒杀活动等。
该情况的发生会导致系统在这段时间内执行大量操作,例如对资源的请求,数据库的操作等。如果高并发处理不好,不仅仅降低了用户的体验度(请求响应时间过长),同时可能导致系统宕机,严重的甚至导致OOM异常,系统停止工作等。
如果要想系统能够适应高并发状态,则需要从各个方面进行提高高并发能力。
1.分布式缓存:redis、memcached等,结合CDN来解决图片文件等访问。
2.消息队列中间件:activeMQ等,解决大量消息的异步处理能力。
3.应用拆分:一个工程被拆分为多个工程部署,利用dubbo解决多工程之间的通信。
4.数据库垂直拆分和水平拆分(分库分表)等。
5.数据库读写分离,解决大数据的查询问题。
6.还可以利用nosql ,例如mongoDB配合mysql组合使用。
7.还需要建立大数据访问情况下的服务降级以及限流机制等。
高并发、多线程
1.高并发
高并发是请求,指的是多个客户端同一时刻向服务端发送请求, 它是一种现象。
比如,在双11凌晨12:00分同时有10万个下单请求。
高并发标准:
1)高并发用户数
2)TPS(Transactions Per Second)每秒事务数
3)QPS(Query Per Second)每秒查询率等。
2.多线程
多线程是处理,指的是同一时刻多个执行者处理同一类的任务, 它有具体的实现。
比如,电商网站在双11凌晨12:00分同时有100个线程处理2000个下单请求。
3.并发
多个线程操作相同的资源,保证线程安全,合理使用资源。
多线程技术
1:并发基础
2:并发锁
3:并发工具类
4:集合&并发容器
ArrayList、Vector、LinkedList等区别详解
5:并发队列
6:并发其它
高并发架构技术
1、Redis为代表的分布式缓存技术
2、RocketMQ为代表的分布式消息队列技术
4、Dubbo为代表的服务架构技术
5、数据库层分库分表等技术
6、亿级负载均衡技术
7、熔断限流等技术
8、高并发秒杀等技术
大型Web网站的特点如下:
大型Web网站的技术挑战主要来自于大量的用户,高并发的访问和海量的数据存储,任何简单的业务一旦需要处理TB级别的数据和面对数以亿计的用户,问题就会变得很棘手。那么如何打造一个高可用、高性能、易扩展、可伸缩且安全的网站?首先要从架构方面入手,以高性能架构为基础,辅以优化后的前端应用(如减少Http请求,终端缓存等等)和后台程序(如Jvm优化,操作系统优化等等)即可以构建一个高性能的Web网站。
首先我们来了解下构建一个高性能Web网站时,性能的瓶劲在哪里?如下图所示:
从上图可以分析出性能瓶劲主要表现在两个方面:
1、 硬件资源层面,如不同运营上的网络,服务器的带宽限制,服务器的CPU、内存及磁盘IO等;
2、 软件层面,Web应用程序的性能,数据库服务器的性能;
硬件资源的提升对性能的提升时逐级递减的直至趋于0,所以性能的提高不能通过无休止的增加硬件资源,所以我们就要考虑如何从软件架构的层面来提供性能,下图为高性能架构的主要思路:
架构思路的说明如下:
1、 负载均衡,包括早期的使用DNS负载均衡,四层交换的负载均衡及七层交换的负载均衡;一般业界多采用硬件四层交换负载均衡和软件四层交换负载均衡,硬件四层交换负载均衡优势时稳定性高,功能强大,但价格较高,一般的公司难以承受,典型产品是F5、A10;软件四层交换负载均衡的优势是免费开源,通过热备等方式也可以构建一个稳定性高的负载均衡,所以我们的首选软件四层交换负载均衡(即LVS)
2、 高可用性方面要考虑避免单点故障,需要引入热备(包括主从和主主两种方式),集群以及灾备;
3、 Web应用开发架构方面要选择合适的应用开发框架同时考虑将动态页面进行静态化并进行静态资源(图片,CSS,JS及页面)的缓存(此点建议使用Nginx或者Varnish进行缓存);数据存储方面考虑使用分布式存储系统(需要根据所存储文件的大小选择合适的存储系统,比如一般的图片文件和视频文件选择的存储系统就会有所不同,前者一般可以选择FastDFS,后者选择HDFS)以及引入数据缓存(如Redis集群)和NoSql数据库(也叫内存数据库,比如:MongoDB)
4、 数据库方面需要考虑进行读写分离,分库、分表、分区等;
5、 网络方面引入CDN来解决不同网络服务商的接入速度问题并考虑在不同运营商机房部署服务器,通过镜像技术来实现不同网络服务商的接入速度问题。
Web应用架构的演化历程:
Web应用架构的特点如下图
微服务架构有其明显的优势,已经是目前及未来Web应用架构的首选,其缺点是:微服务过多,服务治理成本高,不利于系统维护;分布式系统开发的技术成本高(容错、分布式事务等),对团队挑战大;所以如果是一般初学者建议还是选择先从MVC架构开始。
综合以上的简单分析,我们可以大致得出高性能的架构如下图:
1、 使用LVS作为软件四层交换负载均衡并使用Heartbeat实现双机热备;
2、 使用反向代理软件来实现数据缓存(静态资源缓存),此处我们可以选择使用Nginx或者Varnish
3、 Web应用框架可以更加系统规模进行选择,小编建议初学者选择先从MVC架构开始;
4、 数据持久化层使用MyBatis以提高性能,数据缓存使用Redis集群;
5、 分布式存储选择HDFS并引入NoSql数据库,数据库方面实现读写分离和热备,必要的时候还需要分库分表等;
--------------------------------------------------------------------------------------------------------------------
高并发设计的技术方案
1.负载均衡
2.分布式微服务
3.缓存机制
4.分布式关系型数据库
4.1 垂直分表
4.2 水平分表
4.3 开源框架分类
4.4 实现方案
5.分布式消息队列
5.1 常见的消息队列
5.2 消息队列的场景
6.CDN 内容分发网络
7.其他
8.总结
————————————————
1.负载均衡
靠优化单台机器的内存、CPU、磁盘、网络带宽,使其发挥极致性能,已经不太现实。
负载均衡,它的职责是将网络请求 “均摊”到不同的机器上。避免集群中部分服务器压力过大,而另一些服务器比较空闲的情况
通过负载均衡,可以让每台服务器获取到适合自己处理能力的负载。在为高负载服务器分流的同时,还可以避免资源浪费,一举两得。
常见的负载算法:
- 随机算法
- 轮询算法
- 轮询权重算法
- 一致性哈希算法
- 最小连接
- 自适应算法
常用负载均衡工具:
- LVS
- Nginx
- HAProxy
对于一些大型系统,一般会采用 DNS+四层负载+七层负载的方式进行多层次负载均衡。
————————————————
2.分布式微服务
每个微服务独立部署,服务和服务间采用轻量级的通信机制,如:标准的HTTP协议、或者私有的RPC协议。
微服务特点:
按照业务划分服务,单个服务代码量小,业务单一,容易维护
每个微服务都有独立的基础组件, 例如数据库
微服务之间的通信为Http 协议或者其他协议, 具有容错性
微服务有一定的治理方案, 服务之间不耦合, 可以随时加入和删除
单个微服务可以集群部署, 有负载均衡的能力
整个微服务有安全机制, 包括用户验证, 权限验证, 资源保护
整个微服务有链路跟踪的能力
有完整的实时日志系统
市面常用微服务框架有:Spring Cloud 、Dubbo 、kubernetes、gRPC、Thrift 等
常用的注册中心有:Zookeeper、etcd、Eureka、Nacos、Consul
需要注意一些很复杂的问题
- 分布式事务
- 限流机制
- 熔断机制
- 网关
- 服务链路跟踪
————————————————
3.缓存机制
性能不够,缓存来凑。要想快速提升性能,缓存肯定少不了
缓存能够带来性能的大幅提升,以 Memcache 为例,单台 Memcache 服务器简单的 key-value 查询能够达到 TPS 50000 以上;Redis性能数据是10W+ QPS
常见的缓存分为本地缓存和分布式缓存,区别在与是否要走网络通讯。
本地缓存是部署在应用服务器中,而我们应用服务器通常会部署多台,当数据更新时,我们不能确定哪台服务器本地中了缓存,更新或者删除所有服务器的缓存不是一个好的选择,所以我们通常会等待缓存过期。因此,这种缓存的有效期很短,通常为分钟或者秒级别,以避免返回前端脏数据。
分布式缓存采用集群化管理,支持水平扩容,并提供客户端路由数据,数据一致性维护更好。虽然有不到 1ms 的网络开销,但比起其优势,这点损耗微不足道。
缓存更新常用策略:
Cache aside,通常会先更新数据库,然后再删除缓存,为了兜底还会设置缓存时间。
Read/Write through, 一般是由一个 Cache Provider 对外提供读写操作,应用程序不用感知操作的是缓存还是数据库。
Write behind,延迟写入,Cache Provider 每隔一段时间会批量写入数据库,大大提升写的效率。像操作系统的page cache也是类似机制。
————————————————
4.分布式关系型数据库
MySQL数据库采用B+数索引,三层结构,为了保证IO性能,一般建议单表存储 千万 条数据.
分表又可以细分为 垂直分表 和 水平分表 两种形式。
4.1 垂直分表
数据表垂直拆分就是纵向地把一张表中的列拆分到多个表,表由“宽”变“窄”,简单来讲,就是将大表拆成多张小表,一般会遵循以下几个原则:
冷热分离,把常用的列放在一个表,不常用的放在一个表。
字段更新、查询频次拆分
大字段列独立存放
关系紧密的列放在一起
4.2 水平分表
表结构维持不变,对数据行进行切分,将表中的某些行切分到一张表中,而另外的某些行又切分到其他的表中,也就是说拆分后数据集的并集等于拆分前的数据集。
SQl组合。因为是逻辑表名,需要按分表键计算对应的物理表编号,根据逻辑重新组装动态的SQL
数据库路由。如果采用分库,需要根据逻辑的分表编号计算数据库的编号
结果合并。如果查询没有传入指定的分表键,会全库执行,此时需要将结果合并再输出。
4.3 开源框架分类
Proxy模式。SQL 组合、数据库路由、执行结果合并等功能全部存放在一个代理服务中,业务方可以当做。
支持多语言, 但是引入一个中间件, 会形成流量瓶颈, 安全风险高, 运维成本高
Client 模式。常见是 sharding-jdbc,业务端系统只需要引入一个jar包即可,按照规范配置路由规则。jar 中处理 SQL 组合、数据库路由、执行结果合并等相关功能。
简单, 轻便, 减少了流量瓶颈与运维成本, 但是单语言, 升级不方便
4.4 实现方案
如何选择分表键。
数据尽量均匀分布在不同表或库、跨库查询操作尽可能少、这个字段的值不会变。比如电商订单采用user_id。
基因分库分表
数据存储中,相互关系的表,尽量分库时落到同一个库中,避免遍历多个库查询,而且还能避免分布式事务。
一般分库或者分表我们采用取余操作,余数相同的id落到相同的库中,或分表规则一致。
分片策略。
根据范围分片、根据 hash 值分片、根据 hash 值及范围混合分片
历史数据迁移
增量数据监听 binlog,然后通过 canal 通知迁移程序开始增量数据迁移
开启任务,全量数据迁移
开启双写,并关闭增量迁移任务
读业务切换到新库
线上运行一段时间,确认没有问题后,下线老库的写操作
数据量大,就分表;并发高,就分库
在实际的业务开发中,要做好数据量的增长预测,做好技术方案选型。另外,在引入分表方案后,要考虑数据倾斜问题,这个跟分表键有很大关系,避免数据分布不均衡影响系统性能
————————————————
5.分布式消息队列
并不是所有的调用都要走同步形式,对于时间要求不高、或者非核心逻辑,我们可以采用异步处理机制。
消息队列主要有三种角色:生产者、消息队列、消费者。两者之间通过消息中间件完成了解耦,系统的扩展性非常高。
5.1 常见的消息队列
ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaQ,RocketMQ、Pulsar 等
5.2 消息队列的场景
异步处理。将一个请求链路中的非核心流程,拆分出来,异步处理,减少主流程链路的处理逻辑,缩短RT,提升吞吐量。如:注册新用户发短信通知。
削峰填谷。避免流量暴涨,打垮下游系统,前面会加个消息队列,平滑流量冲击。比如:秒杀活动。生活中像电源适配器也是这个原理。
应用解耦。两个应用,通过消息系统间接建立关系,避免一个系统宕机后对另一个系统的影响,提升系统的可用性。如:下单异步扣减库存
消息通讯。内置了高效的通信机制,可用于消息通讯。如:点对点消息队列、聊天室。
————————————————
6.CDN 内容分发网络
目的是在现有的网络中增加一层网络架构,将网站的内容发布到最接近用户的网络“边缘”,使用户可以就近取得所需的内容,提高用户访问网站的响应速度。
CDN = 镜像(Mirror)+缓存(Cache)+整体负载均衡(GSLB)
CDN都以缓存网站中的静态数据为主,如:CSS、JS、图片和静态页面等数据。用户从主站服务器中请求到动态内容后,再从CDN下载静态数据,从而加速网页数据内容的下载速度。
CDN 特点:
本地Cache加速
镜像服务
远程加速
带宽优化
集群抗攻击
CDN 应用场景
网站站点/应用加速
视音频点播/大文件下载分发加速
视频直播加速
移动应用加速
————————————————
7.其他
分布式文件系统、大数据、NoSQL、NewSQL,慢慢也开始成为高并发系统的周围框架生态补充。
8.总结
本文列举了高并发设计的技术方案:
1 负载均衡 2.分布式微服务 3. 缓存 4.分布式数据库 6.消息队列 7.CDN
其实还有分布式锁等, 分布式锁可以通过redis, zk, mysql, etcd去实现
————————————————
【高并发解决方案】
一、对于被频繁调用,更新频率较低的页面,可以采用HTML静态化技术
二、图片服务器分离
三、数据库集群和库表散列
mysql主从。m-m-s-s-s...(2个主,多个从。多个从使用负载均衡。主写入数据,从读取数据)
四、缓存。众多的缓存框架
五、负载均衡。nginx,lvs,F5
六、搜索用单独的服务器,搜索框架
七、使用MQ服务器
-----------------------------------
集群主要分成三大类:
高可用集群(High Availability Cluster/HA),
负载均衡集群(Load Balance Cluster),
高性能计算集群(High Performance Computing Cluster/HPC)
秒杀架构设计理念
限流: 鉴于只有少部分用户能够秒杀成功,所以要限制大部分流量,只允许少部分流量进入服务后端。
削峰:对于秒杀系统瞬时会有大量用户涌入,所以在抢购一开始会有很高的瞬间峰值。高峰值流量是压垮系统很重要的原因,所以如何把瞬间的高流量变成一段时间平稳的流量也是设计秒杀系统很重要的思路。实现削峰的常用的方法有利用缓存和消息中间件等技术。
异步处理:秒杀系统是一个高并发系统,采用异步处理模式可以极大地提高系统并发量,其实异步处理就是削峰的一种实现方式。
内存缓存:秒杀系统最大的瓶颈一般都是数据库读写,由于数据库读写属于磁盘IO,性能很低,如果能够把部分数据或业务逻辑转移到内存缓存,效率会有极大地提升。
可拓展:当然如果我们想支持更多用户,更大的并发,最好就将系统设计成弹性可拓展的,如果流量来了,拓展机器就好了。像淘宝、京东等双十一活动时会增加大量机器应对交易高峰。