分布式、微服务项目知识点

nacos

注册中心

①引入spring-cloud-starter-alibaba-nacos-discovery依赖
②开启服务注册发现,在主程序上添加EnableDiscoveryClient
③配置文件添加nacos地址
④配置文件添加服务名字,这样才知道注册中心注册了哪个服务

配置中心

①引入依赖spring-cloud-starter-alibaba-nacos-config
②创建bootstrap.properties配置文件,并在里面声明nacos地址和服务名称,这个配置文件优先application.yml运行
③在nacos页面配置中心添加数据集(Data Id),应用默认加载的是服务应用名+.properties
④配置文件里添加任何配置
⑤添加配置文件动态刷新,在controller上添加@RefreshScope(动态获取并刷新配置),@value(“${配置项的名}”)获取配置文件的值
⑥如果配置项配置中心和当前应用配置文件都有,优先使用配置中心中的配置。
细节
1)命名空间:配置隔离;spring.cloud.nacos.config.namespace=命名空间的UUID
默认是public,默认新增的所有配置都在public
①开发、测试、生产:利用命名空间来做环境隔离
②每一个微服务直接相互隔离配置,每一个微服务都创建自己的命名空间,只加载自己命名空间下的配置
2)配置集:所有配置的集合
3)配置集ID(Data ID):类似文件名
4) 配置分组:
默认所有的配置集都属于:DEFAULR_GROUP
设置应用使用哪个组的配置:spring.cloud.nacos.config.group=DEFAULT_GROUP(组名)
5)同时加载多个数据源:
bootstrap.properties上配置如下内容

#选择多数据源
spring.cloud.nacos.config.extension-configs[0].data-id=datasource.yml
spring.cloud.nacos.config.extension-configs[0].group=dev
spring.cloud.nacos.config.extension-configs[0].refresh=true
spring.cloud.nacos.config.extension-configs[1].data-id=mybatis.yml
spring.cloud.nacos.config.extension-configs[1].group=dev
spring.cloud.nacos.config.extension-configs[1].refresh=true

Feign

①引入依赖spring-cloud-starter-openfeign
②接口上声明是远程调用,并写清楚调用的是哪个服务的接口,如@FeignClient(“youhui”)
③开启远程调用功能:主程序加上@EnableFeignClients(basePackages = “com.guli.huiyuan.feign”)

gateway

容器用的是Netty,而不是Tomcat,netty拥有非常高的网络性能

路由转发

