1.NacosԴ??bug
2.聊聊 Spring Cloud 全链路灰度发布 方案~
3.Consul 留给你的时间不多了
4.使用Copyonwrite改造本地缓存
NacosԴ??bug
大家好,我是R哥。
Nacos 2.3.2 正式发布,针对一个重大 bug 进行了修复。
Nacos 是一个用于构建云原生应用的动态服务发现、配置管理和服务管理平台,表白网站源码由阿里巴巴开源。它旨在提供注册中心和配置中心的功能,为微服务提供支持。
在Nacos 2.3.2版本中,修复了一个在Nacos 2.3.1版本中存在的重要 bug。该 bug 导致在修改Nacos配置内容后,Nacos服务器会不断向Nacos客户端推送配置,即使服务器端数据没有变化,也会频繁推送,从而消耗客户端和服务器资源。
这一 bug 对系统性能影响较大,间谍源码特别是在业务高峰期时,可能会成为系统的瓶颈。因此,建议大家不要盲目追求最新版本,以免成为测试版本的牺牲品。
Nacos 2.3.2版本除了修复了上述 bug,还增强了其他方面,并解决了几个 bug。这些变动可以关注 Nacos 的官方文档以获取更详细的更新信息。
Nacos 的崛起反映了 Spring Cloud Alibaba 微服务技术的流行。许多早期的 Spring Cloud Netflix 相关组件,如 Eureka 2.x、Ribbon、Zuul、Hystrix 等,已停止维护更新,源码147属于过时技术。学习 Spring Cloud Alibaba 成为当前最明智的选择。
Nacos 在 Spring Cloud Alibaba 技术栈中扮演着关键角色,它作为注册中心和配置中心,功能强大、性能优异。如今,Nacos 的功能越来越强大,作为 Spring Cloud Alibaba 的核心成员之一,掌握Nacos技能对于工作和职业发展都至关重要。
R哥将持续关注并分享更多 Java 技术干货。更多关于 Nacos 的文章可以访问我的博客。如有侵权,保留追究法律责任的权利。
聊聊 Spring Cloud 全链路灰度发布 方案~
在实际生产环境中,为了进行需求变更和测试,猜谜源码通常采用灰度发布策略,即只切出部分流量进行新功能的试用,确保稳定后再全面上线,这能有效隔离潜在的bug影响大部分用户。 灰度发布,也称金丝雀发布,是一种平滑过渡的发布方式,允许部分用户尝试新特性,如无问题再逐步扩大范围。这种方式有助于早期发现问题并调整,最大程度地控制影响范围。 然而,仅仅在网关层面实现灰度发布还不够,因为内部服务间的调用可能不会传递灰度标记。全链路灰度发布需要确保服务间调用也能基于灰度标记进行路由。具体来说,发泄源码关键在于:定义灰度标记的传递方式,比如在请求头中添加grayTag参数。
确保灰度标记能在服务间有效传递,如通过ThreadLocal进行线程隔离。
利用元数据在注册中心区分灰度服务与正常服务。
对特定服务如文章服务和评论服务进行精准的灰度发布配置,如使用@RibbonClients注解指定受影响的服务。
实现全链路灰度发布涉及网关层的负载均衡改造,使用Ribbon和Spring Cloud Gateway,并在OAuth2.0鉴权前添加全局过滤器来处理灰度标记。同时,需要在openFeign调用中复制请求头以保持灰度标记。在Nacos中,通过配置文件或动态设置元数据来标记服务为灰度状态。 总结来说,全链路灰度发布的核心在于灰度标记的传递和精准配置,整个流程包括在请求中添加灰度标记、保证标记在服务间的传递、以及在Nacos中管理服务的灰度状态。Consul 留给你的时间不多了
HashiCorp 作出重要决定,所有产品和库的未来版本将从 Mozilla 公共许可证 v2.0 (MPL 2.0) 过渡到 Business Source License(BSL)v1.1。此变更引起社区高度关注和讨论,特别是 HashiCorp 的明星级产品如 Vagrant、Packer、Terraform、Consul、Nomad、Vault 等的开源版本。本次变更后,Consul 的开源版本主要使用了 BSL 许可证。
HashiCorp 的 BSL 许可证引发争议,导致社区讨论和抵抗。知名 Terraform 增强型工具 Terragrunt 的作者 Yevgeniy Brikman 在一篇博文中详细阐述了 BSL 协议的三大问题,并发起 OpenTF(后更名 OpenTofu)项目,以创建一个遵循 MPL 2.0 协议的 Terraform 分叉版本。
虽然 BSL 许可证变更不具有追溯性,所有变更前版本仍遵循 MPL 2.0,但老版本将面临无法持续迭代的问题,包括无法使用最新特性和优化、修复旧版本 bug 及安全漏洞的能力受限。HashiCorp 宣布安全问题修复截止至 年 月 日。
使用 BSL 许可证是否涉及风险?BSL 是商业软件许可证,旨在平衡开源和商业利益。最新版本为 1.1,它结合了开源和闭源软件特点,不属于传统开源协议范畴。BSL 允许开发者在一定时期内提供付费支持和服务,以在开源之前获得商业回报。期限结束后,软件许可将转为兼容 GPL 的协议,使用、修改和分发受到更宽松限制。
多家公司如 MariaDB、Couchbase、Lightbend、Cockroach Labs 和 Sentry 也采用 BSL 许可证。每家公司的生产环境使用限制和协议变更期限不同。例如,MariaDB 的 MaxScale 产品在生产环境中应用节点数限制为 3 个;Couchbase 的 Couchbase Lite、KV engine 产品不允许商业使用;Lightbend 的 Akka 产品在特定收入水平下可以免费使用。
HashiCorp 的 BSL 许可证使用限制为:不能以托管或嵌入方式向第三方提供竞争力产品,以与 HashiCorp 的付费版本竞争。这为企业用户在生产环境中使用 HashiCorp 产品带来了法务风险。
对于已经使用 HashiCorp 非商业版产品的用户,最佳做法是更换产品选型。在选择目标产品时,需要考虑两点:功能兼容性和迁移成本。以 HashiCorp Consul 为例,可考虑使用 Nacos 等主流注册中心作为平滑替代方案。Nacos 在license、CAP支持、高可靠性和生态方面优于 Consul、Eureka 和 Zookkeeper。
如何平滑迁移至 Nacos?Nacos Sync 提供了迁移工具,使服务 Provider 和 Consumer 可以解耦,并实现服务注册和发现的解耦。迁移过程包括安装 Nacos Sync、配置服务 Consumer 和 Provider、确认无问题后下线 Nacos Sync 和原有注册中心。
总之,HashiCorp 的 BSL 许可证变更对用户带来了潜在风险,选择替代产品和迁移方案是必要的。使用开源软件需深入了解许可证条款,以避免法律合规风险。Nacos 等注册中心提供了一个平滑过渡的选择,帮助用户减少风险并实现技术升级。
使用Copyonwrite改造本地缓存
背景
周四下午正在吃的下午茶,偷闲刷了一会手机(光明正大的),突然就有客服中心的**姐找上门来说xxx操作又出现失败了,但是多点几次又没问题了(之前也出现过,可是代码中没有任何异常处理和日志的输出很难排查,没办法老代码,前任写的我也没办法,只能加上等复现的时候再看看),看着**姐焦急的表情,下午茶瞬间就不香了,找bug去!
产生原因定位在rancher上输入账号找到对应的服务,根据关键字找到相关日志映入眼帘的是java.lang.NullPointException跟随报错的行数找到了相关代码块:
if(StringUtils.isNotEmpty(feeSetting.getFileId())){ returnschoolService.deal(sysConfigService.getString("url"));}其中报错的是
schoolService.deal(sysConfigService.getString("url"));定位问题,应该是调用StringgetString(Stringkey);空指针导致的.
分析相关代码:
publicStringgetString(Stringkey){ if(configs==null){ initConfig();}returnconfigs.get(key);}其中initConfig()的实现:
privatevoidinitConfig(){ synchronized(lock){ if((configs==null)||configs.isEmpty()){ configs=newHashMap<String,String>();//从db中加载到configsloadSysConfig();}}}其中configs是个成员变量
privatestaticMap<String,String>configs=null;复制代码查了一下数据库,有对应的数据存在,不是数据的问题
getString(Stringkey)接口内部没报错,说明这个程序没报错
抓了抓头(有点意思),只有Map中没有相应的数据才有可能报空指针,查找了相关方法,找到了如下代码:
publicvoidreload(){ if((configs!=null)&&!configs.isEmpty()){ configs.clear();this.initConfig();}}只有一处调用该方法
@ComponentpublicclassSysConfgMQListenerimplementsMessageListenerConcurrently{ protectedfinalLoggerlog=LoggerFactory.getLogger(SysConfgMQListener.class);@AutowiredprivateISysConfigServicesysConfigService;@OverridepublicConsumeConcurrentlyStatusconsumeMessage(List<MessageExt>msgs,ConsumeConcurrentlyContextcontext){ log.info("SysConfgMQListenerretrieving...");for(MessageExtmsg:msgs){ log.info("messageExt,body:{ }",newString(msg.getBody()));this.sysConfigService.reload();}returnConsumeConcurrentlyStatus.CONSUME_SUCCESS;}}这是RocketMq的消费者这里调用了,而且还是广播模式,所有节点都能消费,这个Mq的生产者是在后台触发刷新时候产生的.
真相只有一个首先触发Mq的消费,导致Map刷新,重新加载调用reload()
当执行configs.clear();之后Map就是一个空对象,没有任何数据
如果这个时候是有多个线程访问getString(Stringkey)获取到的值就是null
改造第一个想到的是用Redis来替换,但是很快就自我否定了,这个接口在没有触发刷新机制的前提下运行了几年是好好的,而且基础配置放Redis的话过期时间的设置不好判断,并且还要多个IO的传递,性能没有本地的Map好.
第二个想到的方案就是在getString(Stringkey)方法中加锁,这只能当做下下策
正在一筹莫展的时候,突然灵光一闪,这不是跟注册中心很像吗?各个客户端去拉取数据,而nacos为了高性能就是用了Copyonwrite的思想来实现的,越想越行,干!
代码改造如下:
publicvoidreload(){ if((configs!=null)&&!configs.isEmpty()){ //先清除再加载会出现,在两个操作之间请求的接口获取都为空//configs.clear();//this.initConfig();this.reloadForConfigs();}}其中this.reloadForConfigs();
privatevoidreloadForConfigs(){ Map<String,String>newConfigs=newHashMap<>();try{ List<Config>datas=configDao.listConfigs();if(datas!=null){ for(Configcf:datas){ newConfigs.put(cf.getKey(),cf.getValue());}}}catch(Exceptione){ LogUtil.exception(log,e);}if(CollectionUtil.isNotEmpty(newConfigs)){ //替换旧的this.configs=newConfigs;}}这改造完上线之后,跟踪了一段时间日志中也没发现空指针(**姐也不来找我了-_-,不开森),有那么一点点的成就感.
总结开发的时候要考虑多线程和并发场景
遇到问题别慌,认真分析
好的方案不是一蹴而就的
多读好的代码如框架源码,不断的积累,现在用不上,某一时刻就用上了
作者:董懂