04_SpringCloud

文章目录

  • 单体架构与微服务架构的介绍
    • 单体架构
    • 微服务架构
  • 微服务的实现
    • 服务之间的调用
    • 服务注册中心
      • Eureka 注册中心
      • Eureka的自我保护机制
      • Nacos注册中心

单体架构与微服务架构的介绍


单体架构

  • 单体架构
    • 所有的代码最终打包成一个文件(jar包),整个系统的所有功能单元整体部署到同一个进程
      在这里插入图片描述
  • 单体架构的扩容
    • 一个单体应用在运行时,会部署在一台云服务器上,但是随着用户体量的增长,一台云服务器上运行的一个单体应用,已经无法承载日益增长的请求量。
    • 我们可以对单体应用实现扩容,即使用单体应用集群,通过使用单体应用的集群,可以一定程度上,很好的应对日益增长的用户请求。但这个方案不是很完美
      在这里插入图片描述
  • 单体架构的优势
    • 应用的开发很简单
    • 易于对应用程序进行大规模的更改
    • 测试相对直观简单
    • 部署简单明了
    • 横向扩容不费吹灰之力
  • 单体架构的弊端
    • 代码过度复杂且严重耦合,导致难以维护
      1. 由于系统本身过于庞大和复杂,以至于任何一个开发者都很难理解它的全部,因此,修复软件中的问题和正确实现新功能就变得困难且耗时
      2. 更糟糕的是,这种极度的复杂性,可能会形成一个恶性循环: 由于代码难以理解,因此开发者在更改时更容易出错,每一次更改都会让代码库变得更复杂,更难懂
    • 从代码提交到实际部署的周期很长
      1. 众多开发人员都向同一个代码库提交代码,常常使得代码库的构建结构处于无法交付的状态。当采用了分支来解决这个问题,又必须忍受漫长且痛苦的合并过程
      2. 因为代码库中的代码十分复杂,以至于任何一个更改可能引起的影响是未知的,为了避免牵一发而动全身的后果,即使是一个微小的更改,也必须执行全部的测试
    • 扩展性受限
      1. 如果单体应用中的某一个功能点存在性能问题,那么就需要多部署几个单体应用的实例,再加上负载均衡的设备(比如nginx),才能保证整个应用的性能能够支撑用户的使用(资源浪费)
      2. 在某些情况下,应用的不同模块对资源的需求是相互冲突的,比如某些模块需要高效的IO,某些模块需要高性能的CPU, 而这些模块都在一个单体应用之内,因此其所部署的服务器必须满足所有的需求(成本过高)
    • 开发慢,启动慢,严重影响开发效率
    • 交付可靠的单体应用困难
      1. 单体应用体积庞大,难以进行全面和彻底的测试,而缺乏可靠的测试意味着代码中的错误会进入生产环境
      2. 缺乏故障隔离,因为所有的模块都在同一个进程中运行,每隔一段时间,在一个模块中的代码错误,将会导致整个应用程序的崩溃

微服务架构

  • 微服务架构
    • 本质就是按照单一职责原则实现了特定的一组功能
    • 因为每个微服务的本质都可以是一个应用程序,这就要求,微服务可以独立部署,独立运行,独立对外提供服务(运行在一个独立的进程中)
    • 微服务架构是模块化开发的一种形式
      • 在单体架构中,模块通常由一组编程语言所提供的的结构(例如Java中的包,或者jar文件)来定义,但是通过这种方式得到的模块,不同模块的代码还是可以相互引用,导致模块中对象依赖关系的混乱
      • 在微服务架构中,使用微服务作为模块化的单元,要访问服务,只能通过服务对外提供的API,于是服务的API为它自身构筑了一个不可逾越的边界,你无法越过API去访问服务内部的类。
        在这里插入图片描述
  • 微服务架构的优势
    • 每个服务都相对较小,容易维护
    • 使得大型的应用程序实现快速的持续交付和持续部署
      1. 每一个服务相对较小,编写全面的测试代码和执行自动化测试都变得相对容易
      2. 每个服务都独立于其他服务部署,如果负责服务的开发人员,需要部署对该服务的更改,不需要与其他开发人员协商,因此将更改频繁部署到生产中要容易的多
    • 应用扩展灵活
      1. 应用被拆分为不同的微服务,而微服务可以独立部署,因此,扩容就不在针对整个应用了,哪里出现性能瓶颈,对哪个服务扩容即可
      2. 即使不同的的服务需要资源存在冲突,也没有关系,把它们分别部署到具有拥有各自所需要资源的机器上即可
    • 更好的容错
      1. 相比于单体架构中,一个故障拖垮整个系统的情况,一个服务的故障,并不会影响想到其他服务的正常运行
  • 微服务架构的弊端
    • 分布式系统可能复杂难以管理
    • 分布式部署追踪问题难
      • 目前主流的解决方案
        1. 把所有服务的日志收集到同一个文件中(ELK)
        2. 给每一个调用生成一个唯一的ID标识,如果出现调用失败,输出这个ID标识(鹰眼系统)
    • 分布式事务比较难处理
    • 服务数量增加,管理复杂性增加
  • 微服务的拆分
    在这里插入图片描述

