Java相关知识点整理《三》

19、6种常见的负载均衡算法。

19.1..轮询法。

请求按顺序轮流分配到后端服务器,而不关心服务器连接数和负载能力。

19.2.随机算法。

19.3.源地址哈希算法。

获取客户端IP,哈希计算后得到一个数值,用该数值对服务器列表的大小进行取模运算,得到的结果便是客户端要访问的服务器编号。

19.4.加权轮询算法。

19.5.加权随机算法。

19.6.最小连接数算法。

请求总是转发到连接数最小的服务器上。

20、Zuul相关知识。

Zuul提供了一个框架,可以对过滤器进行动态的加载编译运行

Zuul过滤器之间没有直接的相互通信,他们之间通过一个RequestContext的静态类来进行数据的传递。RequestContext类中有ThreadLocal变量来记录每个Request所需传递的数据。使用ThreadLocal达到线程安全目的。

20.1.Zuul四种过滤器类型。

(a)RRE:前置过滤器,这种过滤器在请求被路由之前调用。

(b)ROUTING:这种过滤器将请求路由到微服务,使用Apache HTTPClient或者Netflix Ribbon请求微服务。

(c)POST:这种过滤器在路由到微服务以后执行。

(d)ERROR:其他阶段发生错误时执行该过滤器。

20.2.Zuul两种内置特殊过滤器。

StaticResponseFilter:允许Zuul本身生成响应,而不是请求转发到源。

SurgicalCycleFilter:允许将特定请求路由到分隔的调试集群和主机。

20.3.ContextLifeCycleFilter到RequestContext的生命周期管理。

ContextLifeCycleFilter的核心功能是为了清除RequestContext;请求上下文RequestContext通过ThreadLocal存储,需要在请求完毕后删除该对象。RequestContext提供了执行filter Pipeline所需的Context,因为Servlet是单列多线程,这就要求RequestContext既要线程安全又要Request安全。Context使用ThreadLocal保存,这样每个worker线程都有一个与其绑定的RequestContext,因为worker仅能同时处理一个Request,这就保证了RequestContext既是线程安全的又是Request安全的。

21、Eureka与Zookeeper的对比。

分布式CAP理论:

C一致性、A可用性、P分区容错性

Zookeeper:基于CP,不保证高可用,如果Zookeeper正在选主,或者Zookeeper集群中半数以上机器不可用,那么将无法获取数据。

Eureka:基于AP,能保证高可用,即使所有的机器挂了,也能拿到本地缓存的数据。

22、Kafka学习记录。

在一个可配置的时间段内,Kafka集群内保留所有发布的消息,不管这些消息有没有被消费。比如,如果消息的保存策略被设置为两天,那么在一个消息被发布的两天内,它都是可以被消费的。之后它将被丢弃以释放空间。Kafka的性能是和数据量无关的常量级的,所以保留太多的数据并不是问题。

消息发布的两种模式:

(1)队列模式(queuing)。

Consumers可以同时从服务端读取消息,每个消息只被其中的一个customer读取到。

(2)发布—订阅模式(publish—subscribe)。

消息被广播到所有的consumer中。Consumers可以加入一个consumer组,共同竞争同一个topic,topic的消息将被分发到组中的一个成员中。同一组的consumer可以在不同程序中,也可以在不同机器上。

注:如果所有的consumer都在一个组上,就成为了传统的队列模式,在各consumer中实现负载均衡。如果所有的consumer都在不同的组上,就成为了发布—订阅模式。

注:consumer组的消费数量不能多于分区的数量,也就是有多少分区就允许有多少并发消费。

Kafka只能保证一个分区之内的消息的有序性,在不同的分区之间是不可以的,这已经可以满足了大部分应用的需求,如果需要topic中所有消息的有序性,那就只能让这个topic只有一个分区,当然也就只有一个consumer组消费它。

Producer直接将数据发送到broker的leader(主节点),不需要再多个节点进行分发。为了帮助producer做到这点,所有的kafka都可以及时的告知:哪些节点是活动的?目标topic、目标分区的leader在哪儿。这样producer就可以直接将消息发送到目的地了。

Producer将消息推送到broker,consumer从broker拉取消息。

Kafka生产者不能从代码上生成topic,只有在服务器上用命令生成。

