专题类网站坪山区坪山街道六联社区

news/2025/9/23 16:30:03/文章来源:
专题类网站,坪山区坪山街道六联社区,企业网站推广怎么做,xp 做网站服务器吗文章目录 前言1.第一次尝试1.1服务被调用方更新1.2压测第一次尝试1.3 问题分析1.4 同步的不是最新列表 2.第二次尝试2.1调用方过滤下线服务2.2压测第二次尝试2.3优化 写到最后 前言 在上文的基础上#xff0c;通过压测的结果可以看出#xff0c;使用DiscoveryManager下线服务… 文章目录 前言1.第一次尝试1.1服务被调用方更新1.2压测第一次尝试1.3 问题分析1.4 同步的不是最新列表 2.第二次尝试2.1调用方过滤下线服务2.2压测第二次尝试2.3优化 写到最后 前言 在上文的基础上通过压测的结果可以看出使用DiscoveryManager下线服务之后进行压测是不会出现异常情况的但唯一缺点就是下线服务的方式是取消注册与续约之后并没有结束进程。也就使得在调用api下线后的服务其实是还存在处理请求的能力的。加之eureka三种级别的缓存同步需要一定时间Eureka-Client从三级缓存中拉取的并不是实时的服务列表进而使得Ribbon从Eureka-Client拉取的也不是实时的服务列表。最终导致Ribbon负载均衡到了已经下线的服务实例并且此时该实例进程还未关闭刚好能处理请求就造成了下线了两个端口的服务实例但是却还是被负载均衡到来处理请求 按照这个思路再去看这张图 可不可以通过某种手段当服务下线后去越过三级缓存直接去更新Ribbon缓存来缩短感知时间 我先说答案——是可以的 1.第一次尝试 1.1服务被调用方更新 手动从Eureka-Client同步服务缓存信息 在之前分析Ribbon源码的时候说到了接口路径从http://服务名称/接口路径——http://服务地址/接口路径这个过程中调用方的请求被Ribbon拦截器拦截并且通过负载均衡最终被改写成为了一个准确的服务地址其中有一个非常重要的方法getLoadBalancer(“服务名称”) 可见他通过服务名称就拿到了该服务名称下的所有服务列表allServerList和可用服务列表(upServerList)我们通过这个操作可不可以直接获取到最新一手的可用服务列表并且手动去set进Ribbon的可用服务列表缓存里让他不再去每过30S同步 Tips:在我们的SpringCloud项目中有一个非常重要的组件SpringClientFactory是Spring Cloud中用于管理和获取客户端实例的工厂类。在这里面可以获取特定服务的负载均衡器即ILoadBalancer 于是便有了下面的操作专门配置一个Bean去更新Ribbon缓存每当调用服务下线接口去下线指定服务后就去自动同步Ribbon缓存不用再Ribbon每隔30S去自动同步 Configuration Slf4j public class ClearRibbonCache {public void clearRibbonCache(SpringClientFactory clientFactory, ListInteger portParams) {// 获取指定服务的负载均衡器ILoadBalancer loadBalancer clientFactory.getLoadBalancer(user-service);//在主动拉取可用列表而不是走拦截器被动的方式——这里ListServer reachableServers loadBalancer.getReachableServers();//这里从客户端获取会等待客户端同步三级缓存// 在某个时机需要清除Ribbon缓存((BaseLoadBalancer) loadBalancer).setServersList(ableServers); // 清除Ribbon负载均衡器的缓存} }于是在下线服务的接口中就多了一步自动更新缓存的操作不熟悉这个接口的可以去看上一篇文章 GetMapping(value /service-down-list)public String offLine(RequestParam ListInteger portParams) {ListInteger successList new ArrayList();//得到服务信息ListInstanceInfo instances eurekaClient.getInstancesByVipAddress(appName, false);ListInteger servicePorts instances.stream().map(InstanceInfo::getPort).collect(Collectors.toList());//去服务列表里挨个下线OkHttpClient client new OkHttpClient();log.error(开始时间{}, System.currentTimeMillis());portParams.parallelStream().forEach(temp - {if (servicePorts.contains(temp)) {String url http:// ipAddress : temp /control/service-down;try {Response response client.newCall(new Request.Builder().url(url).build()).execute();if (response.code() 200) {log.debug(temp 服务下线成功);successList.add(temp);} else {log.debug(temp 服务下线失败);}} catch (IOException e) {log.error(e.toString());}}});log.debug(开始清除Ribbon缓存);clearRibbonCache.clearRibbonCache(clientFactory,portParams);return successList 优雅下线成功;}1.2压测第一次尝试 同样我们采用(100线程-3S)的JMeter压测模型去在调用服务下线接口后的15S,30S后压测压测的接口即为一个普通的跨服务调用接口 下线服务 下线服务的15S 此时,观察控制台的日志输出可以发现已经下线的两个服务实例还是被负载均衡到了已下线但进程未退出好像更新了缓存没有任何效果诶。 下线服务的30S 情况和15S如出一辙并且请求负载均衡到了已下线但进程未退出的服务上。 下线服务的45S 可见调用api下线服务直到45S左右已经下线的服务才从每层缓存信息中完全清除这个时间是非常致命的 1.3 问题分析 在服务发布的场景就会出现这样一个业务问题开发调用api下线了某两个服务通知运维可以去关闭这两个服务进程了运维kill-9杀掉了这两个进程准备发布新服务。但此时客户端用户向服务端发送了请求刚好该请求涉及跨服务调用并且由于Ribbon同步Eureka-Client缓存Eureka-Client同步Eurek-Server中的三级缓存需要一定时间Ribbon缓存中的可用服务列表不是最新的同步过来已下线进程也被kill的服务。最后请求受到Ribbon负载均衡落到了一个开发通过api下线的服务实例分发到了一个运维kill-9的服务实例上造成接口返回500、404、connect time out、connect refused…等错误造成频繁告警。 1.4 同步的不是最新列表 透过现象看本质 为什么手动同步Ribbon缓存没有起到效果是不是同步的内容出了问题下面打断点开启debug看看服务下线后到底拿到的是什么服务列表 意外发现曾经天真以为可以拿到的实时的服务列表到头来确实一场空小丑竟是我自己。明明8083,8084已经下线可为什么还在可用服务列表里并且还set到了Ribbon缓存中 原来啊通过那个方法获取服务列表是从Eureka-client拿的而这其实就是client去三级缓存那里同步的问题。 你说到为什么手动更新了缓存还是会有一段同步时间 那就是client从三级缓存同步来的服务列表还存在没下线的服务所以导致手动更新到ribbon缓存里的列表也还存在没下线的服务。看到这里Eureka的“牺牲一致性保证高可用”是不是体现的淋漓尽致呢 这个一致性难道真的不能解决了吗 其实我还有一招 同时结合Eureka-Ribbon架构的服务调用链路其实在服务调用方去更新Ribbon缓存才能更好保证Ribbon负载均衡的服务列表是我所控制的 PS这里节省了一次尝试即在服务被调用方去引入过滤操作尝试过压测结果还是和以前一样所以就忽略了。直接去服务调用方尝试 2.第二次尝试 2.1调用方过滤下线服务 从拿到的服务列表中过滤下线服务并且在调用方执行 在调用方执行那被调用方下线的端口信息怎么让调用方知道呢跨进程通信你选择MQ还是Redis这里我选择Redis 在上述更新缓存的操作中稍作更改把更新操作移动到服务调用方并且引入Redis来作为通信支持这里采用hash的数据结结构那么被调用方现在所需要的就是更新下线的端口信息到redis中 GetMapping(value /service-down-list)public String offLine(RequestParam ListInteger portParams) {ListInteger successList new ArrayList();//得到服务信息ListInstanceInfo instances eurekaClient.getInstancesByVipAddress(appName, false);ListInteger servicePorts instances.stream().map(InstanceInfo::getPort).collect(Collectors.toList());//去服务列表里挨个下线OkHttpClient client new OkHttpClient();log.error(开始时间{}, System.currentTimeMillis());portParams.parallelStream().forEach(temp - {if (servicePorts.contains(temp)) {String url http:// ipAddress : temp /control/service-down;try {Response response client.newCall(new Request.Builder().url(url).build()).execute();if (response.code() 200) {log.debug(temp 服务下线成功);successList.add(temp);} else {log.debug(temp 服务下线失败);}} catch (IOException e) {log.error(e.toString());}}});// todo Redis通知stringRedisTemplate.opsForHash().put(port-map,down-ports,portParams.toString());return successList 优雅下线成功;}并且以前更新Ribbon可用服务列表操作也有稍微变化即新增了一个手动过滤操作 Configuration Slf4j public class ClearRibbonCache {/*** 削减*/public static boolean cutDown(ListInteger ports, Server index) {return ports.contains(index.getPort());}public void clearRibbonCache(SpringClientFactory clientFactory, String portParams) {// 获取指定服务的负载均衡器ILoadBalancer loadBalancer clientFactory.getLoadBalancer(user-service);//在主动拉取可用列表而不是走拦截器被动的方式——这里ListServer reachableServers loadBalancer.getReachableServers();//这里从客户端获取会等待客户端同步三级缓存//过滤掉已经下线的端口符合条件端口的服务过滤出来ListInteger portList StringChange.stringToList(portParams);ListServer ableServers reachableServers.stream().filter(temp - !cutDown(portList, temp)).collect(Collectors.toList());log.debug(可用服务列表{}, ableServers);// 在某个时机需要清除Ribbon缓存((BaseLoadBalancer) loadBalancer).setServersList(ableServers); // 清除Ribbon负载均衡器的缓存} }在服务调用方每次进行跨服务调用前都去从Redis中获取出实时下线的端口并且去更新Ribbon缓存 2.2压测第二次尝试 当下线完服务立即进行压测可以看到所有的跨服务调用请求都落在了还未下线的实例上并且已下线但进程未关闭的服务实例没有再处理请求 并且15S30S的时间节点上也没有任何异常 可见通过此种方式来主动更新Ribbon可用服务列表确实可行特别是在运维那边发布新服务的一个特定场景下可以解决Eureka感知下线服务迟钝从而影响Ribbon负载到不可用的服务实例上这一问题。 2.3优化 其实如果每次在新发布服务的场景下告警的接口都可以精确定位到并且数量不多的情况我觉得在那几个业务接口里去手动同步一下Ribbon缓存没有什么大问题也可以解决问题。但是如果每次告警的接口有很多并且不固定那上述的方法就显得有些许臃肿。而且这也是一种入侵式编程我其实是不推荐的 说起入侵式编程不禁就会想到无入侵式编程——Aop 直接把出现错误的模块作为切面并把更新Ribbon的操作作为切入点写到表达式里就完美做到了不改变已有业务而实现了更新功能就像这样 Aspect Component Slf4j public class RequestAspect {ResourceSpringClientFactory springClientFactory;ResourceClearRibbonCacheBean clearRibbonCacheBean;Resourceprivate StringRedisTemplate stringRedisTemplate;Before(value execution(* com.yu7.order.web.*.*(..)))public void refreshBefore(JoinPoint joinPoint) {String ports (String) stringRedisTemplate.opsForHash().get(port-map, down-ports);log.debug(从Redis获取的端口为{}, ports);//下线了才会有值没有值说明没下线不用更新if (ObjectUtils.isNotEmpty(ports)) {clearRibbonCacheBean.clearRibbonCache(springClientFactory, ports);}} }进行压测结果和预期完全一致~ 写到最后 我想说其实我的方案只是相当于提出了一个大体框架和构想粗略地实现了基于Eureka的微服务架构中服务状态感知的问题当业务里存在不止一种调用关系下线服务类型不一致服务断断续续下线会造成value值丢失…方案就需要进一步细化还存在硬编码问题嘻嘻并且为了切面不影响业务还应该给存到Redis的数据加上TTL等其他保险措施总而言之也欢迎大家提出建议共同精进一起解决这一难题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/913161.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

