Sentinel 链路限流
https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6
NodeSelectorSlot
中记录了资源之间的调用链路,这些资源通过调用关系,相互之间构成一棵调用树。这棵树的根节点是一个名字为 machine-root
的虚拟节点,调用链的入口都是这个虚节点的子节点。
一棵典型的调用树如下图所示:
machine-root
/ \
/ \
Entrance1 Entrance2
/ \
/ \
DefaultNode(nodeA) DefaultNode(nodeA)
上图中来自入口 Entrance1
和 Entrance2
的请求都调用到了资源 NodeA
,Sentinel 允许只根据某个入口的统计信息对资源限流。比如我们可以设置 strategy
为 RuleConstant.STRATEGY_CHAIN
,同时设置 refResource
为 Entrance1
来表示只有从入口 Entrance1
的调用才会记录到 NodeA
的限流统计当中,而不关心经 Entrance2
到来的调用。
调用链的入口(上下文)是通过 API 方法 ContextUtil.enter(contextName)
定义的,其中 contextName 即对应调用链路入口名称。详情可以参考 ContextUtil 文档。
web-context-unify: false #默认将调用链路收敛
application.yml
server: port: 8052 #应用名称 (sentinel 会将该名称当作服务名称) spring: application: name: order-sentinel cloud: sentinel: transport: dashboard: 127.0.0.1:8858 web-context-unify: false #默认将调用链路收敛
package com.wsm.order.service; public interface OrderService { public String getUser(); }
package com.wsm.order.service.impl; import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.alibaba.csp.sentinel.slots.block.BlockException; import com.wsm.order.service.OrderService; import org.springframework.stereotype.Service; @Service public class OrderServiceImpl implements OrderService { @Override @SentinelResource(value = "getUser",blockHandler = "blockHandlerGetUser") public String getUser() { return "查询用户"; } public String blockHandlerGetUser(BlockException e){ return "流控用户"; } }
package com.wsm.order.controller; import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.alibaba.csp.sentinel.slots.block.BlockException; import com.wsm.order.service.OrderService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.TimeUnit; @RestController @RequestMapping("/order") public class OrderController { @Autowired OrderService orderService; @RequestMapping("/add") public String add(){ System.out.println("下单成功!"); return "生成订单"; } @RequestMapping("/get") public String get(){ System.out.println("查询订单!"); return "查询订单"; } @RequestMapping("/test1") public String test1(){ return orderService.getUser(); } @RequestMapping("/test2") public String test2(){ return orderService.getUser(); } @RequestMapping("/flow") // @SentinelResource(value = "flow",blockHandler = "flowBlockHandler") public String flow(){ System.out.println("========flow===="); return "正常访问"; } public String flowBlockHandler(BlockException e){ return "流控了"; } @RequestMapping("/flowThread") // @SentinelResource(value = "flowThread",blockHandler = "flowThreadBlockHandler") public String flowThread() throws InterruptedException { TimeUnit.SECONDS.sleep(5); System.out.println("========flowThread===="); return "正常访问"; } public String flowThreadBlockHandler(BlockException e){ return "flowThread流控了"; } }