23、分布式Session解决方案。

23.1.Session复制。

Tomcat、Jetty服务器等自带,配置即可。

使用场景:机器较少,网络流量较少。

缺点:广播式复制到其余机器有一定延时,带来一定的网络开销。

23.2.客户端Cookie存储Session。

缺点:每次那个请求都携带Session,占网络带宽;存储大小收到cookie大小限制;网络传输存在安全隐患。

23.3.反向代理Nginx。

外载一层Nginx,反向代理使用用户IP做hash,以保证每一个IP的请求落在同一台web-server上。

23.4.集中式缓存处理。

Redis集群存储,Spring Session存储Redis。

使用场景:集群中机器数量较多,网络环境复杂。

缺点:实现复杂,稳定性依赖于缓存的稳定性,Session信息放入缓存时要有合理的策略写入。

24.分布式事务解决方案。

24.1.两阶段提交(2PC)。

增设事务协调器(TC)处理控制事务节点事务。

缺点:多次节点之间的网络通信,通信时间较长。

锁定资源时间长。

不适宜高并发场景。

24.2.补偿机制(TCC)。

事务链中的任一操作。都对应一个符合回滚规则的逆向操作;若事务链的任何操作失败,则分别调用各已被正向操作的回滚操作,进行事务回滚。

24.3.本地消息表(MQ异步确保)。

本地消息表这种实现方式应该是业界使用最多的,其核心思想是将分布式事务拆分成本地事务进行处理。

消息生产方:需要额外新建一个消息表,并记录消息发送状态。消息表和业务数据要在同一个事务里提交,也就是说他们要存储在同一个数据库里面。然后消息会经过MQ发送到消费方。如果消息发送失败,进行消息重试机制。

消息消费方:需要处理这个消息,完成自己的业务逻辑。此时如果本地事务处理成功,表明已经处理成功了,如果处理失败,那么会进行重试机制。如果业务上处理失败,可以给生产方发送一个业务补偿消息,通知生产方进行业务回滚。

生产方和消费方定时扫描本地消息表,把还没有处理完成的消息或者发送失败的消息再发送一遍。

25.分布式锁解决方案。

分布式锁:保证一个方法在同一时间内只能被同一个线程执行。

25.1.基于数据库实现分布式锁。

直接创建一张锁表,然后通过操作该表中的数据来实现。当我们要锁住某个方法和资源时,就在该表中增加一条记录,想要释放锁是删除此记录即可。

基于数据库的排他锁来实现分布式锁(在查询语句后加上“for update”,数据库存储method_name需要创建唯一索引)。

25.2.基于缓存实现分布式锁。

String result=jedis.set(lockKey,requestId,SET_IF_NOT_EXIST,SET_WITH_EXPIRE_TIME,expireTime);

lockKey:获取锁的唯一key。

requestId:调用客户端通过UUID.randomUUID().toString()生成requestId并传递给被调用资源,这就把资源和客户端绑定,在解锁的时候就有对应依据。

expireTime:过期时间,过期自动释放锁。

实现思想:

(a)获取锁的时候,使用setnx加锁,并使用expire命令为锁添加一个超时时间,超过该时间则自动解锁。锁的value值为一个随机生成的UUID,通过此在解锁的时候进行判断。

(b)获取锁的时候还设置一个获取的超时时间,若超过这个时间则自动放弃获取锁。

(c)释放锁的时候,通过UUID判断是不是该锁,若是该锁则执行delete进行锁释放。

25.3.基于Zookeeper实现分布式锁。

当每个客户端对某个资源加锁时,在Zookeeper上的与该方法对应的指定节点目录下,生成一个唯一的瞬时有序节点。判断是否获取锁的方式很简单,只要判断当前客户端创建的子节点是否为当前子节点列表中序号最小的子节点,如果是则认为获得锁,否则监听子节点变更消息,获得子节点变更通知后重复此步骤直至获得锁。完成业务流程后,删除对应的子节点释放锁。

26.Ribbon负载均衡相关知识。

Ribbon是Netflix公司开源的一个负载均衡项目,它属于客户端负载均衡器,Feign已经默认使用了Ribbon(Zuul使用Ribbon做负载均衡器,默认采用轮询算法)。

