微服务系列(一)springcloudAlibaba之Nacos注册和配置中心及openFeign远程调用

一,认识微服务

我们先看看开发大型项目采用单体架构存在哪些问题,而微服务架构又是如何解决这些问题的。

1.1 单体架构

单体架构(monolithic structure):整个项目中所有功能模块都在一个工程中开发;项目部署时需要对所有模块一起编译、打包;项目的架构设计、开发模式都非常简单。

当项目规模较小时,这种模式上手快,部署、运维也都很方便,因此早期很多小型项目都采用这种模式。

但随着项目的业务规模越来越大,团队开发人员也不断增加,单体架构就呈现出越来越多的问题:

1.1.1 单体架构呈现的问题: 
  • 团队协作成本高:试想一下,你们团队数十个人同时协作开发同一个项目,由于所有模块都在一个项目中,不同模块的代码之间物理边界越来越模糊。最终要把功能合并到一个分支,你绝对会陷入到解决冲突的泥潭之中。

  • 系统发布效率低:任何模块变更都需要发布整个系统,而系统发布过程中需要多个模块之间制约较多,需要对比各种文件,任何一处出现问题都会导致发布失败,往往一次发布需要数十分钟甚至数小时。

  • 系统可用性差:单体架构各个功能模块是作为一个服务部署,相互之间会互相影响,一些热点功能会耗尽系统资源,导致其它服务低可用。

1.2 微服务

微服务架构,首先是服务化,就是将单体架构中的功能模块从单体应用中拆分出来,独立部署为多个服务。同时要满足下面的一些特点:

  • 单一职责:一个微服务负责一部分业务功能,并且其核心数据不依赖于其它模块。

  • 团队自治:每个微服务都有自己独立的开发、测试、发布、运维人员,团队人员规模不超过10人

  • 服务自治:每个微服务都独立打包部署,访问自己独立的数据库。并且要做好服务隔离,避免对其它服务产生影响

就比如我们的购物商城,我们可以把商品,用户,购物车,交易等模块拆分,交给不同的团队去开发,并独立部署:

如果采用这样的开发方式,单体架构出现的问题解决了吗?

  • 团队协作成本高?

    • 由于服务拆分,每个服务代码量大大减少,参与开发的后台人员在1~3名,协作成本大大降低

  • 系统发布效率低?

    • 每个服务都是独立部署,当有某个服务有代码变更时,只需要打包部署该服务即可

  • 系统可用性差?

    • 每个服务独立部署,并且做好服务隔离,使用自己的服务器资源,不会影响到其它服务。

微服务架构解决了单体架构存在的问题,特别适合大型互联网项目的开发,因此被各大互联网公司普遍采用。大家以前可能听说过分布式架构,分布式就是服务拆分的过程,其实微服务架构正是分布式架构的一种最佳实践的方案。

1.2.1 微服务拆分出现的问题
  • 如果出现跨服务的业务该如何处理?

  • 页面请求到底该访问哪个服务?

  • 如何实现各个服务之间的服务隔离?

1.3 springcloud

微服务拆分以后碰到的各种问题都有对应的解决方案和微服务组件,而SpringCloud框架可以说是目前Java领域最全面的微服务组件的集合了。

而且SpringCloud依托于SpringBoot的自动装配能力,大大降低了其项目搭建、组件使用的成本。对于没有自研微服务组件能力的中小型企业,使用SpringCloud全家桶来实现微服务开发可以说是最合适的选择了!

1.3.1 springcloud官网

Spring Cloud

目前SpringCloud最新版本为2023.0.x版本,对应的SpringBoot版本为3.2.x版本,但2022及后续版本全部依赖于JDK17,目前在企业中使用相对较少。

SpringCloud版本SpringBoot版本
2023.0.x aka Leyton3.2.x
2022.0.x aka Kilburn3.0.x
2021.0.x aka Jubilee2.6.x, 2.7.x (Starting with 2021.0.3)
2020.0.x aka Ilford2.4.x, 2.5.x (Starting with 2020.0.3)
Hoxton2.2.x, 2.3.x (Starting with SR5)
Greenwich2.1.x
Finchley2.0.x
Edgware1.5.x
Dalston1.5.x

