微服务解决方案:
1.SpringCloud(Netfilx和阿里巴巴)
2.Dubbo+ Zookeeper(CP具有一致性,分区容错性)
同步服务后才能请求,
3.istio(服务网格化)->谷歌公司的服务网格化
我的解决方案
注册配置中心:服务总线:Nacos:AP-可用性,分区容错性
**服务调用:**OpenFeign
**服务调用-负载均衡:**LoadBalaner
网关:Gateway
流控,熔断降级:Sentinel
链路追踪:Sleuth+Zipki
三高:高并发、高可用、高性能。
1.注册配置中心
注册配置中心,服务总线(涉及到CAP的选择问题)
- Nacos:AP-可用性,分区容错性
- Zookeeper:CP一致性,分区容错性,走的是文件操作
- consul
- Eureka: AP-可用性,分区容错性
C:表示一致性
A:可用性
P:分区容错性
base理论:
基本一致性(并不是强一致性)和分区容错性。最后达到一个最终一致性。
服务的注册发现
服务注册的策略的是每5秒向nacos server发送一次心跳,
心跳带上了服务名,服务ip,服务端口等信息。
同时 nacos server也会向client 主动发起健康检查,支持tcp/http检查。
如果15秒内无心跳且健康检查失败则认为实例不健康,如果30秒内健康检查失败则剔除实例。
配置的动态管理
普通application参数在配置中心直接配置,如果需要可以动态刷新的配置,
需要在相应类上加上
@RefreshScope注解,当在nacos配置中心更改配置后,方法getId的值也会刷新。
可视化设置
2.服务调用:
- OpenFeign
- Feign
服务调用-负载均衡
- LoadBalaner
- Ribbon
OpenFeign
使用
参数
消息头
负载均衡
超时控制:
OpenFeign默认调用的服务超时时间为1s,如果超过会报错
http协议调用远程接口。
什么是OpenFeign?
OpenFeign是一种声明式、模板化的HTTP客户端。在Spring Cloud中使用OpenFeign,可以做到使
用HTTP请求访问远程服务,就像调用本地方法一样的,
3.网关
作用:
过滤器就是在请求的传递过程中,对请求和响应做一些修改
- Gateway
- zuul
- zuul2
过滤器
全局: 作用全部路由上
负载均衡客户端过滤器LoadBalancer
LoadBalancerClientFilter
通过负载均衡客户端根据路由的URL解析转换成真是的请求URL
http客户端相关过滤器HttpClient
NettyRoutingFilter
NettyWriteResponseFilter
通过HttpClient客户端转发请求真实的URL并将响应写入到当前的请求响应中
Websocket相关过滤器Websocket
路径转发相关过滤器ForwardPath
路由ur|相关过滤器RouteToRequestUrl
WebCliet相关过滤器WebClient
局部:作用在某一个路由上
内置局部过滤器
routes:
- id: service-edu
uri: lb://service-edu
predicates:
- Path=/user/**, /*/edu/**
filters:
- SetStatus=250 # 修改返回状态
自定义过滤器
定义一个Filter实现 GlobalFilter 和 Ordered接口
路由匹配转发
通过时间匹配(datetime)
通过配置predicated 的 Before ,After ,Between 等属性,可以实现限制路由转发的时间段。
时间对比:Spring 是通过 ZonedDateTime 来对时间进行的对比,ZonedDateTime 是 Java 8 中日期时间功能里,用于表示带时区的日期与时间信息的类
通过Cookie匹配(Cookie)
Cookie Route Predicate 可以接收两个参数,一个是 Cookie name ,一个是正则表达式,路由规则会通过获取对应的 Cookie name 值和正则表达式去匹配,如果匹配上就会执行路由,如果没有匹配上则不执行。
通过 Header 属性匹配(Header)
Header Route Predicate也是接收 2 个参数,一个 header 中属性名称和一个正则表达式,这个属性值和正则表达式匹配则执行
通过Host匹配(Host)
Host Route Predicate 接收一组参数,一组匹配的域名列表,这个模板是一个 ant 分隔的模板,用
.号作为分隔符。它通过参数中的主机地址作为匹配规则通过请求方式匹配(Method)
可以通过是 POST、GET、PUT、DELETE 等不同的请求方式来进行路由
通过请求路径匹配(Path)
Path Route Predicate 接收一个匹配路径的参数来判断是否走路由,以上的例子都用了Path匹配
通过请求 ip 地址进行匹配(RemoteAddr)
Predicate 也支持通过设置某个 ip 区间号段的请求才会路由,RemoteAddr Route Predicate 接受 cidr 符号(IPv4 或 IPv6 )字符串的列表(最小大小为1),例如 192.168.0.1/16 (其中 192.168.0.1 是 IP 地址,16 是子网掩码)
如果请求的远程地址是 192.168.1.10,则此路由将匹配。
4.流控,熔断降级
- Sentinel
- resilience4j
流量阈值:可视化界面,设置QPS单机阈值,200左右。
服务降级:用到的注解@SentinelResource(value = “doSomeThing”)
降级触发:(RT、异常率、异常数)
异常数:
异常数 (
DEGRADE_GRADE_EXCEPTION_COUNT):当资源近 1 分钟的异常数目超过阈值之后会进行熔断。
由于统计时间窗口是分钟级别的,若
timeWindow小于 60s,则结束熔断状态后仍可能再进入熔断状态。
5.链路追踪
- Sleuth+Zipkin
解决的问题:
微服务跟踪(sleuth)在整个分布式系统中能跟踪一个用户请求的过程
(包括数据采集,数据传输,数据存储,数据分析,数据可视化),
捕获这些跟踪数据,就能构建微服务的整个调用链的视图,这是调试和监控微服务的关键工具。
Zipkin
是辅助我们查询跟踪数据以实现对分布式系统的监控程序
Zipkin 是 Twitter 的一个开源项目,它基于 Google Dapper 实现,
它用于收集服务的定时数据,以解决微服务架构中的延迟问题,
包括数据的收集、存储、查找和展现。
可以使用它来收集各个服务器上请求链路的跟踪数据,通过它提供的 REST API 接口,
来辅助我们查询跟踪数据以实现对分布式系统的监控程序,
从而及时地发现系统中出现的延迟升高问题并找出系统性能瓶颈的根源。
除了面向开发的 API 接口之外,它也提供了方便的 UI 组件来帮助我们直观的搜索跟踪信息和分析请求链路明细,
比如:可以查询某段时间内各用户请求的处理时间等。 Zipkin 提供了可插拔数据存储方式:In-Memory、MySql、Cassandra 以及 Elasticsearch。
6.分布式锁
Redis的RedLock,属于非公平锁。
同一时刻,只能有一个客户端持有锁。
三种实现方式
- 基于数据库实现分布式锁
- 基于Redis实现分布式锁
- 基于zookeeper实现分布式锁
实现步骤
Redission引入包
初始化一个客户端。
redission.getLock();获得锁
分布式锁,锁的是优惠券ID
使用命令介绍:
(1)SETNX
SETNX key val:当且仅当key不存在时,set一个key为val的字符串,返回1;若key存在,则什么都不做,返回0。
(2)expire(设置定期删除)
expire key timeout:为key设置一个超时时间,单位为second,超过这个时间锁会自动释放,避免死锁。
(3)delete
delete key:删除key
配置分布式锁
在nginx中配置Tomcat实例
设置一下本地路径
应用场景
防止优惠劵的超发
死锁
分布式锁的内部代码没执行完,出现了异常,当前的key会永远的留在Redis中,就会发生死锁。
防止死锁
设置一个
try{ ... }catch{ e.Exception(); }finaly{ stringRedisTemplate.delete(key值); }设置一个5秒的过期时间,当过期以后自动去删除这个key
删除分布式锁
stringRedisTemplate.delete(key值);
锁续命
如果分布式锁过期了还没处理完,就要进行续命。
当一个线程获取到锁以后,会自动开启一个守护线程(看门狗),每隔10秒(超时时间的三分之一),来监听当前线程,是否还持有锁,可以用用来给锁续命
怎么判断是不是当前线程自己的锁?
根据线程ID判断
如果分布式锁过期了还没处理完,除了“续命”这种操作,也可以进行一个超时回滚。
锁的主从复制问题
问题:锁在Redis主从复制的时候,还未从主节点复制到从结点时,主节点挂了,key就消失了。
解答:设置一个哨兵将主节点的关键信息备份到哨兵,然后哨兵去随机原则一个从服务器,将原来的信息同步上去。
7.调用一个公用的实体类
调用服务一般是在消费者,里写个接口,接口里写上生产者中controller里的方法
(路径也要与controller中的一致),然后让其他类通过这个接口调用另一个服务的方法。
8.nginx负载均衡策略
在服务器集群中,Nginx起到一个代理服务器的角色(即反向代理),
为了避免单独一个服务器压力过大,将来自用户的请求转发给不同的服务器。
使用流程
负载均衡用于从“upstream”模块定义的后端服务器列表中选取一台服务器接受用户的请求。一个最基
本的upstream模块是这样的,模块内的server是服务器列表:
#动态服务器组
upstream dynamic_zuoyu {
server localhost:8080; #tomcat 7.0
server localhost:8081; #tomcat 8.0
server localhost:8082; #tomcat 8.5
server localhost:8083; #tomcat 9.0
}
在upstream模块配置完成后,要让指定的访问反向代理到服务器列表:
#其他页面反向代理到tomcat容器
location ~ .*$ {
index index.jsp index.html;
proxy_pass http://dynamic_zuoyu;
}
负载均衡策略
| 轮询 | 默认方式 |
|---|---|
| weight | 权重方式 |
| ip_ hash | 依据ip分配方式 |
| least conn | 最少连接方式 |
| fair(第三方) | 响应时间方式 |
| url_ hash(第三方) | 依据URL分配方式 |
9. 防止网络攻击,安全路径
URL动态化:当前用户和当前的商品ID,进行加密作为路径传参,形成一个动态路径。
10.分布式事务
多个服务同时修改记录时,保证数据的一致性。
分布式思路:
- 通过在redis设置一个唯一锁,如果存在key,则认为有其他客户端在使用,等待锁释放。
- 如果不存在key,说明没有客户端使用,可以执行任务,执行完毕,解锁,删除key.
存在的问题
获得锁后,服务宕机,由于key是唯一的,所以无法被删除.
解决:设置过期时间。
任务执行过长,超过过期时间。
解决:通过一个守护线程,给线程续命.
任务执行造成死循环,会造成无限续命.
解决:设置最大续命时间。
两段式
三段式
CAP和Base
C:表示一致性
A:可用性
P:分区容错性