微服务的实现

在这里插入图片描述

  • CDN网络
    • Content Delivery Network(内容分发网络),主要是为了提高静态资源的访问速度
  • SpringCloud 基于SpringBoot提供了一套微服务架构实现的解决方案,包括服务的注册与自动发现,面向接口的服务调用,服务调用的负载均衡,服务网关,服务熔断等等组件,它利用SpringBoot开发的便利性,巧妙的简化了分布式系统的基础设施搭建,使开发者可以基于SpringBoot的开发风格做到快速启动和部署。

服务之间的调用

  • 服务调用之间的理论
    • 基于SpringCloud实现的微服务,其本质是Tomcat中的一个应用,它们都支持基于Http协议的通信,因此我们可以通过Http协议实现服务进程(实例)间的通信
    • 于是服务间的通信过程就变成了,调用者发送Http请求,被调用这返回Http响应,一次请求响应过程,就等价于一次服务调用过程
    • 在一次服务调用过程中,我们称调用者为服务消费者(使用或者消费另一个服务的功能),我们称被调用者为服务提供者(提供被消费的功能),服务消费者和服务提供者的概念仅仅是在单次调用中的概念,一个服务既可以是服务消费者,也可以是服务提供者
    • 因此,服务提供者只要对外暴露了接口,那么服务消费者就能通过调用服务提供者对外提供的接口,从而实现对服务提供者的调用,使用服务提供者的功能
  • 实现服务调用的准备
    • 通过代码发送Http请求——使用RestTemplate
      • RestTemplate是一个专门用来发送Http请求的工具,通过封装JDK中的HttpURLConnection类库,提供简单易用的模板方法API,它所提供的模板方法几乎覆盖了常用的所有Http请求类型的场景
  • 导入SpringCloud的配置
    <properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><spring-boot.version>2.2.2.RELEASE</spring-boot.version></properties><dependencyManagement><dependencies><!-- spring-boot --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency><!--spring cloud alibaba--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>2.1.0.RELEASE</version><type>pom</type><scope>import</scope></dependency><!--spring cloud--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Hoxton.SR1</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>

eg:

服务提供者实现

  • 依赖
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
</dependencies>
  • 配置
server:port: 8090
  • 代码
@RestController
public class BaseProviderController {@GetMapping("/base/provider/demo")public String baseDemo(String name) {String resp = "base-provider-demo" + name;return resp;}
}

服务提供者实现

  • 依赖同上
  • 配置
server:port: 8091
  • 代码
@RestController
public class BaseConsumerController {@GetMapping("/base/consumer/demo")public String baseDemo() {// 调用provider对外暴露的接口// 通过发起Http请求// 1. 请求的地址// http://localhost:8090/base/provider/demo?name=xxx// 2. 通过RestTemplate发起Http请求// RestTemplate restTemplate = new RestTemplate();// 3. 请求的参数自己定义// 1. 创建RestTemplate的对象RestTemplate restTemplate = new RestTemplate();// 2. 传可变长度的参数// 使用1,2,3,4来占位,表示是第几个参数// String resp = getVariblesParams(restTemplate);// 3. 使用hashMap// 使用HashMap中的Key来占位// String resp = getHashMapParams(restTemplate);// 4. 使用getForEntityString response = getForEntityUseHashMap(restTemplate);return response;}private static String getForEntityUseHashMap(RestTemplate restTemplate) {String url = "http://localhost:8090/base/provider/demo?name={name}";Class<String> respType = String.class;HashMap<String, Object> hashMap = new HashMap<>();hashMap.put("name", "ww");ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, respType, hashMap);// 响应码 200 500 404 302 304int codeValue = responseEntity.getStatusCodeValue();System.out.println("codeValue = " + codeValue);// 响应对象HttpStatus statusCode = responseEntity.getStatusCode();System.out.println("statusCode = " + statusCode);// 响应体String response = responseEntity.getBody();System.out.println("response = " + response);return response;}private static String getHashMapParams(RestTemplate restTemplate) {String url = "http://localhost:8090/base/provider/demo?name={name}";Class respType = String.class;HashMap<String, Object> hashMap = new HashMap<>();hashMap.put("name", "zs");String resp = (String) restTemplate.getForObject(url, respType, hashMap);return resp;}private static String getVariblesParams(RestTemplate restTemplate) {// {1}是用来占位的String url = "http://localhost:8090/base/provider/demo?name={1}";Class responseType = String.class;// 参数String resp = (String) restTemplate.getForObject(url, responseType, "ls");return resp;}
}

服务注册中心