因此,我推荐使用:Spring Cloud 2021.0.x以及Spring Boot 2.7.x版本。

另外,Alibaba的微服务产品SpringCloudAlibaba目前也成为了SpringCloud组件中的一员,后面的内容中,我也会使用其中的部分组件。

二 微服务的拆分

2.1 熟悉我们的商城项目

先看一下我们商城的目录机构:

2.1.1 登录

看一下登录流程:

登录的方法在,controller。UserController这个类里面。

2.1.2 搜索商品

在首页的输入框里面,可以输入搜索关键字,点击搜索,进行搜索。

这个页面调用的接口是,/search/list,对应的服务端入口在,controller.SearchController这个类里面的Search方法。

2.1.3 购物车

在搜索到的商品列表中,点击按钮加入购物车,即可将商品加入购物车:

加入成功后即可进入购物车列表页,查看自己购物车商品列表:

我们可以在这里进行删除和修改的操作

相关的功能在,controller.CartController中

其中,查询购物车列表时,由于要判断商品最新的价格和状态,所以还需要查询商品信息,业务流程如下:

2.1.4 下单

在购物车页面,点击结算按钮,会进入订单结算页面:

点击提交订单,会提交请求到服务端,服务端做3件事情:

  • 创建一个新的订单

  • 扣减商品库存

  • 清理购物车中商品

业务入口在controller.OrderController类中的createOrder方法:

2.2 服务拆分原则

服务在才拆分的时候,我们要考虑几个问题:

  • 什么时候拆?

  • 怎么拆?

2.2.1 什么时候拆分

一般情况下,对于一个初创的项目,我们首先要做的就是验证项目的可行性。这个阶段,我们因该敏捷开发,快速生产可用的产品,投入市场进行验证。为了达到目的,我们往往是先开发单体架构,这个过程开发成本比较低,可以快速产出结果,一旦发现项目不符合市场,损失较小。

如果这一阶段采用复杂的微服务架构,投入大量的人力和时间成本用于架构设计,最终发现产品不符合市场需求,等于全部做了无用功。

最后得到的结论:

所以,对于大多数小型项目来说,一般是先采用单体架构,随着用户规模扩大、业务复杂后再逐渐拆分为微服务架构。这样初期成本会比较低,可以快速试错。但是,这么做的问题就在于后期做服务拆分时,可能会遇到很多代码耦合带来的问题,拆分比较困难(前易后难)。

而对于一些大型项目,在立项之初目的就很明确,为了长远考虑,在架构设计时就直接选择微服务架构。虽然前期投入较多,但后期就少了拆分服务的烦恼(前难后易)。

2.2.2 怎么拆分

微服务拆分时粒度要小,这其实是拆分的目标。具体可以从两个角度来分析:

  • 高内聚:每个微服务的职责要尽量单一,包含的业务相互关联度高、完整度高。

  • 低耦合:每个微服务的功能要相对独立,尽量减少对其它微服务的依赖,或者依赖接口的稳定性要强。

高内聚首先是单一职责,但不能说一个微服务就一个接口,而是要保证微服务内部业务的完整性为前提。目标是当我们要修改某个业务时,最好就只修改当前微服务,这样变更的成本更低。

一旦微服务做到了高内聚,那么服务之间的耦合度自然就降低了。

两种拆分方式
  • 纵向拆分

  • 横向拆分

所谓纵向拆分,就是按照项目的业务功能模块来拆分。例如商城中,就有用户管理功能、订单管理功能、购物车功能、商品管理功能、支付功能等。那么按照功能模块将他们拆分为一个个服务,就属于纵向拆分。这种拆分模式可以尽可能提高服务的内聚性。

