JAVA架构篇——CRUD以外的新大陆,主打一个思想升华(微服务篇)

(有一说一,我相信大家能看出来有些内容一眼AI,但是我觉得ai有时候能把我脑子里的想法表达的很清楚,这会省去很多时间,还请大家多多包涵~~~)

📚 本文学习路线与重点

本文将从个人项目经验出发,逐步深入到企业级微服务架构的核心组件,最后探讨分布式环境下的并发控制。以下是层层递进的学习路线:

🎯 学习重点与目标

  1. 第一阶段:从个人项目到企业认知
    • 理解个人项目与企业项目的本质差异
    • 认识微服务架构的演进必要性
    • 掌握 Spring Cloud 基础架构图
  2. 第二阶段:网关技术深度解析
    • 核心重点:Zuul 网关的业务层功能(路由、认证、限流)
    • 核心重点:Nginx 的网络层优势(性能、静态资源、负载均衡)
    • 关键理解:两者如何协同工作形成双层网关架构
  3. 第三阶段:分布式环境下的并发挑战
    • 核心问题:为什么单机锁在微服务中失效?
    • 解决方案:分布式锁的原理与实现方案
    • 实战重点:Redis 分布式锁的代码实现与注意事项
    • 应用场景:库存扣减、订单防重等实际业务场景

🚀 学习收益

  • 掌握企业级微服务架构中网关的选型与部署策略
  • 理解从单机应用到分布式系统的思维转变
  • 学会在分布式环境下保证数据一致性的关键技术
  • 获得可直接应用于实际项目的代码示例和架构方案

接下来,让我们按照这个路线,一步步深入理解每个环节的技术细节和实战应用。

先说一句,秋招真让人头大哇,不过我不想做一个只会背八股,丢到企业环境里就懵逼的新人,所以我都是自己做项目,然后实习也踏踏实实干活,现在就是站在企业的角度讲给大家真实的企业环境下要用到什么,毕竟网上现在都卷上天了,大家都太焦虑了~

博主在最近实习了三个月后,帮我所在的这家公司做了一个系统,虽然是在微服务架构和主从复制下的一个模块,但是这次的经验让我真真切切的理解到了企业项目的复杂度远远高于个人项目,不过话又说回来(典中典),AI 横行的时代,一些 CRUD 的工作完全可以靠 AI 来做了,所以我们可以从新的角度来学习,当 AI 驾驶员,那么架构就尤其重要了~

那么我们话不多说,开始正文~

首先,你要先有自己从 0 到 1 的一个项目(这里因为博主最近换了一家实习,之后带大家做一个,但是可能要花一些时间来整理了)

为什么强调自己做呢?其实是因为现在这个时代,虽然网上视频很多,但是网上的你自己可以刷一遍知道有点啥功能,剩下自己做就完事儿了,因为每个人的思路不同,自己做的感受是及其深刻的,然后就是当你自己做完你可能发现就是一些 CRUD 以及一些中间件,比如 Redis 和 RabbitMQ 这些的使用,本质上好像也是基于业务需求的一些 CRUD,这个时候你就会发现自己好像突然停滞不前,不知道从哪里继续提升自己了(本人的真实写照呜呜呜)

然后在一次吃饭的时候,和我们的主管聊到了最近的状态,他说可以了解一下微服务的架构,于是,我踏进了架构的大门

首先一般而言,当单机架构不能支撑公司的业务,公司就会拓展到微服务的架构

然后有一个 Spring Cloud 的一种架构如下:

因为这里其实现在都用 Nacos 作为注册中心了,但是现在市面上还是有一些老系统是用 Eureka 的,所以画了 Eureka,然后知道了这个图,我们就分别讲一下他们干了点啥~

Zuul网关与Nginx的作用

在微服务架构中,网关(Gateway)扮演着至关重要的角色,它就像是整个系统的“大门”和“交通警察”。Zuul和Nginx是两种常见的网关/代理解决方案,它们的作用既有重叠,也有各自的侧重点。

1. Zuul网关的作用