spring:
  application:
    name: getway
  cloud:
    gateway:
      routes:
        - id: baidu_route  #路由id,一般使用服务名称,不能重复
          uri: http://www.baidu.com  # 实际要转发的路径
          predicates: #断言,条件符合的才会转发
            - Query=url,baidu

        - id: shangpin_route
          uri: lb://shangping  #lb代表负载均衡
          predicates:
            - Path=/api/shangping/**
          filters:
            - RewritePath=/api/(?<segment>.*),/$\{segment}

鉴权

限流

日志输出

性能测试

nginx动静分离:静态资源放在nginx上,tomcat只处理请求数据
数据库加索引
用Java自带工具jvisualvm来监控堆内存,发现频繁GC就相应给新生代和老年代增加内存
业务逻辑上有多次查数据库的可以改为一次查数据库所有值保存起来,然后再从保存值用lambda过滤所得对应条件的值
加缓存

缓存

适合放入缓存:即时性、数据一致性要求不高的,不用每次都展示最新的消息,如物流信息和菜单
访问量大且更新频率不高的数据(读多写少)

堆外内存溢出(OutOfDirectMemoryError)

springboot2.0后默认使用lettuce作为操作redis的客户端,lettuce底层使用netty(高吞吐)进行网络通信。lettuce的bug导致netty堆外内存溢出,没有及时释放连接。netty堆外内存没有指定会默认使用-Xmx。如果只是增大内存,高并发时他只会延迟堆外内存溢出的出现时间,后面还会出现。
解决方法:1、升级lettuce客户端;2、切换jedis使用成spring boot操作客户端的工具。(redis依赖排除lettuce,引入jedis依赖)

缓存穿透

指查询一个一定不存在的数据,由于缓存不命中就会导致每次都去查数据库,失去缓存的意义。
风险:利用不存在的数据进行大量攻击,导致数据库瞬时压力过大,最终程序崩溃;
解决:null值也存入缓存,并设置短暂过期时间(防止下次有这个数据)

缓存雪崩

指大量数据存入缓存时使用了相同的过期时间,导致某一时刻缓存大量失效,全都访问到数据库。数据库压力雪崩。
解决:在每个缓存的过期时间加上一个随机值,如1-5分钟,这样缓存过期时间的重复率就会下降,就不会导致缓存同一时刻大量失效。

缓存击穿

指一个热点数据设置了过期时间,数据刚好失效时大量请求来查询,导致大量请求直接访问数据库。
解决:加锁,让第一个获得锁的请求查数据后把数据存到缓存,释放锁后让其他获得锁的请求先查缓存就会有数据,不用再去请求数据库。缓存数据应该在锁里面加,加完再释放锁,不然在释放锁后再加缓存可能会导致多查询数据库,因为当锁释放后,缓存加数据需要时间,可能另一个线程拿到锁后缓存还没数据,导致又要去数据库查找。

分布式锁

引入spring-boot-starter-data-redis依赖
使用redisTemplate来做Redis连接工具

//1、占分布式锁。去Redis占坑
        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "111");
        if (lock){
            //加锁成功。。。执行业务
            Map<String,List<Catelog2Vo>> map = getDate();
            redisTemplate.delete("lock");//删除锁
            return map;
        }else {
            //加锁失败。。。重试
            //休眠100ms重试
            return getCatelogJson();//自旋的方式
        }

这个Redis方法是不存在才会存入值并且返回true(Redis里就是set lock test NX,NX就是不存在才会添加,添加后返回ok)

锁问题

如以上代码,如果在执行业务异常或断电,这就会导致锁没删除,那个线程就一直占用着锁,别人永远拿不到,就会导致死锁。
方法:在执行业务前设置锁的过期时间(业务里面加的);隐患:设置锁过期前断电导致死锁。

//1、占分布式锁。去Redis占坑
        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "111");
        if (lock){
            //加锁成功。。。执行业务
            redisTemplate.expire("lock",300,TimeUnit.SECONDS);
            Map<String,List<Catelog2Vo>> map = getDate();
            redisTemplate.delete("lock");//删除锁
            return map;
        }

方法:在设置锁时同步设置过期时间(set lock test EX 300 NX)(原子操作);隐患:执行业务时间过长,锁过期时间到自动删除,执行删除锁操作时无锁可删这还是乐观的情况,最坏情况是执行删锁时因为锁过期了被其他线程获取锁执行业务,这时候删的锁就是其他线程的锁了。这样别的线程就会拿到锁进来,2个线程同时操作,就没锁住。

//1、占分布式锁。去Redis占坑
        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "111",300,TimeUnit.SECONDS);
        if (lock){
            //加锁成功。。。执行业务
            //设置过期时间必须和加锁是同步的,原子的
            //redisTemplate.expire("lock",300,TimeUnit.SECONDS)
            Map<String,List<Catelog2Vo>> map = getDate();
            redisTemplate.delete("lock");//删除锁
            return map;
        }

方法:给锁加UUID值,删锁时先获取锁的名称,是自己的锁再删;隐患:当去拿到锁的UUID值时,锁的值过期自动删除了,这时删锁了,就会有2个线程进来,①是锁自动过期拿锁进来的;②是手动删锁后别的线程拿锁进来;

//1、占分布式锁。去Redis占坑
        String uuid = UUID.randomUUID().toString();
        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid,300,TimeUnit.SECONDS);
        if (lock){
            //加锁成功。。。执行业务
            //设置过期时间必须和加锁是同步的,原子的
            //redisTemplate.expire("lock",300,TimeUnit.SECONDS)
            Map<String,List<Catelog2Vo>> map = getDate();
            String lockValue = redisTemplate.opsForValue().get("lock").toString();
            if (uuid.equals(lockValue)){
                //删除我自己的锁
                redisTemplate.delete("lock");//删除锁
            }
            return map;
        }

方法:删锁时判断该锁名称是否该值(原子性),Redis官方推荐的脚本删锁。

//1、占分布式锁。去Redis占坑
        String uuid = UUID.randomUUID().toString();
        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid,300,TimeUnit.SECONDS);
        if (lock){
            //加锁成功。。。执行业务
            //设置过期时间必须和加锁是同步的,原子的
            //redisTemplate.expire("lock",300,TimeUnit.SECONDS)
            Map<String,List<Catelog2Vo>> map;
            try{
                map = getData();
            }finally {
                String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
                redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class)
                        , Arrays.asList("lock"), uuid);
            }
//            String lockValue = redisTemplate.opsForValue().get("lock").toString();
//            if (uuid.equals(lockValue)){
//                //删除我自己的锁
//                redisTemplate.delete("lock");//删除锁
//            }
            return map;
        }

redisson(分布式锁)

引依赖,编写配置类(设置redis连接信息),编写业务(获得锁,加锁,释放锁)。
此锁是阻塞式等待,默认加的锁都是30S时间
优点:1、锁的自动续期,如果业务执行时间过长,运行期间每10S(看门狗机制,每/3,10秒会执行定时任务重新刷新过期时间)会自动给锁续上新的30S,不用担心锁过期自动删掉。
2、加锁的业务只要运行完成,就不会给当前锁续期,即使不手动解锁,锁默认30S后会自动删除。
也可以自己设置锁过期时间,发送脚本到redis执行,但自己设置的就不会自动续期,到期就会删除锁 。

锁的分类

可重入锁:A拿到锁后B还可以继续拿锁;
公平锁:按照请求的顺序依次拿锁,1拿完就2拿;
读写锁:当有写锁时,读锁不能用,保证数据都是最新的,写锁就是所谓的排他锁(互斥锁,独享锁),读锁和写锁一般是成对存在,读锁可以多个,读锁是共享锁,写锁没释放读就必须等待。读锁没释放,写锁就必须等待。
信号量: 设置信号量大小,然后每次获取一个信合,最多获取信号量最大值个,还要获取就需要等待(或者调尝试获取方法,有就返回true没有就返回false),当使用完可以释放信合,信号量重新加一。
闭锁:等待所有锁执行完才执行业务。拿锁,设置锁执行次数,等待闭锁完成,后面每次拿锁使用时就计数减一,直到执行完锁的次数,闭锁自动完成。可以用了做限流。

缓存一致性

数据修改了需要保证缓存里的数据也同步更新
方法:
①双写操作,更改数据完同步更改缓存里的数据;隐患:会出现脏数据,如更改1,然后写缓存1比较慢,更改2,写缓存2完成,写缓存1才完成。解决:加读写锁,保证改数据和改缓存同步。
在这里插入图片描述

②失效模式,改完数据删缓存,后面需要用缓存里数据时会从数据库拿;隐患:出现脏数据,写完1,删除1,写完2,然后读缓存,缓存没有查数据库1,删除缓存2,最后更新缓存(是第一次改数据库的值,不是最新改第二次的值);解决:加读写锁,但是如果要经常改的数据且要实时获取的,就没必要使用缓存了。
在这里插入图片描述

③使用canal,canal相当于从数据库,会把数据库更新的二进制文件同步过来,然后更新返回redis。缺点:又加了一个中间件,需要做配置。
在这里插入图片描述

SpringCache

引依赖,配置,开启缓存功能,使用注解缓存

线程池

启动线程我们直接让线程池里提交任务,不然每次都要 new Thread()会控制不住资源导致系统资源不够用。
七大参数:
int corePoolSize,核心线程数(一直存在,除非设置超时销毁);线程池创建好以后就准备就绪状态;
int maximumPoolSize,最大线程数量;控制资源
long keepAliveTime,存活时间。如果当前线程数量大于核心线程数量,释放空闲的线程(线程空闲时间大于存活时间);
TimeUnit unit,存活时间的时间单位;
BlockingQueue workQueue,阻塞队列。如果任务很多,就会将目前多的任务放在队列里面,只要有空闲线程,就会去队列里面取出新的任务继续执行。
ThreadFactory threadFactory,线程的创建工厂
RejectedExecutionHandler handler 拒绝策略,如果队列满了就执行指定的拒绝策略拒绝执行任务(如删除新旧任务、同步执行任务等)。

工作顺序:
1)、线程池创建,设置好核心线程数量,准备接受任务;
2)、核心线程满了,就将再进来的任务放入阻塞队列中,空闲的core(核心)就会自己去阻塞队列获取任务执行;
3)、阻塞队列满了,就直接开新线程执行,最大只能开到max指定的数量;
4)、max满了就用拒绝策略拒绝任务;
5)、max都运行玩了,有很多空闲,在指定的存活时间以后,释放max-core这些线程。

优点:
①降低资源的消耗:通过重复利用已经创建好的线程,降低线程的创建和销毁带来的损耗。
②提高响应速度:因为线程池的线程数没有超过线程池的最大上限时,有的线程处于等待分配任务的状态,当任务来时无需创建新的线程就能执行。
③提高线程的可管理性:根据当前系统的特点对池内的线程进行优化处理,减少创建和销毁带来的系统开销,可以进行统一的分配资源。

OAuth2.0

在这里插入图片描述
原理:
①需要用其他应用登录的平台向用户申请请求认证(如CSDN点击QQ登录);
②用户授权(用户输入QQ账号和密码);
③给认证服务器认证,检查用户输入信息是否正确(验证QQ账号密码是否正确);
④认证通过,返回访问令牌给第三方(账号密码正确,返回访问令牌给CSDN);
⑤第三方应用使用访问令牌访问其他应用资源服务器,获取开放保护信息(CSDN使用访问令牌访问QQ获取自己需要的信息);
⑥资源服务器返回受保护信息和认证令牌给第三方(QQ返回昵称头像等信息给CSDN)。

session

session是储存在服务器上本次会话的数据(正常是用户状态数据)
分布式下session共享问题:①同一个服务,发往不同的服务器,session不同步,解决:1,、Tomcat复制session到其他服务器(几台可以,多了就浪费资源,影响带宽);2、IP hash一致性,nginx配置负载方法为iphash,这样每个IP都会访问同一台服务器;
②不同服务,session不能共享。解决:1、子域共享session,只要域名是子域的都存到redis里去,这样每个服务都去Redis上查都可以查到;

SpringSession

引依赖,yml配置使用Redis存储,主程序开启Redis自动存储session功能@EnableRedisHttpSession
子域共享:
1、编写配置类,自定义cookie,设置cookie的作用域为统一(放大作用域,一般为主域名);
2、编写配置类,定义序列划结果为JSON,方便观察

消息中间件

异步调用
应用解耦
流量控制(流量削峰)

RabbitMQ

在这里插入图片描述
工作流程
1、生产者发送消息(头+体),包含路由键(指定发送给哪个虚拟主机的交换机);
2、交换机收到消息会根据自己跟队列的绑定关系发到对应的队列里面;
3、消费者跟消息队列建立了长连接(消费者宕机后会把消息存起来,避免大量消息遗失),通过信道拿到消息队列里的消息。
一个客户端只跟队列一次连接。
使用:
①引入依赖,开启MQ功能(监听消息才需要开启),配置MQ的地址,端口,和虚拟主机地址;
②创建交换机:amqpAdmin.declareExchange(new DirectExchange(交换机名字,是否持久化,是否自动删除));
③创建队列:amqpAdmin.declareQueue(new Queue(队列名字,是否持久化,是否排他(只能自己连),是否自动删除));
④创建交换机和队列(交换机)的绑定关系:amqpAdmin.declareBinding(new Binding(目的地,目的地类型,交换机名字,路由键,自定义参数));
⑤发消息:rabbitTemplate.converAndSend(交换机名字,路由键,消息)。注意:如果发送的消息是个对象,会自动使用序列化机制将对象写出去,对象就必须实现 serializable;如果想是JSON的话就需要创建MQ配置文件,添加一个消息转换器为JSON的消息转换器。
⑥收消息:类跟方法上标@RabbitListener(queues={“队列名”}数组),只能方法上就用@RabbitHandler(),可以重载接收不同类型的消息,开启监听消息,放在业务逻辑组件上,必须放在容器中才能起作用。

RabbitMQ消息确认机制-可靠性抵达

保证消息不丢失,可靠性抵达,可以使用事务消息,但性能会下降250倍,为此引入确认机制
1、confirmCallback 确认模式:消息生产者发送消息到消息服务器然后确认回调通知生产者;
2、returnCallback 未投递到 queue 退回模式:消息服务器中,交换机发消息到队列后确认回调通知交换机;
3、ack机制:队列到消息消费者,就通知队列。
在这里插入图片描述

幂等性

接口幂等性就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的。
解决方案:
1、token机制:执行业务前获取token存到Redis,然后前端发送请求接口时携带token过来,服务端获取Redis上的token对比,一致才执行业务,为了保证只有一个请求拿到值对比成功,所以需要获取、比较和删除必须要原子性,使用Redis lua脚本来完成,Redis执行如下脚本。

if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end

2、使用锁:只要控制好数据库的操作即可,所以可以使用悲观锁(写多读少,一般跟事务一起使用,查询都在锁里面)和乐观锁(读多写少,数据库加个字段version,每次更新拿到version值,然后更新时+1,更新时对比version值,不匹配不进行更新)和分布式锁(在业务执行时加锁)。
3、

事务

本地事务

基本性质:

 原子性:一系列的操作整体不可拆分,要么同时成功,要么同时失败
 一致性:数据在事务的前后,业务整体一致。如转账。A:1000;B:1000; 转 200 事务成功; A:800 B:1200
 隔离性:事务之间互相隔离。
 持久性:一旦事务成功,数据一定会落盘在数据库。

隔离级别:

读未提交:该隔离级别的事务会读到其它未提交事务的数据,此现象也称之为脏读。

读已提交:一个事务可以读取另一个已提交的事务,多次读取会造成不一样的结果,此现象称为不可重复读问题,Oracle 和 SQL Server 的默认隔离级别。

可重复读:该隔离级别是 MySQL 默认的隔离级别,在同一个事务里,select 的结果是事务开始时时间点的状态,因此,同样的 select 操作读到的结果会是一致的,但是,会有幻读现象。MySQL的 InnoDB 引擎可以通过 next-key locks 机制(参考下文"行锁的算法"一节)来避免幻读。

序列化:在该隔离级别下事务都是串行顺序执行的,MySQL 数据库的 InnoDB 引擎会给读操作隐式加一把读共享锁,从而避免了脏读、不可重读复读和幻读问题。

事务的坑:在同一个类里面,编写两个方法,内部调用的时候,会导致事务设置失效。原因是没有用到
代理对象的缘故。
解决:
0)、导入 spring-boot-starter-aop
1)、@EnableTransactionManagement(proxyTargetClass = true)
2)、@EnableAspectJAutoProxy(exposeProxy=true)
3)、AopContext.currentProxy() 调用方法

分布式事务

CAP

CAP原则又称CAP定理:指的是在一个分布式系统中
 一致性:在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
 可用性:在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
 分区容错性:大多数分布式系统都分布在多个子网络。每个子网络就叫做一个区(partition)。分区容错的意思是,区间通信可能失败。比如,一台服务器放在中国,另一台服务器放在美国,这就是两个区,它们之间可能无法通信。
CAP 原则指的是,这三个要素最多只能同时实现两点,不可能三者兼顾

BASE

BASE理论:是对 CAP 理论的延伸,思想是即使无法做到强一致性(CAP 的一致性就是强一致性),但可
以采用适当的采取弱一致性,即最终一致性。有基本可用(允许损失响应时间或部分功能性)、软状态、最终一致性

方案

1、2PC模式(3PC引入超时):事务协调器要求每个涉及到事务的数据库预提交(precommit)此操作,并反映是
否可以提交. 第二阶段:事务协调器要求每个数据库提交数据。其中,如果有任何一个数据库否决此次提交,那么所有数据库都会被要求回滚它们在此事务中的那部分信息。
2、TTC事务补偿:自定义事务准备(try接口,业务调取)、提交、回滚代码,然后事务协调器统一调提交、回滚接口。
3、最大努力通知型方案:异常时通知其他服务,引进MQ,把消息发给MQ,然后其他服务订阅。
springCloud Alibaba有组件seata

seata(并发不高的分布式事务)

在这里插入图片描述

Seata 的整体工作流程如下:

1、TM(事务管理器,@GlobalTransactional) 向 TC(事务协调器,一个服务器需要下载注册到nacos) 申请开启一个全局事务,全局事务创建成功后,TC 会针对这个全局事务生成一个全局唯一的 XID(此时,由TM发起的全局事务已经开启)

2、XID 通过服务的调用链传递到其他服务

3、RM(资源管理器,每个微服务的@Transactional) 向 TC 注册一个分支事务,并将其纳入 XID 对应全局事务的管辖(事务参与者执行本地事务,此时分支事务已经执行完成,并反馈给TC执行结果。可以理解为AT模式下的第一个阶段)

4、TM 根据 TC 收集的各个分支事务的执行结果,向 TC 发起全局事务提交或回滚决议(事务协调者根据事务管理者的决议,发送提交或回滚的调度命令,可以理解为AT模式下的第二阶段)

5、TC 调度 XID 下管辖的所有分支事务完成提交或回滚操作
使用步骤:
1、为每个服务创建 undo_log 表;
2、需要分布式事务的服务导入 seata-starter
3、使用 seata 数据源代理原数据源
4、给微服务加入 file.conf 和 registry.conf
5、启动 seata 服务器
6、使用事务注解
7、测试回滚效果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 以下是我推荐的几个Java微服务实战项目: 1. Spring Cloud微服务电商项目:这是一个完整的电商应用程序,使用Spring Cloud实现微服务架构。它包括注册中心、配置中心、网关、商品服务、订单服务、用户服务等多个微服务模块,涵盖了大部分微服务技术点。 2. 微服务在线教育项目:这是一个在线教育平台,使用Spring Cloud实现微服务化。它包括注册中心、配置中心、网关、用户服务、课程服务、订单服务等多个微服务模块,同时还使用了分布式事务解决方案Seata,涵盖了分布式事务相关技术点。 3. 微服务电影购票项目:这是一个电影购票应用程序,使用Spring Cloud实现微服务化。它包括注册中心、配置中心、网关、影院服务、电影服务、订单服务等多个微服务模块,同时还使用了Spring Cloud Stream实现消息驱动,涵盖了消息驱动相关技术点。 希望这些项目对您有所帮助! ### 回答2: 在Java开发领域,有几个热门的微服务实战项目可以推荐。 首先,Spring Cloud是目前非常流行的微服务框架之一。它是基于Spring Boot构建的,提供了一套完善的微服务解决方案。推荐的一个实战项目是使用Spring Cloud搭建一个电子商务平台。该项目模拟了一个完整的电商系统,包括用户管理、商品管理、订单管理等功能。通过这个项目,你可以学习到如何使用Spring Cloud实现服务注册与发现、服务间通信、负载均衡等微服务相关的知识。 其次,Quarkus是一种新兴的微服务开发框架,它专注于减小应用程序的资源消耗和启动时间。推荐的一个实战项目是使用Quarkus构建一个在线投票系统。该项目可以让用户创建投票活动,并允许其他用户参与投票。通过这个项目,你可以学习到如何使用Quarkus开发快速、高效的微服务应用。 最后,Micronaut是另一个快速、轻量级的微服务框架。它提供了许多与Spring Boot类似的特性,但更加注重性能和资源利用率。推荐的一个实战项目是使用Micronaut构建一个在线博客平台。该项目包括博客的创建、发布、评论等功能。通过这个项目,你可以学习到如何使用Micronaut开发高性能的微服务应用,以及如何利用其注解驱动的开发模式提高开发效率。 总之,以上推荐的实战项目都可以帮助你深入了解Java微服务的开发实践和常用工具。无论你选择哪一个项目,都应该注重实际动手实践,通过编码和调试来加深对微服务开发的理解。 ### 回答3: 有许多值得推荐的Java微服务实战项目,以下列举几个较为常见的: 1. Spring Cloud Netflix:Spring Cloud Netflix是基于Spring Cloud开发的一套微服务项目实战框架,包含众多组件,如Eureka(服务注册与发现)、Ribbon(负载均衡)、Hystrix(断路器)等,帮助开发者快速构建可扩展的微服务架构。 2. Spring Boot + Docker:结合Spring Boot和Docker可以轻松构建可部署的微服务。使用Spring Boot可以方便地创建独立的、生产级别的Spring应用程序,而Docker则提供了环境隔离和轻量级部署的特性,使得微服务的部署和管理更加便捷。 3. Apache Dubbo:Apache Dubbo是一种高性能、轻量级的Java微服务框架。它支持多语言、多协议的微服务调用,具有服务注册和发现、负载均衡、服务容错等核心功能,适用于大规模的分布式系统。 4. Spring Cloud Alibaba:Spring Cloud Alibaba是Spring Cloud与阿里巴巴集团开发的一套微服务工具链,基于Spring Cloud实现了服务注册与发现、配置中心、消息总线等功能。该项目与阿里巴巴的一些开源产品(如Nacos)深度集成,为开发者提供了更多的选择。 无论选择哪个Java微服务实战项目,了解微服务架构的基本概念和原则是必要的。此外,熟悉分布式系统的设计和开发经验以及相关的技术栈(如数据库、消息中间件等)也是必备的。最重要的是,选择的项目要与自己的实际需求相符,并具备社区支持和活跃度,以便在遇到问题时能够得到及时的帮助和解决方案。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值