免费入驻的网站设计平台网站开发静态和动态

[react] 在React中你有遇到过安全问题吗?怎么解决? dangerouslySetInnerHTML预防xss攻击 个人简介 我是歌谣,欢迎和大家一起交流前后端知识。放弃很容易, 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

公司网页制作网站怎么设置网站

目录 传送参数页面接受参数页面最后 uniapp全局事件&#xff0c;也就是说&#xff0c;不相邻的&#xff0c;不是父子组件&#xff0c;也可以传递参数。 一个组件&#xff0c;传递项目内所有文件其中一个里面内&#xff0c;可以接受到参数。 传送参数页面 <template><…

做网站用模板专题制作 wordpress

&#x1f345; 作者主页&#xff1a;Java李杨勇 &#x1f345; 简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java李杨勇公号作者✌ 简历模板、学习资料、面试题库、技术互助【关注我&#xff0c;都给你】 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f…

厦门做商城网站网站宣传册

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

网站维护员工作内容代理网页免费

av_packet_unref 该接口使用了如下调用,该接口主要作用是清理AVPacket中的所有空间数据&#xff0c;清理完毕后进行初始化操作&#xff0c;并且将 data 与 size 置为0&#xff0c;方便下次调用。 void av_packet_unref(AVPacket *pkt) {av_packet_free_side_data(pkt);av_buf…