Zuul是Netflix开源的API网关,后来被Spring Cloud集成,成为Spring Cloud Netflix套件的一部分。它的核心作用包括:

  • 路由转发:作为所有外部请求的统一入口,根据配置的规则,将请求转发到后端的各个微服务。例如,所有以 /api/user/** 开头的请求都转发到用户服务。
  • 负载均衡:与Eureka或Nacos等服务发现组件结合,自动将请求分发到同一个服务的多个实例上,提高系统的可用性和处理能力。
  • 身份认证与安全:在网关层统一进行身份验证(如JWT校验)、权限控制和安全过滤(如防止SQL注入、XSS攻击),避免每个微服务重复实现。
  • 限流与熔断:可以对API的访问频率进行限制,保护后端服务不被突发流量冲垮。同时,当某个下游服务不可用时,可以进行熔断,快速失败并返回降级响应,避免雪崩效应。
  • 请求监控与日志:集中记录所有经过网关的请求和响应日志,便于问题排查和系统监控。

简单来说,Zuul是面向业务逻辑的智能路由器和过滤器,它深度集成在Spring Cloud生态中,更擅长处理基于服务发现的路由和复杂的业务过滤链。

2. Nginx的作用

Nginx是一个高性能的HTTP和反向代理服务器。在微服务架构中,它通常被部署在更外层,作用包括:

  • 反向代理与负载均衡:这是Nginx最核心的功能。它接收客户端请求,并根据配置的负载均衡策略(如轮询、权重、IP哈希)将请求转发到后端的服务器集群(可以是Zuul网关集群,也可以是直接的应用服务器)。
  • 静态资源服务:Nginx处理静态文件(如图片、CSS、JS)的效率极高,通常用它来直接提供前端页面和静态资源,减轻应用服务器的压力。
  • SSL/TLS终端:在Nginx上配置HTTPS证书,负责SSL/TLS加解密,让后端的应用服务器专注于处理业务逻辑。
  • 高并发与高可用:Nginx采用事件驱动、非阻塞的架构,能够轻松应对数万甚至数十万的并发连接,是构建高可用、高性能网站的关键组件。
  • 简单的路由与重写:可以通过配置实现基于URL路径、域名等的简单路由和重写规则。

简单来说,Nginx是面向网络和性能的“流量分发器”和“静态资源管家”,它更侧重于网络层的性能、稳定性和简单的请求分发。

3. 两者如何协作?

在实际的企业级架构中,Zuul和Nginx常常是协同工作的关系,形成两层网关:

  1. Nginx作为第一层(入口网关):负责SSL卸载、全局负载均衡、静态资源服务和将请求分发给后端的多个Zuul网关实例。
  2. Zuul作为第二层(业务网关):接收来自Nginx的请求,进行精细化的API路由、身份认证、限流熔断等业务逻辑处理,再将请求转发给具体的微服务。

这种分工使得Nginx可以发挥其高性能、高稳定的特长处理网络流量,而Zuul则可以专注于复杂的业务路由和治理逻辑,两者相辅相成。

那么了解到这些有啥用呢,当然是站在全局看代码了,你看这种架构下,你还能用 synchronized 吗?

答案当然是不可以啦

你看要是一个接口过来很多请求,他就先会分配资源吧,分配完资源后实例开始处理这些接口,你要是用到锁这个方法,那你的数据还能保持一致性吗?

4. 微服务架构下的锁机制

synchronized 是 Java 中的单机锁,它只在单个 JVM 进程内有效。在微服务架构中,由于请求会被分发到多个服务实例上,单机锁无法保证跨进程的数据一致性。

为什么单机锁在微服务中失效?
  1. 多实例部署:微服务通常会有多个实例运行在不同的服务器或容器中。
  2. 负载均衡:Nginx/Zuul 会将请求分发到不同的实例,每个实例都有自己的 JVM。
  3. 锁范围有限synchronized 只能锁住当前 JVM 内的资源,无法跨进程锁住共享资源。
解决方案:分布式锁

在微服务架构中,需要使用分布式锁来保证跨多个服务实例的数据一致性。常见的分布式锁实现方案:

  • 基于 Redis 的分布式锁
    • 使用 SETNX(SET if Not eXists)命令实现
    • 需要设置过期时间,防止死锁
    • 示例:Redisson 客户端提供了完善的分布式锁实现
  • 基于 ZooKeeper 的分布式锁
    • 利用 ZooKeeper 的顺序节点和临时节点特性
    • 通过创建临时顺序节点来实现公平锁
    • 可靠性高,但性能相对较低
  • 基于数据库的分布式锁
    • 利用数据库的唯一约束或乐观锁
    • 简单但性能较差,不适合高并发场景
Redis 分布式锁示例代码

(吐槽一下,这ai写的,一定要把导入的东西写到代码里吗,大家看个示例就好,还是要遵循咱们公司的代码规范的~)

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

public class DistributedLockExample {
    
    private RedissonClient redissonClient;
    
    public DistributedLockExample() {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");
        this.redissonClient = Redisson.create(config);
    }
    
    public void processWithLock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        
        try {
            // 尝试获取锁,最多等待10秒,锁持有时间30秒
            boolean isLocked = lock.tryLock(10, 30, java.util.concurrent.TimeUnit.SECONDS);
            
            if (isLocked) {
                try {
                    // 临界区代码 - 保证同一时刻只有一个实例能执行
                    System.out.println("获取到分布式锁,执行业务逻辑...");
                    // 你的业务逻辑 here
                } finally {
                    lock.unlock();
                }
            } else {
                System.out.println("获取锁失败,可能有其他实例正在处理");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.out.println("获取锁被中断");
        }
    }
}
使用分布式锁的注意事项
  1. 锁的粒度:锁的粒度要适中,太粗影响性能,太细增加复杂度。
  2. 超时时间:必须设置合理的超时时间,防止死锁。
  3. 可重入性:同一个线程可以多次获取同一把锁。
  4. 容错性:考虑 Redis/ZooKeeper 集群故障时的处理方案。
  5. 性能影响:分布式锁会增加网络开销,需要评估对性能的影响。
实际架构中的锁使用场景
  • 库存扣减:防止超卖,保证库存数据的准确性
  • 订单创建:防止重复下单
  • 配置更新:保证配置变更的原子性
  • 定时任务:防止多个实例同时执行同一个定时任务

所以回到你的问题:在微服务架构下,不能使用 synchronized,但可以使用分布式锁来解决跨实例的数据同步问题。选择哪种分布式锁方案,需要根据业务场景、性能要求和团队技术栈来决定。

所以虽然我只是初步了解了皮毛,但是确真的让我意识到了业务决定了架构和技术深度,嗯嗯

希望大家有所收获~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Re.不晚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值