横向拆分是看各个功能模块之间有没有公共的业务部分,如果有将其抽取出来作为通用服务。例如用户登录是需要发送消息通知,记录风控数据,下单时也要发送短信,记录风控数据。因此消息发送、风控数据记录就是通用的业务功能,因此可以将他们分别抽取为公共服务:消息中心服务、风控管理服务。这样可以提高业务的复用性,避免重复开发。同时通用业务一般接口稳定性较强,也不会使服务之间过分耦合。

我后面的微服务知识点,是按照纵向拆分的原则进行的

  • 商品服务

  • 购物车服务

  • 用户服务

  • 订单服务

  • 支付服务

2.3 拆分商品服务,购物服务

一般微服务项目有两种不同的工程结构:

  • 完全解耦:每一个微服务都创建为一个独立的工程,甚至可以使用不同的开发语言来开发,项目完全解耦。

    • 优点:服务之间耦合度低

    • 缺点:每个项目都有自己的独立仓库,管理起来比较麻烦

  • Maven聚合:整个项目为一个Project,然后每个微服务是其中的一个Module

    • 优点:项目代码集中,管理和运维方便(授课也方便)

    • 缺点:服务之间耦合,编译时间较长

2.3.1 商品服务
1 创建模块

在hmall中创建新的module:

选择 New Module 输入名称 item-service;注意JDK版本要使用11

2,添加依赖

item-service的pom.xml文件参考如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.heima</groupId>
        <artifactId>hmall</artifactId>
        <version>1.0.0</version>
    </parent>

    <artifactId>item-service</artifactId>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>
    <dependencies>
        <!--common-->
        <dependency>
            <groupId>com.heima</groupId>
            <artifactId>hm-common</artifactId>
            <version>1.0.0</version>
        </dependency>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--数据库-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>
        <!--单元测试-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
    </dependencies>
    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

在刚刚创建好的模块的pom,文件里面添加依赖。

3,创建启动引导类:

代码:

package com.hmall.item;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;

@MapperScan("com.hmall.item.mapper")
@SpringBootApplication
public class ItemApplication {
    public static void main(String[] args) {
        SpringApplication.run(ItemApplication.class,args);
    }
}
4,复制配置文件:

复制hm-service中的application.yml,application-local.yml,application-dev.yml,文件到item-service项目的resource下面。

修改application.yml文件修改如下:

server:
  port: 8081
spring:
  application:
    name: item-service
  profiles:
    active: dev
  datasource:
    url: jdbc:mysql://${hm.db.host}:3306/hm-item?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: ${hm.db.pw}
mybatis-plus:
  configuration:
    default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
  global-config:
    db-config:
      update-strategy: not_null
      id-type: auto
logging:
  level:
    com.hmall: debug
  pattern:
    dateformat: HH:mm:ss:SSS
  file:
    path: "logs/${spring.application.name}"
knife4j:
  enable: true
  openapi:
    title: 商品接口文档
    description: "商品接口文档"
    email: 666888.qq.com
    concat: hhhhhh
    url: https://www.123321.com
    version: v1.0.0
    group:
      default:
        group-name: default
        api-rule: package
        api-rule-resources:
          - com.hmall.item.controller
