# nerver **Repository Path**: netdebug/nerver ## Basic Information - **Project Name**: nerver - **Description**: 微服务神经元,目标功能:五层过滤、规则路由、容错(泛化容错)、熔断、隔离等功能 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 19 - **Created**: 2016-05-22 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README #微服务神经元(Nerver) 主要功能:过滤、动态规则路由、容错、熔断、隔离、限流、超时控制。 **QQ交流群:191958521(微服务神经元)** ##一、过滤 ###1.过滤类型 过滤规则(FilterType)参考了Netflix的Zuul项目进行实现,提供了以下五层过滤器: + PRE:请求到达Nerver服务器之前进行过滤 + ROUTE:请求路由转发至源服务器(Orgin Server)之前进行过滤 + RECV:请求从Orgin Server回来到达Nerver服务器之前过滤 + RET:请求从Nerver服务器离开之前(响应用户)进行过滤 + ERROR:当请求在Nerver服务器中发送异常时进行过滤 ###2.过滤设计方案 ![过滤设计方案](docs/五层路由设计方案.png "过滤设计方案") ##二、动态规则路由 ###1.路由规则 如: /api/goods/** → http://127.0.0.1:8081/api/goods /api/user/** → http://127.0.0.1:8082/api/user ... ###2.路由实现 采用httpclient实现请求的转发(路由)。 ###3.路由类型 目前已支持:GET、POST、PUT、DELETE、HEAD、OPTIONS、PATCH和TRACE类型请求的路由。 ###4.使用示例 第一步:模拟启动待被路由的远程服务器 /** * 被路由的服务器 * @author lry */ public class OrginServer extends AbstractHandler { public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); response.setContentType("text/html; charset=UTF-8"); response.setHeader("Content-Type", "text/html; charset=UTF-8"); response.setStatus(HttpServletResponse.SC_OK); baseRequest.setHandled(true); response.getWriter().println("已经到达源服务器了!参数:"+JSON.toJSONString(request.getParameterMap())); } public static void main(String[] args) throws Exception { Server server = new Server(8081); server.setHandler(new OrginServer()); server.start(); System.out.println("源服务器启动成功"); server.join(); } } 第二步:启动微服务神经元服务器 /** * 微服务神经 * @author lry */ public enum Nervor { INSTANCE; public RouteModuler routeModuler=RouteModuler.INSTANCE; public IContainer container=null; public void start() { try { //添加路由规则 routeModuler.addRouteRule(new RouteRule(0, true, "/api/get/**", "http://127.0.0.1:8081/api/get")); container=new JettyContainer(); container.cstart(8080); } catch (Throwable t) { if(container!=null){ container.cstop(); } t.printStackTrace(); } } public static void main(String[] args) throws Exception { INSTANCE.start(); } } 第三步:打开浏览器访问 http://127.0.0.1:8080/nerver/v1/api/get/123?name=nerver&data=123456 其中“/nerver/v1”表示服务器名称和版本号 ##三、容错 ###**1.设计场景:** ![容错设计](docs/容错设计.png) ###**2.泛化容错核心设计:** ![泛化容错核心设计](docs/泛化容错核心设计.png) ###**3.使用场景** 主要用于分布式系统之间进行交互的代码模块,即容错有依赖的代码模块。当分布式系统之间发生远程通信时,需要对代码模块实现容错处理(不保证事务的一致性)。 ###**4.容错策略** + **故障转移(Failover):** 失败自动切换,当出现失败,重试其它服务器 通常用于读操作,但重试会带来更长延迟 + **快速失败(Failfast):** 快速失败,只发起一次调用,失败立即报错;通常用于非幂等性的写操作,比如新增记录。 + **故障保护(Failsafe):** 失败安全,出现异常时,直接忽略;通常用于写入审计日志等操作。 + **失败缓存(Failcache):** + **失败恢复(Failback):** 失败自动恢复,后台记录失败请求,定时重发;通常用于消息通知操作。 + **并行策略(Forking):** 并行调用多个服务器,只要一个成功即返回;通常用于实时性要求较高的读操作,但需要浪费更多服务资源。 + **广播策略(Broadcast):** 广播调用所有提供者,逐个调用,任意一台报错则报错;通常用于通知所有提供者更新缓存或日志等本地资源信息。 ##四、熔断 ###1.使用场景 在一定的时间窗内,当分布式远程通信中的某一条线路的失败率达到一定的阀值时,系统需要暂时断掉该条线路,以保证后续的服务质量。在熔断一定的时间后,需要尝试线路是否正常,正常则恢复熔断,否则周期性检查是否恢复。 ##五、隔离 ###1.使用场景 分布式服务在远程调用时,可为会发生未知的异常,进而可能会引起整个主服务进程都宕掉,则会导致大面积的服务瘫痪。为了防止单个服务依赖异常而引发其他服务一起陪葬的问题,需要对每一个远程依赖进行隔离。 ##六、限流 ###1.使用场景 当某一片区的服务整体失败率较高时,我们可以选择拒绝部分请求,从而防止该片区集体宕掉或下线的问题;或者使用与流量的迁移过程。 ###2.流量控制使用说明 请直接运行 cn.tm.ms.nerver.qos.QosAtomicFlowCtrl 运行结果 耗时: 7923ms 业务成功笔数: 1000 126 笔/秒 业务处理成功率: 100.0% ##七、超时控制 ###1.使用场景 在分布式依赖的模块,为防止服务端长时间等待远程响应的结果,而使用超时设置来控制远程消费异常的情况。 ##八、幂等机制 ###**1.背景** 在业务开发中,我们常会面对防止重复请求的问题。当服务端对于请求的响应涉及数据的修改,或状态的变更时,可能会造成极大的危害。重复请求的后果在交易系统、售后维权,以及支付系统中尤其严重。前台操作的抖动,快速操作,网络通信或者后端响应慢,都会增加后端重复处理的概率。重复消息是SOA服务实现中非常常见的问题,你永远不要指望调用方每次请求消息不一样,对于读操作,重复消息可能无害,可对于写操作很可能就是灾难。 因此,可以通过幂等(Idempotent)机制处理重复的消息,基本处理思路是: + 调用者给消息一个唯一请求ID标识。ID标识一个工作单元,这个工作单元只应执行一次,工作单元ID可以是Schema的一部分,也可以是一个定制的SOAP Header,服务的Contract 可以说明这个唯一请求ID标识是必须的; + 接收者在执行一个工作单元必须先检验该工作单元是否已经执行过。检查是否执行的逻辑通常是根据唯一请求ID ,在服务端查询请求是否有记录,是否有对应的响应信息,如果有,直接把响应信息查询后返回;如果没有,那么就当做新请求去处理。 ###**2.使用场景** + 防止重复提交 + 保证服务请求的可靠性(尽可能的保证每一次请求都有响应,一次失败) ###**3.定义** 在指定的时间窗(一段时间)内,失败后使用重复提交的方式来保证服务的高可靠性。当服务的一致性做得足够好,则可以使用幂等机制来实现所有请求的高可靠,否则该机制只能删除、查询、部分修改的操作,而针对新增是致命的。 ###**4.幂等方案** 对时间全局性要求高的,可能就必须选择DB这种持久化方案比较可靠,但是性能不够好啊(然后就要考虑loadmemory,以及数据同步的问题,就一步还要考虑实时性要求了)。在空间的要求中,根据不同的幂等范围,可以考虑分布式数据库(分布式集群全局流水号幂等)。还是某种少量数据幂等(可能只需要单台,做好主备)。 ###**5.数据的对象和范围** 你要考虑你的幂等的全局性:空间全局性和时间全局性。 + 空间全局性:比如是交易流水幂等还是用户ID幂等。是某种类型交易流水幂等,还是某个人|机构|渠道的交易流水幂等 + 时间全局性:是幂等几秒,还是几分钟,还是永远。 不同的要求,可以有不一样的解决方案、难度和成本。