  • 服务注册中心,由服务注册中心来统一管理服务的状态和信息
    在这里插入图片描述

Eureka 注册中心

  • Eureka是SpringCloud Netflix中包含的注册中心的组件,它扮演注册中心的角色,实现服务的注册与自动发现
  • Eureka采用了C-S的架构设计
    • EurekaServer作为服务器端,它具体就实现了服务注册中心的功能
    • EurekaClient作为客户端,服务提供者可通过它实现和EurekaServer的通信完成服务的注册,服务消费者可通过它与EurekaServer通信完成服务的自动发现
      在这里插入图片描述

eg:

配置并启动EurekaServer

  1. 新建一个子Maven工程,这个工程仅仅只是为了启动一个EurekaServer进程
    在这里插入图片描述
  2. 在子工程中添加依赖
    <dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency></dependencies>
  1. 在子工程的resources目录下添加配置信息
server:port: 7001
# Eureka配置
eureka:instance:# Eureka服务端的实例名字hostname: localhostclient:# 表示是否向 Eureka 注册中心注册自己(这个模块本身是服务器,所以不需要)register-with-eureka: false# fetch-registry如果为false,则表示自己为注册中心,客户端的化为 turefetch-registry: falseservice-url:defaultZone: http://localhost:7001/eureka/
  1. 配置启动类,并在启动类上添加注解@EnableEurekaServer
@SpringBootApplication
// 开启Eureka的注册中心
@EnableEurekaServer
public class EurekaServerApplication {public static void main(String[] args) {SpringApplication.run(EurekaServerApplication.class, args);}
}

服务提供者整合Eureka

  1. 在服务提供者的Maven工程中,添加如下依赖
    <dependencies><!-- springboot --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- eureka-client --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency></dependencies>
  1. 在子工程的resources目录下添加配置信息
spring:application:name: registry-provider  # 服务集群的名字
server:port: 7101eureka:client:service-url:defaultZone: http://localhost:7001/eureka/  # 注册中心的地址instance:instance-id: eureka-provider-7101  # 服务实例的名字hostname: localhost
  1. 配置启动类,并在主启动类添加注解@EnableEurekaClient
@SpringBootApplication
@EnableEurekaClient
public class EurekaProviderApplication1 {public static void main(String[] args) {SpringApplication.run(EurekaProviderApplication1.class, args);}
}
  1. controller的实现代码
@RestController
public class EurekaDemoController {@GetMapping("/eureka/provider/demo")public String eurekaDemo(String name) {System.out.println("eureka-provider1 调用到了");return name + "...";}
}

服务消费者整合Eureka

