的业务系统进行垂直化改造,以业务功能为维度拆分出多个子系统,这样做就是为了能够更清晰地规划和体现出每个子系统的职责,降低业务稠合,以及提升容错性。但是在多元化的业务需求下,子系统中一定会存在较多的共享业务,这些共享业务肯定会被重复建设,产生较多的冗余业务代码。而且,业务系统中数据库连接之类的底层资源必然会限制业务系统所允许横扩的节点数量,因为在横扩过程中,连接数是机器数的平方。除了共享业务重复建设和资源连接受限,还有一个不容忽视的问题,当业务做大时,技术团队的人员规模也开始膨胀,太多人共同维护一个系统肯定会坏事,尤其是那些“手潮”的同学,经常会导致SVN 中的版本冲突。因此为了避免这些问题,服务化架构( SOA )改造刻不容缓。
SOA好处:原本共享的业务被拆分,形成可复用的服务,可以在最大程度上避免共享业务的重复建设、资源连接瓶颈等问题出现
什么是微服务:所谓的微服务架构,从宏观上来看,无非就是细化了服务拆分过程中的粒度,粒度越细,业务稠合越小,容错性越好,并且后期扩展会越容易
RPC调用过程:·1、底层的网络通信协议处理。2、解决寻址问题。3、请求/响应过程中参数的序列化和反序列化工作。RPC 的本质就是屏蔽上述复杂的底层处理细节,让服务提供方和服务调用方都能够以一种极其简单的方式(甚至简单到就像是在实现一个本地方法和调用一个本地方法一样)来实现服务的发布和调用,使开发人员只需要关注自身的业务逻辑即可
限流算法
1 . 令牌桶算法:
· 每秒会有r 个令牌被放人桶内,也就是说, 会以1/r 秒的平均速率向桶中依次
放人令牌(比如每秒共放人10 个令牌,那么每0 . 1 秒放人1 个令牌):
· 桶的容量是固定不变的,假设桶中最多只允许存放b 个令牌,如果桶满了再
放人令牌,则溢出(新添加的令牌被丢弃) ;
· 当一个n 字节的请求包到达时,将消耗n 个令牌,然后再发送该数据包;
· 若桶中的可用令牌数小于n ,则该数据包将会被执行限流处理(被抛弃或缓存)。
2. 漏桶算法:
·可以以任意速率向桶中流人水滴;
·桶的容量是固定不变的,如果桶满了则溢出(新流人的水滴被丢弃) I
·按照固定的速率从桶中流出水滴。
Guava 实现平均速率限流:
public void limit(){
final RateLimiter limit=RateLimit.create(5);//每秒向桶中存放5 个Token
for(int i=0;i<10;i++){
double waitTime=limit.acquire();//获取一个Token
System.out.println(waitTime);
}}
public void limit () {
RateLimiter lim 工t = RateL 工miter . create(5) ;//每秒中向桶中存放5 个Token
System.out.println(limit.acquire(5));//产生突发流量时, 一次从桶中获取5 个Token
System.out.println(limit.acquire()) ;
}
除了标准的平均速率限流,如果希望系统在启动时的限流速率从慢速逐渐过渡
到平均速率,给系统一个缓冲时间,那么RateLimiter 也提供有相应的支持,只需要
在create()方法中设置缓冲时间即可:
RateLimiter .create(S, 1, TimeUnit.SECONDS);
在create(double permitsPerSecond, long warmupPeriod, Time Unit unit)方法中, 参
数“warmupPeriod”用于设置限流速率从慢速过渡到平均速率的缓冲时间,参数“unit”
则用于设置缓冲时间单位。在此需要注意,假设请求被执行限流后,我们不希望请
求一直处于等待状态获取Token ,而是直接丢弃或短暂等待,那么便需要使用
RateLimiter 提供的tryAcquire()方法:
boolean result = limit.tryAcquire() ;//尝试从桶中获取Token ,获取不到不等待立即返回false
if (result ) {
System . out . println { ”成功获取到Token " ) ;
result= limit.tryAcquire(10, TimeUnit.MILLISECONDS) ;//尝试从桶中获取Token ,只等待10ms
if (result) {
System . out . println { " 成功获取到Token " );
}
用Nginx 实现接入层限流:
http{
#定义每个IP的session空间大小
limit_zone one $binary_remote_addr 20m
#定义每个IP每秒允许发起的请求数
limit_req_zone $binary_remote_addr zone=req_one:20m rate=10r/s
#定义每个IP能够发起的并发连接数
limit_conn one=10
#缓存还没来得及处理的请求,存不下的就拒绝
limit_req zone=req_one burst=100
server{
listen 80;
server_name localhost;
location /{
stub_status on;
access_log off;
}
}
}
使用计数器算法实现商品抢购限流:
public boolean limit(List<String> skus) {
if (检测限流开关是否打开) {
if (null != skus && !skus.isEmpty()) {
/ * key 为SKU, value 为可抢购的剩余次数*/
Map<String, Integer> skuMap =获取被限流的SKU 名单;
synchronized (skuMap) {
try {
for (String sku : skus) {
/*检查目标SKU 是否包含在限流名单中*/
if (skuMap.containsKey(sku)) {
while_skus . add(sku);
/* 如果抢购次数达到阑值,则不允许下单*/
if (0 >= skuMap . get(sku))
return false;
}
}
for(String sku :while_skus){
skuMap.put(sku,skuMap.get(sku)-1);
}
}finally{
if(!while_skus.isEmpty()){
while_skus.clear();
}
}}}}
return true;
}
基于时间分片的消峰方案:
所谓消峰,其实指的就是对峰值流量进行分散处理,避免在同一时间段内产生
较大的用户流量冲击系统,从而降低系统的负载压力。接下来笔者就为大家讲解如
何在业务上做调整来实现流量消峰。
活动分时段进行实现消峰;通过答题验证实现消峰