LoadBalancerClient的实现类为RibbonLoadBalancerClient,它是最终的负载均衡处理执行器。

IRule用做负载均衡的策略,它有三个方法,其中choose()是根据key来获取Server,setLoadBalancer()和getLoadBanlancer()是用来设置和获取ILoadBalance的。

Ribbon提供了如下七种负载均衡策略:

(a)BestAvailableRule:选择一个最小并发请求的Server。

(b)AvailabilityFilteringRule:过滤掉那些高并发的后端Server(active connections超过配置的阀值)。

(c)WeightedResponseTimerRule:根据响应时间分配一个weight,响应时间越长,weight越小,被选中的可能性越低。

(d)RetryRule:对选定的负载均衡策略机上重试机制。

(e)RoundRobinRule:轮询式选择Server(默认机制)。

(f)RandomRule:随机选择一个Server响应。

(g)ZoneAvoidancdRule:符合判断server所在区域的性能和server的可用性选择server。

application.properties配置随机访问的示例:

service-B.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadBalancer.RandomRule

27.Spring Security相关知识。

Spring Security就是引入一系列的SecurityFilter,将其添加到Spring中去了;在有请求时,根据URL是否符合每个Filter的规则来判断是否需要该Filter来进行处理。

几个核心组件:

(a)SecurityContextHolder。

用于存储Security Context,主要是当前回话的Principal,默认是使用ThreadLocal来存放这些信息(线程安全);常用于获取当前用户的相关信息,Spring Security使用Authentication来封装这些信息。

(b)UserDetails、Principal、Authentication。

Spring Security中使用Authentication存储当前用户的主要信息。Authentication中存储的是Principal,与UserDetails直接可以强制转换。UserDetails主要用于存储用户名、密码、权限列表等信息。Spring Security提供了一个UserDetailService接口,该接口用于查询并返回一个UserDetails,实现该接口的loadByUsername方法,查询当前用户及用户对权限列表存储返回。

(c)GrantedAuthority。

Authentication对象除了getPrincipal()方法调用返回用户基本信息外,还有getAuthorities()方法可以返回List<GrantedAuthority>。即为用户的权限相关信息,通常都是一些角色信息。

Spring Security的认证授权实现:

(1)首先需要一个认证管理器AuthenticationManager,他将注册一个ProviderManager示例;

(2)其次要注册一个或多个认证provider,即相关的认证逻辑,认证管理器会依次执行这些provider。

(3)这些provider执行之后认证管理器将返回一个完整的Authentication对象或者认证失败的异常。

(4)假设(3)中的认证成功之后,Authentication将会保存到Spring Context中,之后该用户的访问,都会根据Authentication中的List<GrantedAuthority>判断是否有访问权限。

28.Oauth2的相关知识。

Oauth在“客户端”与“服务器提供商”之间,设置了一个授权层。“客户端”不能直接登录“服务器提供商”,只能登录授权层,以此将用户与客户端区分开来。“客户端”登录授权层所用的令牌(token),与用户的密码不同。用户可以在登录的时候,指定授权层令牌的授权范围和有效期。

Oauth2有如下四种授权模式:

(1)授权码模式。

(a)用户访问客户端,后者将前者导向认证服务器。

(b)用户选择是否给予客户端授权。

(c)假设用户给予授权,授权服务器将用户导向客户端事先指定的“重定向URI”,同时附上一个授权码。

(d)客户端收到授权码,附上早先的“重定向URI”,向认证服务器申请令牌。这一步是在客户端的后台服务器上完成的,对用户不可见。

(e)认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access_token)和更新令牌(refresh_token)。

(2)简化模式。

简化模式不通过第三方应用程序的服务器,直接在浏览器中向认证服务器申请令牌,跳过了授权码这个步骤。

(3)密码模式。

用户向客户端提供自己的用户名和密码,客户端使用这些信息,向“服务提供商”索要授权。

在这种模式下,用户必须把自己的密码给客户端,但是客户端不得存储密码。这种场景通常在对客户端高度信任的情况下。

(4)客户端模式。

客户端以自己的名义,而不是以用户的名义,向“服务提供商”进行认证。(直接通过传递client_id和client_secret向认证服务器获取token)。

猜你喜欢

转载自blog.csdn.net/u012459871/article/details/82926965