  1. 添加依赖
    <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency></dependencies>
  1. 在resources文件目录下添加配置
spring:application:name: registry-consumer
server:port: 7102# Eureka配置
eureka:client:service-url:defaultZone: http://localhost:7001/eureka/instance:instance-id: eureka-consumer-7102 #修改Eureka上的默认描述信息hostname: localhost
  1. 主启动类,添加注解
@SpringBootApplication
@EnableEurekaClient
public class EurekaConsumerApplication {public static void main(String[] args) {SpringApplication.run(EurekaConsumerApplication.class, args);}
}
  1. controller目录下添加代码
@RestController
public class EurekaConsumerController {@AutowiredDiscoveryClient discoveryClient;@GetMapping("/eureka/consumer/demo")public String consumerDemo() {// 发起Http请求,调用服务提供者// 需要注意的事情:不要把服务提供者的地址写死,引入注册中心的目的就是不写死地址// 1. 创建一个RestTemplate对象RestTemplate restTemplate = new RestTemplate();// 2. 从注册中心获取服务提供者的地址// 写集群的名字List<ServiceInstance> instanceList = discoveryClient.getInstances("registry-provider");for (ServiceInstance serviceInstance : instanceList) {String uri = serviceInstance.getUri().toString();System.out.println("uri = " + uri);String instanceId = serviceInstance.getInstanceId();System.out.println("instanceId = " + instanceId);}// 3. 发起调用ServiceInstance serviceInstance = instanceList.get(0);String uri = serviceInstance.getUri().toString();String url = uri + "/eureka/provider/demo?name={1}";Class<String> respType = String.class;String resp = restTemplate.getForObject(url, respType, "ls");return resp;}
}

Eureka的自我保护机制

自我保护机制触发的场景如下:

