业务设计
幂等:就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用,就像数学里的数字1,多少次幂的结果都是1。举个最简单的例子,那就是支付,用户购买商品后支付,支付扣款成功,但是返回结果的时候网络异常,此时钱已经扣了,用户再次点击按钮,此时会进行第二次扣款,返回结果成功,用户查询余额发现多扣钱了,流水记录也变成了两条...
详细内容参考 《分布式中的幂等性》https://www.cnblogs.com/vveiliang/p/6643874.html
防重:防止同样的数据同时提交
除了在业务方向判断和按钮点击之后不能继续点击的限制以外,在服务器端也可以做到防重:
在服务器端生成一个唯一的随机标识号(Token<令牌>)同事在当前用户的Session域中保存这个令牌,然后将令牌发送到客户端的form表单中,在form表单中使用隐藏域来存储这个Token,表单提交的时候联通这个Token一起提交到服务器,然后在服务器端判断客户提交上来的Token与服务器端生成的Token是否一致,如果不一致,那就重复提交了,此时服务器端就可以不处理重复提交的表单,如果相同则处理表单,处理完后清楚当前用户的Session域中存储的标识号。
在下列情况中,服务器程序将拒绝处理用户提交的表单请求:
1)存储Session域中的Token与表单提交的Token不一致
2)当前用户的Session中不存在Token 3)用户提交的表单数据中没有Token。
限流方式:
1. 限制瞬时并发数 : 比如在入口层(nginx添加nginx_http_limit_conn_module)来限制同一个ip来源的连接数,防止恶意攻击访问的情况。
2. 限制总并发数:通过配置数据库连接池、线程池大小来约束总并发数
3. 限制时间窗口内的平均速率:在接口层面,通过限制访问速率来控制接口的并发请求。
4. 其他方式:限制远程接口的调用速率、限制MQ的消费速率。
常用限流算法
1. 滑动窗口协议:一种常见的流量控制技术,用来改善吞吐量的技术。
滑动窗口协议的由来:
滑动窗口(sliding window)是一种流量控制技术。早期的网络通讯中,通信双方不会考虑网络的拥挤情况直接发送数据。由于大家不知道网络拥塞状况,同时发送数据,导致中间节点阻塞掉包,谁也发送不了数据,所以就有了滑动窗口机制来解决此问题。 发送和接收方都会维护一个数据帧的序列,这个序列被称为窗口。
定义:滑动窗口协议(Sliding Window Protocol),属于TCP协议的一种应用,用于网络数据传输时的流量控制,以避免拥塞的发生。该协议允许发送方在停止并等待确认前发送多个数据分组。由于发送方不必每发一个分组就停下来等待确认,因此该协议可以加速数据的传输,提高网络吞吐量。
发送窗口:就是发送端允许连续发送的帧的序号表。发送端可以不等待应答而连续发送数据(可以通过设置窗口的尺寸来控制)
接收窗口:接收方允许接收的帧的序列表,凡是落在接收窗口内的帧,接收方都必须处理,落在接收窗口外的帧将被丢弃。接收方每次允许接收的帧数称为接收窗口的尺寸
2. 漏桶:漏桶算法能强行限制数据的传输速率。
3. 令牌桶:属于控制速率类型的限流算法。
4. 计数器:最简单的一种。通过控制时间段内的请求次数。
https://mp.weixin.qq.com/s/qeDFklNlvlP9o2uqVtTmdg
限流算法有:令牌桶、漏桶。计数器也可以用来进行粗暴限流实现。
一般开发高并发系统场景的限流有:
限制总并发数(比如数据库连接池、线程池)、
限制瞬时并发数(如Nginx的limit_conn模块,用来限制瞬间并发连接数)、
限制时间窗口内的平均速率(如Guava的RateLimiter、Nginx的limit_req模块,用来限制每秒的平均速率),
以及限制远程接口调用速率、限制MQ的消费速率等。
另外还可以根据网络连接数、网络流量、CPU或内存负载等来限流。
https://my.oschina.net/u/3705388/blog/1631547
分布式限流实践
https://my.oschina.net/u/3705388/blog/1806229
降级
-
页面降级。
-
页面片段降级。
-
页面异步请求降级。
-
服务功能降级。
-
读降级。比如多级缓存模式,如果后端服务有问题,则可以降级为只读缓存,这种方式是用于对读一致性要求不高的场景。
-
写降级。比如秒杀抢购我们可以只进行Cache的更新,然后异步扣减库存到DB,保证最终一致性即可,此时可以将DB降级为Cache。
-
爬虫降级。
-
风控降级。
http://blog.csdn.net/foreverling/article/details/78011726
应用限流
Tomcat
在Tomcat容器中,我们可以通过自定义线程池,配置最大连接数,请求处理队列等参数来达到限流的目的。
Tomcat默认使用自带的连接池,这里我们也可以自定义实现,打开/conf/server.xml文件,在Connector之前配置一个线程池:
-
<Executor name="tomcatThreadPool"
-
namePrefix="tomcatThreadPool-"
-
maxThreads="1000"
-
maxIdleTime="300000"
-
minSpareThreads="200"/>
-
name:共享线程池的名字。这是Connector为了共享线程池要引用的名字,该名字必须唯一。默认值:None;
-
namePrefix:在JVM上,每个运行线程都可以有一个name 字符串。这一属性为线程池中每个线程的name字符串设置了一个前缀,Tomcat将把线程号追加到这一前缀的后面。默认值:tomcat-exec-;
-
maxThreads:该线程池可以容纳的最大线程数。默认值:200;
-
maxIdleTime:在Tomcat关闭一个空闲线程之前,允许空闲线程持续的时间(以毫秒为单位)。只有当前活跃的线程数大于minSpareThread的值,才会关闭空闲线程。默认值:60000(一分钟)。
-
minSpareThreads:Tomcat应该始终打开的最小不活跃线程数。默认值:25。
配置Connector
-
<Connector executor="tomcatThreadPool"
-
port="8080" protocol="HTTP/1.1"
-
connectionTimeout="20000"
-
redirectPort="8443"
-
minProcessors="5"
-
maxProcessors="75"
-
acceptCount="1000"/>
-
executor:表示使用该参数值对应的线程池;
-
minProcessors:服务器启动时创建的处理请求的线程数;
-
maxProcessors:最大可以创建的处理请求的线程数;
-
acceptCount:指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理。
https://mp.weixin.qq.com/s/smuUEAhZAHtPCz5vbDqhFQ