nacos保护阈值
Nacos 中的保护阈值(Protection Threshold)是用来保护服务实例的一种机制。当某个服务实例出现故障或异常时,服务注册中心 Nacos 会通过心跳检测等方式将其从服务列表中移除,以避免客户端继续向其发送请求。但是,如果移除的实例过多,会导致服务的可用性降低,因此 Nacos 引入了保护阈值机制来避免这种情况的发生。
保护阈值的作用是当服务实例的健康状态低于指定的阈值时,Nacos 将不再将其从服务列表中移除。例如,如果将保护阈值设置为 0.5,当服务实例的健康状态低于 50% 时,Nacos 将不再移除该实例。这样可以保证即使出现故障或异常,仍然能够保留一定数量的服务实例,从而提高服务的可用性。
需要注意的是,保护阈值并不能解决服务实例的故障或异常问题,它只是一种机制来避免过度移除服务实例的问题。因此,在实际使用过程中,还需要针对服务实例的故障或异常问题进行监控和修复,以确保服务的正常运行。
总结:伤兵也要上
@SentinelResource
@SentinelResource
是Sentinel的注解式API,用于标识被限流、降级等资源,并提供相应的处理方法。该注解的常用参数如下:
value
:资源名称,也就是Sentinel控制台中配置限流规则时需要填写的「资源名」。必填参数。entryType
:流量控制针对的端点(请求来源),可选值包括 IN(入口流量)、OUT(出口流量,仅对 Dubbo 服务提供者生效)、DEFAULT(不区分入口和出口),默认值是 DEFAULT。blockHandler
:流控降级处理逻辑,即在触发限流规则后的处理方法,方法需要与被保护的方法在同一个类中。方法签名必须与原方法相同或兼容。fallback
:服务熔断降级处理逻辑,即在发生异常时的处理方法,方法需要与被保护的方法在同一个类中。该方法参数类型、返回值类型都需要与原方法相同或兼容。defaultFallback
:通用熔断降级处理逻辑,该方法没有参数,返回类型需要与原方法相同或兼容。如果参数设置为 true,则所有 Sential 配置的 fallback 都失效,转而执行该默认 fallback。如果方法是静态方法或者构造函数,或者同时配置了 fallback 和 defaultFallback,则忽略 defaultFallback 配置。
此外,该注解还有很多其它参数,比如 metrics 单位、出错信息等等。需要根据不同场景配置适当的参数。
blockHandlerClass 参数
在 @SentinelResource
注解中,blockHandlerClass
是用于设置「处理 BlockException 的函数」所在类的 Class 对象。它可以为 BlockException 异常设置一个专属的处理函数,并且该处理函数必须定义在 blockHandlerClass
指定的类中,方法签名必须与原方法相同或兼容。
例如,如果在资源限流或熔断时,希望使用一个专门的处理方法进行处理,可以将 blockHandlerClass
设置为一个专用的处理 BlockException 的类,同时该类中定义一个和被保护方法参数和返回值类型相同的处理方法(例如 public User fallbackHandleForGetUser(String id){...}
),然后在 @SentinelResource
中设置 blockHandlerClass
和 blockHandler
,如下所示:
@SentinelResource(
value = "getUser",
blockHandlerClass = CustomBlockHandler.class,
blockHandler = "fallbackHandleForGetUser"
)
@GetMapping("/user")
public User getUser(@RequestParam("id") String id) throws Exception {
// 这里是被限流保护的业务逻辑
// ...
}
在 CustomBlockHandler 这个类中,定义如下处理方法:
public class CustomBlockHandler {
public static User fallbackHandleForGetUser(String id){
// 处理被限流时的逻辑
}
}
这样当 getUser 方法被 Sentinel 限流时,就会自动执行 CustomBlockHandler.fallbackHandleForGetUser 方法来进行处理。
Sentinel 流控规则和熔断降级区别
Sentinel 中流控规则和熔断降级规则的主要区别在于:
- 流控规则的目的是控制流量的大小而不是服务的质量,主要是针对于请求量过大时对流量限制,防止系统崩溃;而熔断降级规则的目的是保证服务质量,防止服务访问出现异常时导致依赖服务致命故障。
- 流控规则是通过限制请求量来保证系统不会被资源耗尽导致服务不可用,而熔断降级规则是在发生异常或错误时,限制对该服务的调用,针对可能会引起系统崩溃的异常进行处理。
- 流控规则是通过限制实时请求处理的 QPS/并发线程数/响应时间等信息进行限制的,而熔断降级规则则是通过统计失败率或异常比率来触发熔断,然后在一段时间内关闭或返回异常数据。
- 流控是一种主动防御机制,当 QPS 达到设定的阈值时主动拦截流量进行处理;而熔断则是在系统出现错误或者异常情况时进行自动切换,降级或关闭服务。
- 流控一般应用于高峰期,发生短时间请求量剧增的情况,而熔断则一般应用于长时间或大量访问失败的情况。
综上所述,流控规则和熔断降级规则是两种不同的机制,但其都是为了保障服务的可靠性而设定的。
在实际应用中,应根据不同的业务场景来选择合适的规则来进行限制和熔断,以保证应用的稳定性和可靠性。
@PreAuthorize() 注解
@PreAuthorize
注解是 Spring Security 中的一种基于表达式的访问控制注解,用于描述方法调用所需的权限。@PreAuthorize()
的参数可以是一个字符串,也可以是一个 SpEL 表达式,用于指定权限要求。下面将分别介绍 @PreAuthorize
注解的参数及用法,并给出详细的示例代码。
首先,需要在 Spring Security 的配置类中开启表达式支持:
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// ...
}
1. 使用角色作为表达式
可以使用 ROLE_
前缀来代表角色,例如 ROLE_ADMIN
可以写作 hasRole('ADMIN')
。示例代码如下:
@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/api/users")
public List<User> getAllUsers() {
return userService.getAllUsers();
}
上面的示例代码代表只有具有 ADMIN
角色的用户能够获取所有用户的信息。
2. 使用权限作为表达式
可以使用 hasAuthority()
或 hasAnyAuthority()
函数来代表权限,例如 VIEW_USER
可以写作 hasAuthority('VIEW_USER')
。示例代码如下:
@PreAuthorize("hasAuthority('VIEW_USER')")
@GetMapping("/api/users/{id}")
public User getUserById(@PathVariable Long id) {
return userService.getUserById(id);
}
上面的示例代码代表只有具有 VIEW_USER
权限的用户能够获取指定用户的信息。
3. 使用表达式组合
可以使用逻辑运算符 and
、or
、not
等对表达式进行组合。示例代码如下:
@PreAuthorize("hasRole('ADMIN') and hasAuthority('EDIT_USER')")
@PutMapping("/api/users/{username}")
public void updateUser(@PathVariable String username, @RequestBody User user) {
userService.updateUser(username, user);
}
上面的示例代码代表只有同时具有 ADMIN
角色和 EDIT_USER
权限的用户才有权限更新指定用户的信息。
4. 使用 ${}
访问 Spring 数据库值
可以使用 ${}
访问 Spring 的环境变量或者数据库中的值。示例代码如下:
@PreAuthorize("hasRole('${admin.role}')")
@GetMapping("/api/users")
public List<User> getAllUsers() {
return userService.getAllUsers();
}
上面的示例代码代表只有具有 ${admin.role}
角色的用户能够获取所有用户的信息。
5. 使用其他参数
可以使用其他参数,例如 authentication
、filterObject
等来编写更加复杂的表达式。示例代码如下:
@PreAuthorize("#user.username == authentication.principal.username")
@PutMapping("/api/users/{username}")
public void updateUser(@PathVariable String username, @RequestBody User user) {
userService.updateUser(username, user);
}
上面的示例代码代表只有修改自己的信息的用户才有权限执行这个方法。其中 #user
表示方法传入的 user
参数,authentication.principal.username
表示当前认证用户的用户名。
Spring Security的执行流程
1.用户提交用户名、密码被SecurityFilterChain中的UsernamePasswordAuthenticationFilter过滤器获取到,封装为请求Authentication,通常情况下是UsernamePasswordAuthenticationToken这个实现类。
2.然后过滤器将Authentication提交至认证管理器(AuthenticationManager)进行认证
3.认证成功后,AuthenticationManager身份管理器返回一个被填充满了信息的(包括上面提到的权限信息,身份信息,细节信息,但密码通常会被移除)Authentication实例。
4.SecurityContextHolder安全上下文容器将第3步填充了信息的Authentication,通过SecurityContextHolder.getContext().setAuthentication(…)方法,设置到其中。
5.可以看出AuthenticationManager接口(认证管理器)是认证相关的核心接口,也是发起认证的出发点,它的实现类为ProviderManager。而Spring Security支持多种认证方式,因此ProviderManager维护着一个List列表,存放多种认证方式,最终实际的认证工作是由AuthenticationProvider完成的。咱们知道web表单的对应的AuthenticationProvider实现类为DaoAuthenticationProvider,它的内部又维护着一个UserDetailsService负责UserDetails的获取。最终AuthenticationProvider将UserDetails填充至Authentication。