  • 默认情况下,当eureka server在一定时间内没有收到实例的心跳,便会把该实例从注册表中删除(默认是90秒
  • 但是,如果短时间内丢失大量的实例心跳,这意味着短时间内大量的服务连接丢失了,此时就会触发Eureka的自我保护机制
  • 触发自我保护机制的结果就是,Eureka认为虽然收不到实例的心跳,但它认为实例还是健康的,eureka会保护这些实例,不会把它们从注册表中删掉。

Eureka的自我保护机制的意义

  • 该保护机制的目的是避免网络连接故障,在发生网络故障时,微服务和注册中心之间无法正常通信,但服务本身是健康的
  • 此时,为了避免注册中心同时删除大量本来是正常运行(健康的)的服务实例,于是就会自动触发自我保护机制
  • 该自我保护机制开启之后,Eureka会保护注册表中的信息,不在注销任何微服务,当网络故障恢复后,Eureka会自动退出保护模式,从而使集群更加健壮。

在开发测试阶段应当把Eureka的自我保护机制禁用掉:

  • 原因:在开发测试阶段,需要频繁地重启发布,如果触发了保护机制,则旧的服务实例没有被删除,这时服务消费者按照注册表中的服务提供者信息,发出服务调用请求,会因为该实例关闭而失败,这就导致请求错误,影响开发测试
# 关闭Eureka的自我保护机制
eureka:server:enable-self-preservation: false

Nacos注册中心

  • Nacos(Dynamic Naming and Configuration Service)是服务中心的另外一种实现。从注册中心的功能实现角度,与Eureka等价,只是实现方式有所差异。
  • 与Eureka不同的是,Nacos注册中心类似于Tomcat,是独立启动的服务器

eg:

  1. 启动nacos服务器
    在这里插入图片描述
  2. 进入bin目录,打开命令行
windows: startup.cmd -m standalone
linux: startup.sh -m standalone

在这里插入图片描述

  1. 可以通过 localhost:8848/nacos 访问nacos
    在这里插入图片描述
  2. 在nacos-provider-8002模块中导入依赖
    <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- nacos注册中心 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency></dependencies>
  1. 在nacos-provider-8002模块中新增配置
server:port: 8002  # 服务提供者的端口号
spring:application:name: nacos-provider  # 集群的名字 cloud:nacos:discovery:# nacos服务器地址server-addr: localhost:8848 
  1. 在nacos-provider-8002模块中添加主启动类,添加注解
@SpringBootApplication
@EnableDiscoveryClient
public class NacosProviderApplication {public static void main(String[] args) {SpringApplication.run(NacosProviderApplication.class, args);}
}
  1. 在nacos-provider-8002模块中的controller目录下添加代码
@RestController
public class NacosProviderController {@GetMapping("/nacos/provider/demo")public String nacosDemo(String name) {return name + "nacos provider";}
}
  1. nacos-consumer-9001模块的依赖、配置、主启动类同nacos-provider-8002
  2. nacos-consumer-9001模块controller下的代码
@RestController
public class NacosConsumerController {@AutowiredDiscoveryClient discoveryClient;@GetMapping("/nacos/consumer/demo")public String nacosDemo() {// 发起Http请求,调用服务提供者// 需要注意的事情:不要把服务提供者的地址写死,引入注册中心的目的就是不写死地址// 1. 创建一个RestTemplate对象RestTemplate restTemplate = new RestTemplate();// 2. 从注册中心获取服务提供者的地址// 写集群的名字List<ServiceInstance> instanceList = discoveryClient.getInstances("nacos-provider");for (ServiceInstance serviceInstance : instanceList) {String uri = serviceInstance.getUri().toString();System.out.println("uri = " + uri);String instanceId = serviceInstance.getInstanceId();System.out.println("instanceId = " + instanceId);}// 3. 发起调用ServiceInstance serviceInstance = instanceList.get(0);String uri = serviceInstance.getUri().toString();String url = uri + "/nacos/provider/demo?name={1}";Class<String> respType = String.class;String resp = restTemplate.getForObject(url, respType, "ls");return resp;}
}

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

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

相关文章

(三十六)第 6 章 树和二叉树(二叉树的顺序存储表示实现)

1. 背景说明 2. 示例代码 1) errorRecord.h // 记录错误宏定义头文件#ifndef ERROR_RECORD_H #define ERROR_RECORD_H#include <stdio.h> #include <string.h> #include <stdint.h>// 从文件路径中提取文件名 #define FILE_NAME(X) strrchr(X, \\) ?…

[Kubernetes] Rancher 2.7.5 部署 k8s

server: 192.168.66.100 master: 192.168.66.101 node1: 192.168.66.102 文章目录 1.rancher server 安装docker2.部署k8s3.kubeconfig 1.rancher server 安装docker 所有主机开通ipv4 vi /etc/sysctl.conf#加入 net.ipv4.ip_forward 1#配置生效 sysctl -prancher-server开通…

【spark(零)】spark技术概览

文章目录 一. Spark入门二. Spark RDD与 Spark core三. Spark SQL四. Spark Streaming五. Spark内核原理 一. Spark入门 Spark基础知识 Spark部署模式、 Spark运行流程 【概述】spark&#xff08;一&#xff09;:spark特点、知识范畴、spark架构、任务提交流程、支持哪些运行…

鸿蒙准备1

鸿蒙心路 感慨索性&#xff0c; 看看鸿蒙吧。打开官网相关介绍 新建工程目录结构 感慨 最近面试Android应用开发&#xff0c;动不动就问framework的知识&#xff0c;什么touch事件的触发源是啥&#xff08;eventHub&#xff09;&#xff0c;gc流程是啥&#xff0c;图形框架是什…

美国纽扣电池UL4200A及16CFR1262标准亚马逊要求

2023年9月21日&#xff0c;美国消费品安全委员会CPSC(Consumer Product Safety Commission) 决定采用UL 4200A-2023&#xff08;包含纽扣电池或硬币电池的产品安全标准&#xff09;作为包含纽扣电池或硬币电池的消费品的强制性消费品安全规则&#xff0c;相关要求同时被编入到1…

超越视觉极限:深度学习图像超分辨率算法清单【第一部分】

超越视觉极限&#xff1a;深度学习图像超分辨率算法清单 简介2014年 - SRCNN (Super-Resolution Convolutional Neural Network)2016年 - VDSR (Very Deep Super Resolution)2016年 - LapSRN (Laplacian Pyramid Super-Resolution Network)2017年 - EDSR (Enhanced Deep Super-…

Linux Kernel入门到精通系列讲解(OpenSBI 篇) 3.1 OpenSBI 源码分析之汇编

1.概述 OpenSBI是什么?这个问题对于初学者来说很重要,OpenSBI主要的作用就是一段RISC-V架构程序跳转程序,它集成了许多常用的driver,方便使用者快速移植,学过ARM的应该都知道BL2,OpenSBI的作用就类似于BL2,一段运行在DDR上的程序,负责为U-boot等提供入口参数和程序跳转…

提供 DISC性格测试报告的全新 API接口,带给你惊喜的发现!

简介 DISC个性测验由24组描述个性特质的形容词构成&#xff0c;每组包含四个形容词&#xff0c;这些形容词是根据支配性&#xff08;D&#xff09;、影响性&#xff08;I&#xff09;、服从性&#xff08;C&#xff09;、 稳定性&#xff08;S&#xff09;和四个测量维度以及一…

Nacos面试题(一)

1. 简述什么是 Nacos&#xff1f; Nacos是Dynamic Naming and Configuration Service的简称&#xff0c;是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。Nacos可以帮助应用实现服务注册、发现和负载均衡&#xff0c;同时方便地管理配置信息。 具体来说&…

JMeter - 如何测试REST API / 微服务

概述&#xff1a; 有许多方法和工具可用于测试REST API。 当我需要测试REST API时&#xff0c;在查看了各种工具和选项之后&#xff0c;由于以下原因&#xff0c;我选择了JMeter。 JMeter是免费和开源的。 JMeter可以从CSV文件中直接读取您的测试数据。参数化非常简单。 可以…

SparkSQL与Hive整合 、SparkSQL函数操作

SparkSQL与Hive整合 SparkSQL和Hive的整合&#xff0c;是一种比较常见的关联处理方式&#xff0c;SparkSQL加载Hive中的数据进行业务处理&#xff0c;同时将计算结果落地回Hive中。 整合需要注意的地方 1)需要引入hive的hive-site.xml&#xff0c;添加classpath目录下面即可…

【web网页制作】html+css旅游家乡河南开封主题网页制作(4页面)【附源码】

HTMLCSS家乡河南主题网页目录 &#x1f354;涉及知识&#x1f964;写在前面&#x1f367;一、网页主题&#x1f333;二、页面效果Page1 首页Page2 开封游玩Page 3 开封美食Page4 留言 &#x1f308; 三、网页架构与技术3.1 脑海构思3.2 整体布局3.3 技术说明书 &#x1f40b;四…

springboot lua检查redis库存

需求 最近需求需要实现检查多个马戏场次下的座位等席对应库存渠道的库存余量&#xff0c;考虑到性能&#xff0c;决定采用Lua脚本实现库存检查。 数据结构 库存层级结构 redis库存hash类型结构 实现 lua脚本 --- 字符串分割为数组 local function split(str, char)local…

IIoT:数据融合在工业物联网中的应用——青创智通

工业物联网解决方案-工业IOT-青创智通 随着科技的不断发展&#xff0c;工业物联网&#xff08;IIoT&#xff09;已经逐渐渗透到各个行业&#xff0c;为企业的生产和管理带来了前所未有的便利。 然而&#xff0c;与此同时&#xff0c;海量的数据也为企业带来了挑战。如何将这些…

linux的firmware和hal层

linux的firmware和hal层 在Linux中&#xff0c;固件&#xff08;firmware&#xff09;和硬件抽象层&#xff08;Hardware Abstraction Layer&#xff0c;HAL&#xff09;是两个不同的概念。固件是运行在硬件设备上的程序&#xff0c;它们通常被用来控制硬件的操作。而HAL是一种…

【数学建模】天然肠衣搭配问题

2011高教社杯全国大学生数学建模竞赛D题 天然肠衣&#xff08;以下简称肠衣&#xff09;制作加工是我国的一个传统产业&#xff0c;出口量占世界首位。肠衣经过清洗整理后被分割成长度不等的小段&#xff08;原料&#xff09;&#xff0c;进入组装工序。传统的生产方式依靠人工…

Node.js v20.12.2版本执行npm run dev 报openssl 错误2024最新修复方案

Node.js v20.12.2版本执行npm run dev 报openssl 错误2024最新修复方案 故障描述修复方案 故障描述 ERROR SyntaxError: missing ) after argument list C:\Users\xxx\Documents\workspace\WebstormProjects\xxxx\node_modules\webpack\lib\util\createHash.js:135return new …

基于springboot实现可盈保险合同管理系统项目【项目源码+论文说明】

基于springboot实现可盈保险合同管理系统演示 摘要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本可盈保险合同管理系统就是在这样的大环境下诞生&#xff0c;其…

C语言总结五:操作符(压缩版)

一&#xff0c;操作符分类 算术操作符&#xff0c;移位操作符&#xff0c;位操作符&#xff0c;赋值操作符&#xff0c;单目操作符&#xff0c;关系操作符&#xff0c;逻辑操作符&#xff0c;条件操作符&#xff0c;逗号表达式&#xff0c;下标引用&#xff0c;函数调用&#…

MySQL中GROUP_CONCAT与JSON_OBJECT、GROUP BY的巧妙结合:打造高效JSON数组汇总

在数据库操作中&#xff0c;经常遇到需要将同一组内的多行数据汇总为一个结构化的输出&#xff0c;特别是在处理一对多关系时。MySQL 5.7及以上版本引入了对JSON的支持&#xff0c;使得这一过程变得更加灵活和高效。本文将以一个实例深入探讨如何利用GROUP_CONCAT结合JSON_OBJE…