找什么公司做网站怎么自己弄一个公众号

选择合适的扫描仪是进行档案数字化的关键步骤。以下是一些选择合适扫描仪的要点&#xff1a; 1. 扫描速度&#xff1a;选择具有合适的扫描速度的扫描仪&#xff0c;以便能够快速处理大量的文件。 2. 扫描分辨率&#xff1a;扫描分辨率决定了扫描后图像的清晰度。对于大多数文档…

飞书对程序员下手了,0 代码生成各类系统!!(附保姆级项目实战教程)

大家好,我是R哥。 之前我分享了飞书多维表格的妙用:飞书对程序员下手了,0 代码生成各类系统!!包括以下两个重点: 1、飞书多维表格无需下载飞书也能直接使用了,打开 base.feishu.cn 就可以直接使用飞书多维表格。…

Adaptix C2:跨平台渗透测试与对抗仿真框架

Adaptix C2是一个可扩展的后渗透和对抗仿真框架,专为渗透测试人员设计。采用Golang服务端和C++ QT客户端架构,支持Linux、Windows和MacOS多平台操作,提供完整的加密通信、插件化监听器和代理管理功能。项目描述 Ada…

wordpress发布插件太原网站seo

指纹由于其终身不变性、唯一性和方便性&#xff0c;几乎已成为生物特征识别的代名 词。通常我们说的指纹就是人的手指末端正面皮肤上凸凹不平的纹线&#xff0c;纹线规律地排列 形成不同的纹型。而本节所讲的指纹是指网站CMS 指纹识别、计算机操作系统及W eb 容器的指纹识别等…