hm:
  jwt:
    location: classpath:hmall.jks
    alias: hmall
    password: hmall123
    tokenTTL: 30m
  auth:
    excludePaths:
      - /search/**
      - /users/login
      - /items/**
      - /hi
# keytool -genkeypair -alias hmall -keyalg RSA -keypass hmall123 -keystore hmall.jks -storepass hmall123

application-local.yaml里面也要改成自己虚拟机的IP地址和数据库密码

 

hm:
  db:
    host: 192.168.200.128 # 修改为你自己的虚拟机IP地址
    pw: root # 修改为docker中的MySQL密码
5,复制代码:

复制hm-service中与商品有关的代码到item-service中,复制的代码参考如下:

小提示:

还有一个地方需要改进,ItemServiceImpl中的deductStock方法:

代码:

    @Override
    public void deductStock(List<OrderDetailDTO> items) {
        String sqlStatement = "com.hmall.item.mapper.ItemMapper.updateStock";
        boolean r = false;
        try {
            r = executeBatch(items, (sqlSession, entity) -> sqlSession.update(sqlStatement, entity));

        } catch (Exception e) {
            log.error("更新库存异常", e);
            throw new BizIllegalException("库存不足!");
        }
        if (!r) {
            throw new BizIllegalException("库存不足!");
        }
    }

这也是因为ItemMapper的所在包发生了变化,因此这里代码必须修改包路径。

6,创建数据库表:

最后我们还要导入数据库表。默认的数据库连接的是虚拟机里面的,我们在docker里面进行操作

hm-item.sql文件:

把这个脚本导入到虚拟机对应的数据库里面,创建数据库表:

找到我们的脚本文件:

看看刚才创建好的库

7,测试:

接下来就是启动项目进行测试了;复制一个启动项并修改如下:

看看配置项

启动测试一下下:

接着,启动item-service,访问商品微服务的swagger接口文档:http://localhost:8081/doc.html

然后测试其中的根据id批量查询商品这个接口:

测试参数:100002672302,100002624500,100002533430,结果如下:

看到这个结果就代表我们的微服务拆分成功了

2.3.2 购物车服务
1,创建模块

下面就是刚刚创建好的模块

右击 cart-service 使用IDEA插件 JBLSpringBootAppGen 快速生成启动类及删除不相关文件。

2,添加依赖

打开 hmall/cart-service/pom.xml添加下面的依赖:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.heima</groupId>
        <artifactId>hmall</artifactId>
        <version>1.0.0</version>
    </parent>

    <artifactId>cart-service</artifactId>
    <packaging>jar</packaging>

    <name>cart-service</name>
    <url>http://maven.apache.org</url>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>
        <!--common-->
        <dependency>
            <groupId>com.heima</groupId>
            <artifactId>hm-common</artifactId>
            <version>1.0.0</version>
        </dependency>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--数据库-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>
        <!--单元测试-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>

    </dependencies>
    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

3,修改启动引导类

@MapperScan("com.hmall.cart.mapper")
@SpringBootApplication
public class CartApplication {
    public static void main(String[] args) {
        SpringApplication.run(CartApplication.class,args);
    }
}
4,复制配置文件

复制 hm-service 中的 application.yml、application-local.yml、application-dev.yml 文件到 item-service 项目的 resources目录如下:

application.yml文件修改后如下:

server:
  port: 8082
spring:
  application:
    name: cart-service
  profiles:
    active: local
  datasource:
    url: jdbc:mysql://${hm.db.host}:3306/hm-cart?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: ${hm.db.pw}
mybatis-plus:
  configuration:
    default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
  global-config:
    db-config:
      update-strategy: not_null
      id-type: auto
logging:
  level:
    com.hmall: debug
  pattern:
    dateformat: HH:mm:ss:SSS
  file:
    path: "logs/${spring.application.name}"
knife4j:
  enable: true
  openapi:
    title: 商城接口文档
    description: "商城接口文档"
    email: 434343434@qq.com
    concat: dsdsdsds
    url: https://www.ffgfgfgf.cn
    version: v1.0.0
    group:
      default:
        group-name: default
        api-rule: package
        api-rule-resources:
          - com.hmall.cart.controller
hm:
  jwt:
    location: classpath:hmall.jks
    alias: hmall
    password: hmall123
    tokenTTL: 30m
  auth:
    excludePaths:
      - /search/**
      - /users/login
      - /items/**
      - /hi
# keytool -genkeypair -alias hmall -keyalg RSA -keypass hmall123 -keystore hmall.jks -storepass hmall123
5,复制代码

复制hm-service中与购物车有关的代码到cart-service中;复制代码参考如下

注意事项:

    @Override
    public List<CartVO> queryMyCarts() {
        // 1.查询我的购物车列表
        // TODO 先将用户的id写死为1
        List<Cart> carts = lambdaQuery().eq(Cart::getUserId, 1L).list();
        if (CollUtils.isEmpty(carts)) {
            return CollUtils.emptyList();
        }

        // 2.转换VO
        List<CartVO> vos = BeanUtils.copyList(carts, CartVO.class);

        // 3.处理VO中的商品信息
        handleCartItems(vos);

        // 4.返回
        return vos;
    }

 

拆分好的结构

6,创建数据库表

在docker数据库中,执行下面的hm-cart的SQL。

运行后的结果

 7,测试

在启动前,同样要配置启动项的active profilelocal

然后启动CartApplication,访问swagger文档页面:http://localhost:8082/doc.html

看看测试结果:

我们注意到,其中与商品有关的字段值要么空要么是默认值!这就是因为刚才我们注释掉了查询购物车时,查询商品信息的相关代码。

那么,我们该如何在cart-service服务中实现对item-service服务的查询呢?

2.4服务调用

在拆分的时候,我们发现一个问题:就是购物车业务中需要查询商品信息,但商品信息查询的逻辑全部迁移到了item-service服务,导致我们无法查询。

最终结果就是查询到的购物车数据不完整,因此要想解决这个问题,我们就必须改造其中的代码,把原本本地方法调用,改造成跨微服务的远程调用(RPC,即Remote Produce Call)。

我们查询购物车的流程就变成了这样的:

代码中需要变化的就是这一步:

那么问题来了:我们该如何跨服务调用,准确的说,如何在cart-service中获取item-service服务中的提供的商品数据呢?

我们之前是怎么实现,远程的调用呢

我们在Swagger测试商品查询接口,就是向http://localhost:8081/items这个接口发起请求。

而这种查询就是通过http请求的方式来完成的,不仅仅可以实现远程查询,还可以实现新增、删除等各种远程请求。

2.4.1 RestTemplate

Spring给我们提供了一个RestTemplate的API,可以方便的实现Http请求的发送

其中提供了大量的方法,方便我们发送Http请求,例如:

查看 RestTemplate类可以看到常见的Get、Post、Put、Delete请求都支持,如果请求参数比较复杂,还可以使用exchange方法来构造请求。

我们在cart-service服务中定义一个配置类:

 

代码:

@Configuration
public class RemoteCallConfig {

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
2.4.2 远程调用

从hm-service中复制,我们修改cart-service中的com.hmall.cart.service.impl.CartServiceImplhandleCartItems方法,发送http请求到item-service

private void handleCartItems(List<CartVO> vos) {
        // 1.获取商品id
        Set<Long> itemIds = vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());
        // 2.查询商品
        String itemUrl = "http://localhost:8081/items?ids={ids}";
        ResponseEntity<List<ItemDTO>> response = restTemplate.exchange(
                itemUrl,//请求路径
                HttpMethod.GET,//请求方式
                null,//请求实体
                new ParameterizedTypeReference<List<ItemDTO>>() {
                },//响应数据类型
                Map.of("ids", CollUtils.join(itemIds, ","))//请求参数
        );
        List<ItemDTO> items = null;
        if (response.getStatusCode().is2xxSuccessful()) {
            items = response.getBody();
        }
        if (CollUtils.isEmpty(items)) {
            return;
        }
        // 3.转为 id 到 item的map
        Map<Long, ItemDTO> itemMap = items.stream().collect(Collectors.toMap(ItemDTO::getId, Function.identity()));
        // 4.写入vo
        for (CartVO v : vos) {
            ItemDTO item = itemMap.get(v.getItemId());
            if (item == null) {
                continue;
            }
            v.setNewPrice(item.getPrice());
            v.setStatus(item.getStatus());
            v.setStock(item.getStock());
        }

    }

我们重启cart-service,再次查询我们购物车列表接口

可以发现,所有商品相关数据都已经查询到了。

在这个过程中,item-service提供了查询接口,cart-service利用Http请求调用该接口。因此item-service可以称为服务的提供者,而cart-service则称为服务的消费者或服务调用者。

3,服务注册与发现

在上一章我们实现了微服务拆分,并且通过Http请求实现了跨微服务的远程调用。不过这种手动发送Http请求的方式存在一些问题。

试想一下,假如商品微服务被调用较多,为了应对更高的并发,我们进行了多实例部署,如图:

此时,每个item-service的实例其ip端口不同,问题来了。

  • item-service这么多实例,cart-service如何知道每一个实例的地址?

  • http请求要写url地址,cart-service服务到底该调用哪个实例呢?

  • 如果在运行过程中,某一个item-service实例宕机,cart-service依然在调用该怎么办?

  • 如果并发太高,item-service临时多部署了N台实例,cart-service如何知道新实例的地址?

为了解决上述问题,就必须引入注册中心的概念了,接下来我们就一起来分析下注册中心的原理。

3.1 注册中心原理

微服务远程调用的过程中,包括两个角色。

  • 服务提供者:提供接口供其它微服务访问,比如item-service

  • 服务消费者:调用其它微服务提供的接口,比如cart-service

在大型微服务项目中,服务提供者的数量会非常多,为了管理这些服务就引入了注册中心的概念。注册中心、服务提供者、服务消费者三者间关系如下:

流程如下:

1,服务启动时就会注册自己的服务信息(服务名、IP、端口)到注册中心

2,调用者可以从注册中心订阅想要的服务,获取服务对应的实例列表(1个服务可能多实例部署)

3,调用者自己对实例列表负载均衡,挑选一个实例

4,调用者向该实例发起远程调用

当服务提供者的实例宕机或者启动新实例时,调用者如何得知呢?

5,服务提供者会定期向注册中心发送请求,报告自己的健康状态(心跳请求)

6,当注册中心长时间收不到提供者的心跳时,会认为该实例宕机,将其从服务的实例列表中剔除

7,当服务有新实例启动时,会发送注册服务请求,其信息会被记录在注册中心的服务实例列表

8,当注册中心服务列表变更时,会主动通知微服务,更新本地服务列表

3.2 Nacos注册中心
3.2.1 注册中心简介

目前开源的注册中心框架有很多,国内比较常见的有:

  • Eureka:Netflix公司出品,目前被集成在SpringCloud当中,一般用于Java应用

  • Nacos:Alibaba公司出品,目前被集成在SpringCloudAlibaba中,一般用于Java应用

  • Consul:HashiCorp公司出品,目前集成在SPringCloud中,不限制微服务语言

我就以国内使用较多的Nacos的学习来举例子

Nacos官方网站如下:

3.2.2 安装Nacos
1,创建Nacos数据库

我们基于Docker来部署Nacos的注册中心,首先我们要准备MySQL数据库表,用来存储Nacos的数据。由于是Docker部署,所以大家需要将资料中的 nacos.sql SQL文件导入到你Docker中的MySQL容器中:

运行上述的SQL脚本文件之后;创建的nacos数据库表如下:

2,创建Nacos容器

修改文件中的 MYSQL_SERVICE_HOSTMYSQL_SERVICE_PASSWORD等,改为你自己虚拟机中的mysql容器对应的信息。

把资料下的/Nacos目录上传到虚拟机的/root目录。

进入root目录,然后执行下面的docker命令:

docker run -d \
--name nacos \
--env-file ./nacos/custom.env \
-p 8848:8848 \
-p 9848:9848 \
-p 9849:9849 \
--network hm-net \
--restart=always \
nacos/nacos-server:v2.1.0-slim

创建Nacos容器:

注意:如果下载 nacos 镜像有问题的话;则可使用资料提供的 nacos.tar

加载镜像的命令为:docker load -i nacos.tar

启动完成后,访问下面地址:http://192.168.200.128:8848/nacos/,注意将192.168.12.168替换为你自己的虚拟机IP地址。首次访问会跳转到登录页,账号密码都是nacos

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MySQL 备份方案

优质博文&#xff1a;IT-BLOG-CN 一、为什么要备份 【1】容灾恢复&#xff1a;硬件故障、不经意的 Bug 导致数据损坏&#xff0c;或者服务器及其数据由于某些原因不可获取或无法使用等&#xff08;例如&#xff1a;机房大楼烧毁&#xff0c;恶意的黑客攻击或 Mysql 的 Bug 等&…

React_ 三、Router路由配置

文章目录 [TOC](文章目录) Router路由配置安装和封装使用声明式导航Link和编程式导航useNavigate 导航传参useSearchParams 接收传参useParams 接收传参 路由嵌套children和菜单式渲染404路由配置 路由模式history模式&#xff0c;无/#/ 需要后端支持hash模式&#xff0c;有/#/…

开源模型应用落地-工具使用篇-Spring AI(七)

一、前言 在AI大模型百花齐放的时代&#xff0c;很多人都对新兴技术充满了热情&#xff0c;都想尝试一下。但是&#xff0c;实际上要入门AI技术的门槛非常高。除了需要高端设备&#xff0c;还需要面临复杂的部署和安装过程&#xff0c;这让很多人望而却步。不过&#xff0c;随着…

删除的文件能恢复吗?分享3个恢复方法

我们经常会遇到文件夹里的文件不小心被删除的情况&#xff0c;面对这种情况很多人会感到焦虑和无助。但实际上文件恢复并不是一件难事。在本文中我将分享一些实用的文件恢复方法&#xff0c;并深入探讨各种方法的优缺点&#xff0c;帮助大家更好地应对文件误删的问题。 首先让我…

集简云新增通义千问qwen 72b chat、qwen1.5 等多种大语言模型,提升多语言支持能力

通义千问再开源&#xff01;继发布多模态模型后&#xff0c;通义千问 1.5 版本也在春节前上线。 此次大模型包括六个型号&#xff1a;0.5B、1.8B、4B、7B、14B 和 72B&#xff0c;性能评测基础能力在在语言理解、代码生成、推理能力等多项基准测试中均展现出优异的性能&#x…

Jupyter如何开启Debug调试功能

由于需要对算子做远程调试功能&#xff0c;需要在jupyter中开启远程断点调试功能&#xff0c;特此记录。 本文写作时用到的系统是Ubuntu22&#xff0c;Python的版本是3.8. 首先&#xff0c;创建虚拟环境。 python -m venv venv source venv/bin/activate接着&#xff0c;安装…

hardlock.sys蓝屏解决办法【windows】

微软系统有时会蓝屏无法开机&#xff0c; 需要记下导致蓝屏的文件。 这里是【hardlock.sys】文件导致的。 解决办法是找到这个文件&#xff0c;把文件改名字&#xff0c;让系统找不到这个文件。 可以参考路径&#xff1a;C盘》C:\Windows\System32\drivers\hardlock.sys 把…

回归预测 | Matlab实现BiTCN-BiGRU-Attention双向时间卷积双向门控循环单元融合注意力机制多变量回归预测

回归预测 | Matlab实现BiTCN-BiGRU-Attention双向时间卷积双向门控循环单元融合注意力机制多变量回归预测 目录 回归预测 | Matlab实现BiTCN-BiGRU-Attention双向时间卷积双向门控循环单元融合注意力机制多变量回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.M…

金鸣识别(OCR)与人眼识别哪个更准?

关于OCR&#xff08;Optical Character Recognition&#xff0c;光学字符识别&#xff09;金鸣识别与人眼识别率的对比&#xff0c;确实是一个引人入胜的话题。首先&#xff0c;我们要明确一点&#xff0c;虽然OCR技术在过去几十年里取得了巨大的进步&#xff0c;但要达到与人类…

QCustomPlot / C++ 追踪点、标签绘制开发

一、项目介绍&#xff1a; QCustomPlot曲线相关 1、曲线&#xff08;折线&#xff09;的后面有一个标签&#xff1b;点击标签可移动垂直方向移动曲线 2、曲线下方有纯文本标签 3、曲线设置多个追踪点 4、追踪点可跟随鼠标沿着曲线移动 5、多条曲线移动不卡顿 二、项目展示…

[IDE工具]Ubuntu18.04 VSCode版本升级

一、下载新版本 https://code.visualstudio.com/Download 二、安装deb sudo dpkg -i code_1.87.0-1709078641_amd64.deb 升级完成&#xff01; 三、问题解决 1. 依赖于 libc6 (> 2.28)&#xff1b;然而&#xff1a;系统中 libc6:amd64 的版本为 2.27-3ubuntu1.6 1.1…

代码学习记录13

随想录日记part13 t i m e &#xff1a; time&#xff1a; time&#xff1a; 2024.03.06 主要内容&#xff1a;今天的主要内容是二叉树的第二部分哦&#xff0c;主要有层序遍历&#xff1b;翻转二叉树&#xff1b;对称二叉树。 102.二叉树的层序遍历226.翻转二叉树101. 对称二叉…

什么是ElasticSearch的深度分页问题?如何解决?

在ElasticSearch中进行分页查询通常使用from和size参数。当我们对ElasticSearch发起一个带有分页参数的查询(如使用from和size参数)时,ElasticSearch需要遍历所以匹配的文档直到达到指定的起始点(from),然后返回从这一点开始的size个文档 在这个例子中: 1.from 参数定义…

华为配置智能升级功能升级设备示例

配置智能升级功能升级设备示例 组网图形 图1 配置智能升级功能组网图 背景信息组网需求配置思路前提条件操作步骤操作结果 背景信息 为了方便用户及时了解设备主流运行版本&#xff0c;快速完成升级修复&#xff0c;华为设备支持自动下载、自助升级功能。用户在设备Web网管…

MySQl基础入门③

上一遍内容 接下来我们都使用navicat软件来操作数据了。 1.新建数据库 先创建我门自己的一个数据库 鼠标右键点击bendi那个绿色海豚的图标&#xff0c;然后选择新建数据库。 数据库名按自己喜好的填&#xff0c;不要写中文&#xff0c; 在 MySQL 8.0 中&#xff0c;最优的字…

Text-to-SQL任务中的思维链(Chain-of-thought)探索

导语 在探索LLM在解决Text-to-SQL任务中的潜能时&#xff0c;本文提出了一种创新的‘问题分解’Prompt格式&#xff0c;结合每个子问题的表列信息&#xff0c;实现了与顶尖微调模型&#xff08;RASATPICARD&#xff09;相媲美的性能。 会议&#xff1a;EMNLP 2023链接&#x…

Vue+SpringBoot打造考研专业课程管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 考研高校模块2.3 高校教师管理模块2.4 考研专业模块2.5 考研政策模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 考研高校表3.2.2 高校教师表3.2.3 考研专业表3.2.4 考研政策表 四、系统展示五、核…

【Flutter 面试题】什么是Flutter里的Key?有哪些分类有什么使用场景?

【Flutter 面试题】什么是Flutter里的Key?有哪些分类有什么使用场景&#xff1f; 文章目录 写在前面解答补充说明ValueKey 示例ObjectKey 示例UniqueKey 示例GlobalKey 示例 写在前面 关于我 &#xff0c;小雨青年 &#x1f449; CSDN博客专家&#xff0c;GitChat专栏作者&am…

Docker-自定义镜像

目录 1 前言 2 构建java应用的步骤及镜像结构图 2.1 构建步骤 2.2 镜像结构图 3 Dockerfile常用指令 4 Dockerfile的内容举例 4.1 一般形式 4.2 一般形式的优化 5 构建镜像 5.1 指令 5.2 实操 5.2.1 加载jdk镜像(基础镜像) 5.2.2 构建我们的镜像 5.2.3 使用我们的…

Excel中怎么求排名

使用Rank函数 1.在需要显示排名的单元格内&#xff0c;输入“RANK&#xff08;数值&#xff0c;数值列表&#xff0c;排序方式&#xff09;” 2.将“数值”替换为需要计算排名的单元格的地址&#xff0c;例如E2单元格。 3.将“数值列表”替换为排名的数值范围&#xff0c;例…