ncpa.cpl 意义 这个名称的

ncpa.cpl 意义 这个名称的ncpa.cpl 其实是 Windows 控制面板小程序 (Control Panel item) 的文件名。全称含义:nc → Network Connections(网络连接)pa → Panel Applet(控制面板小程序).cpl → Control Panel ex…

国标GB28181软件EasyGBS网页直播平台在邮政快递场景的落地与应用

国标GB28181软件EasyGBS网页直播平台在邮政快递场景的落地与应用随着电子商务的迅猛发展,邮政快递行业迎来了前所未有的发展机遇,但同时也面临着诸多挑战。如何在保障货物安全、提高运输效率的同时,实现全面的监控和…

做网站的软件下载做知乎网站要多少钱

文章目录 1. 数据的关联与合并1.1 join关联1.1.1 内关联1.1.2 左关联1.1.3 右关联 1.2 Union合并 2. 缓存和checkpoint 1. 数据的关联与合并 1.1 join关联 students表数据&#xff1a; 1.1.1 内关联 内关联只返回两个 DataFrame 中在连接键上匹配的行。 # join 关联 from…

创建了网站黄石网站建设黄石

文章目录 引言复习完全背包问题——买书个人实现 状态转换机——股票买卖V个人实现参考实现 新作两数相除个人实现 新作LRU缓存实现个人实现unordered_map相关priority_queue相关 参考实现自己复现 总结 引言 今天知道拼多多挂掉了&#xff0c;难受&#xff0c;那实习就是颗粒无…

长沙教育网站开发秦皇岛建网站

哈希表是种数据结构&#xff0c;它可以提供快速的插入操作和查找操作。第一次接触哈希表时&#xff0c;它的优点多得让人难以置信。不论哈希表中有多少数据&#xff0c;插入和删除(有时包括侧除)只需要接近常量的时间即0(1)的时间级。实际上&#xff0c;这只需要几条机器指令。…

做网站一定要买主机吗wordpress书库插件

jquery 实现双击编辑并保存Jesse2013-12-11 19:47:001153最近在做一个数据修改的例子&#xff0c;一个个点开修改很麻烦&#xff0c;于是就想到ecshop后台里的 只需单击就以编辑了&#xff0c;在网上查阅资料&#xff0c;就想到双击修改&#xff0c;失去鼠标焦点后post执行HTML…

北京wap网站建设wordpress重复评论

null可赋值任何变量,将变量置为空 DBNull只用于DataRow对象,表示数据库中的空值 String.Empty是0长度字串 Convert.IsDBNull判断是否为DBNull DBNull.Value与Null的区别 Null是.net中无效的对象引用。 DBNull是一个类。DBNull.Value是它唯一的实例。它指数据库中数据为空(&l…

做视频网站注意什么天津工程网站建设

一、峰会简介 近年来&#xff0c;以云计算、移动互联网、物联网、工业互联网、人工智能、大数据及区块链等新一代信息技术构建的智能化应用和产品出现爆发式增长&#xff0c;突破了对于软件形态的传统认知&#xff0c;正以各种展现方式诠释着对新型智能软件的定义。这也使得对…

sql统计一个字段各个值各有多个个的方法

sql统计一个字段各个值各有多个个的方法SELECT COUNT(CASE WHEN apprStatus = 1 and policy_id IN(19657ffd7b6o25bj6ojr) THEN 1 END) AS count_init, COUNT(CASE WHEN apprStatus = 2 and policy_id IN(19657ffd7b6o…

完整教程:深度学习-神经网络(上篇)

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …