微服务实现高并发 秒杀系统,前后端实现
一、前端实现
前端项目初始化
首先,我们需要创建一个新的 Vue 3 项目。你可以使用 Vue CLI 来快速搭建项目。
安装 Vue CLI(如果尚未安装)
bash
npm install -g @vue/cli
创建 Vue 项目
bash
vue create seckill-frontend
cd seckill-frontend
在创建过程中选择默认的 Vue 3 预设或其他你需要的配置。
安装 Axios
Axios 是一个常用的 HTTP 客户端,用于发送请求到后端 API。
bash
npm install axios
实现前端功能
1. 商品列表页面
创建一个 ProductList.vue
组件来显示商品列表,并提供秒杀按钮。
html
<template><div class="product-list"><h1>Available Products</h1><ul><li v-for="product in products" :key="product.id" class="product-item"><h2>{{ product.name }}</h2><p>Price: ${{ product.price }}</p><p>Stock: {{ product.stock }}</p><button @click="seckill(product.id)" :disabled="product.stock <= 0 || isSeckilling">{{ isSeckilling ? 'Secilling...' : 'Seckill Now' }}</button></li></ul></div>
</template><script>
import axios from 'axios';export default {data() {return {products: [],isSeckilling: false,};},created() {this.fetchProducts();},methods: {async fetchProducts() {try {const response = await axios.get('http://localhost:8080/api/products?page=0&size=10');this.products = response.data;} catch (error) {console.error('Error fetching products:', error);}},async seckill(productId) {if (this.isSeckilling) return;this.isSeckilling = true;try {const response = await axios.post(`http://localhost:8080/api/products/seckill/${productId}/1/1`);alert(response.data);} catch (error) {console.error('Seckill failed:', error);alert('Seckill failed! Please try again.');} finally {this.isSeckilling = false;this.fetchProducts(); // Refresh product list after attempting seckill}},},
};
</script><style scoped>
.product-list {padding: 20px;
}.product-item {border-bottom: 1px solid #ccc;padding: 10px 0;
}.product-item button {margin-top: 10px;padding: 5px 10px;cursor: pointer;
}
</style>
2. 主页路由配置
修改 src/router/index.js
文件以包含 ProductList
组件。
js
import { createRouter, createWebHistory } from 'vue-router';
import ProductList from '../components/ProductList.vue';const routes = [{path: '/',name: 'ProductList',component: ProductList,},
];const router = createRouter({history: createWebHistory(),routes,
});export default router;
3. 修改 App.vue
确保 App.vue
正确引入并使用路由。
html
<template><router-view></router-view>
</template><script>
export default {name: 'App',
};
</script><style>
#app {font-family: Avenir, Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;color: #2c3e50;margin-top: 60px;
}
</style>
运行前端应用
确保你的后端服务正在运行,然后启动前端应用:
bash
npm run serve
打开浏览器访问 http://localhost:8081
(假设前端服务运行在 8081 端口),你应该能看到商品列表和秒杀按钮。
总结
通过以上步骤,我们成功创建了一个简单的前端应用使用 Vue 3.0 来与后端秒杀系统进行交互。以下是整个前端项目的概览图:
二、后端实现
实现一个高并发秒杀系统是一个复杂的任务,需要仔细设计和优化以确保系统的稳定性和性能。以下是一个详细的步骤指南,帮助你构建一个基于微服务架构的高并发秒杀系统。
1. 技术选型
选择合适的技术栈对于提高系统的性能和可维护性至关重要。以下是一些推荐的技术:
- 框架: Spring Boot
- 数据库: MySQL 或 PostgreSQL
- 缓存: Redis
- 消息队列: RabbitMQ 或 Kafka(如果需要异步处理)
- 负载均衡: Nginx
- 容器化: Docker
- 部署: Kubernetes
- 分布式锁: Redisson 或 Zookeeper
2. 架构设计
2.1 微服务架构
将应用分解为多个微服务,每个微服务负责特定的功能。例如:
- User Service: 用户管理
- Product Service: 商品管理
- Order Service: 订单管理
- Seckill Service: 秒杀活动管理
- Inventory Service: 库存管理
- Gateway Service: API Gateway
2.2 API Gateway
使用 Spring Cloud Gateway 或 Netflix Zuul 作为 API Gateway,负责路由请求到相应的微服务,并提供统一的身份验证和日志记录。
2.3 数据库设计
设计合理的数据库模式,确保查询高效。可以使用关系型数据库(如 MySQL)或 NoSQL 数据库(如 MongoDB),具体取决于需求。
2.4 缓存机制
使用 Redis 进行缓存,减少对数据库的直接访问,提高响应速度。
2.5 异步处理
使用消息队列(如 RabbitMQ 或 Kafka)进行异步处理,提高系统的吞吐量和响应速度。
2.6 分布式锁
使用 Redisson 或 Zookeeper 实现分布式锁,确保库存扣减的原子性。
3. 实施步骤
3.1 创建 Spring Boot 项目
使用 Spring Initializr 创建一个新的 Spring Boot 项目。
https://start.spring.io/
选择以下依赖:
- Spring Web
- Spring Data JPA
- MySQL Driver
- Lombok
- Spring Security (如果需要身份验证)
- Spring Cloud Gateway
- Spring Cloud Eureka (服务注册与发现)
- Spring AMQP (RabbitMQ)
- Redis
- Resilience4j (容错)
3.2 配置数据库连接
在 application.properties
中配置数据库连接:
spring.datasource.url=jdbc:mysql://localhost:3306/seckill_system?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
3.3 创建实体类
创建实体类来表示数据库中的表。例如,创建 Product
和 Order
实体类:
java
package com.seckillsystem.model;import lombok.Data;import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;@Entity
@Data
public class Product {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String name;private Double price;private Integer stock;
}
package com.seckillsystem.model;import lombok.Data;import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;@Entity
@Data
public class Order {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private Long productId;private Long userId;private Integer quantity;
}
3.4 创建 Repository
创建 Repository 接口来操作数据库。例如,创建 ProductRepository
和 OrderRepository
:
java
package com.seckillsystem.repository;import com.seckillsystem.model.Product;
import org.springframework.data.jpa.repository.JpaRepository;public interface ProductRepository extends JpaRepository<Product, Long> {
}
package com.seckillsystem.repository;import com.seckillsystem.model.Order;
import org.springframework.data.jpa.repository.JpaRepository;public interface OrderRepository extends JpaRepository<Order, Long> {
}
3.5 创建 Service 层
创建 Service 层来处理业务逻辑。例如,创建 ProductService
和 OrderService
:
java
package com.seckillsystem.service;import com.seckillsystem.model.Product;
import com.seckillsystem.repository.ProductRepository;
import org.redisson.api.RedissonClient;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.Optional;@Service
public class ProductService {@Autowiredprivate ProductRepository productRepository;@Autowiredprivate RedissonClient redissonClient;public Optional<Product> getProductById(Long id) {return productRepository.findById(id);}public boolean reduceStock(Long productId) {RLock lock = redissonClient.getLock("product:" + productId + ":lock");try {if (lock.tryLock()) {Product product = productRepository.findById(productId).orElse(null);if (product != null && product.getStock() > 0) {product.setStock(product.getStock() - 1);productRepository.save(product);return true;}}} finally {if (lock.isHeldByCurrentThread()) {lock.unlock();}}return false;}
}
package com.seckillsystem.service;import com.seckillsystem.model.Order;
import com.seckillsystem.repository.OrderRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class OrderService {@Autowiredprivate OrderRepository orderRepository;public Order createOrder(Order order) {return orderRepository.save(order);}
}
3.6 创建 Controller 层
创建 Controller 层来处理 HTTP 请求。例如,创建 ProductController
和 OrderController
:
java
package com.seckillsystem.controller;import com.seckillsystem.model.Product;
import com.seckillsystem.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;import java.util.List;
import java.util.Optional;@RestController
@RequestMapping("/api/products")
public class ProductController {@Autowiredprivate ProductService productService;@GetMappingpublic List<Product> getAllProducts() {return productService.getAllProducts();}@GetMapping("/{id}")public ResponseEntity<Product> getProductById(@PathVariable Long id) {return productService.getProductById(id).map(ResponseEntity::ok).orElse(ResponseEntity.notFound().build());}@PostMapping("/seckill/{productId}/{userId}/{quantity}")public ResponseEntity<String> seckill(@PathVariable Long productId, @PathVariable Long userId, @PathVariable Integer quantity) {if (productService.reduceStock(productId)) {Order order = new Order();order.setProductId(productId);order.setUserId(userId);order.setQuantity(quantity);productService.createOrder(order);return ResponseEntity.ok("Seckill successful!");} else {return ResponseEntity.badRequest().body("Seckill failed! Out of stock.");}}
}
package com.seckillsystem.controller;import com.seckillsystem.model.Order;
import com.seckillsystem.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/api/orders")
public class OrderController {@Autowiredprivate OrderService orderService;@PostMappingpublic Order createOrder(@RequestBody Order order) {return orderService.createOrder(order);}
}
3.7 配置 Redis 缓存
在 pom.xml
中添加 Redis 依赖:
xml
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.16.8</version>
</dependency>
在 application.properties
中配置 Redis 连接:
spring.redis.host=localhost
spring.redis.port=6379# Redisson configuration
spring.redisson.config=classpath:redisson-config.yml
创建 redisson-config.yml
文件:
singleServerConfig:address: "redis://127.0.0.1:6379"
threads: 0
nettyThreads: 0
codec:class: "org.redisson.codec.JsonJacksonCodec"
transportMode: "NIO"
3.8 使用 Swagger 文档
添加 Swagger 依赖以生成 API 文档:
在 pom.xml
中添加 Swagger 依赖:
xml
<dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>3.0.0</version>
</dependency>
创建 Swagger 配置类:
java
package com.seckillsystem.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;@Configuration
@EnableSwagger2
public class SwaggerConfig {@Beanpublic Docket api() {return new Docket(DocumentationType.SWAGGER_2).select().apis(RequestHandlerSelectors.basePackage("com.seckillsystem.controller")).paths(PathSelectors.any()).build();}
}
3.9 容器化和部署
创建 Dockerfile
来容器化应用:
为每个微服务创建一个 Dockerfile
。这里以 Product Service
为例:
Dockerfile
# Use an official OpenJDK runtime as a parent image
FROM openjdk:17-jdk-slim# Set the working directory in the container
WORKDIR /app# Copy the current directory contents into the container at /app
COPY target/product-service.jar /app/product-service.jar# Make port 8080 available to the world outside this container
EXPOSE 8080# Run the application
CMD ["java", "-jar", "product-service.jar"]
假设其他微服务也有类似的结构,你可以分别为它们创建相应的 Dockerfile
。
3.9.2 构建 Docker 镜像
在每个微服务目录中运行以下命令来构建 Docker 镜像:
bash
mvn clean package
docker build -t product-service .
重复上述步骤为其他微服务构建镜像。
3.9.3 使用 Docker Compose 进行本地开发
为了简化多容器应用的开发、测试和部署,可以使用 Docker Compose。
创建 docker-compose.yml
文件:
Yaml
version: '3.8'services:product-service:image: product-serviceports:- "8081:8080"environment:SPRING_DATASOURCE_URL: jdbc:mysql://db:3306/seckill_system?useSSL=false&serverTimezone=UTCSPRING_DATASOURCE_USERNAME: rootSPRING_DATASOURCE_PASSWORD: passworddepends_on:- db- redisorder-service:image: order-serviceports:- "8082:8080"environment:SPRING_DATASOURCE_URL: jdbc:mysql://db:3306/seckill_system?useSSL=false&serverTimezone=UTCSPRING_DATASOURCE_USERNAME: rootSPRING_DATASOURCE_PASSWORD: passworddepends_on:- db- redis- rabbitmqseckill-service:image: seckill-serviceports:- "8083:8080"environment:SPRING_DATASOURCE_URL: jdbc:mysql://db:3306/seckill_system?useSSL=false&serverTimezone=UTCSPRING_DATASOURCE_USERNAME: rootSPRING_DATASOURCE_PASSWORD: passworddepends_on:- db- redis- rabbitmqgateway-service:image: gateway-serviceports:- "8080:8080"depends_on:- product-service- order-service- seckill-servicedb:image: mysql:8.0environment:MYSQL_ROOT_PASSWORD: passwordMYSQL_DATABASE: seckill_systemvolumes:- db_data:/var/lib/mysqlredis:image: redis:latestrabbitmq:image: rabbitmq:managementvolumes:db_data:
启动所有服务:
bash
docker-compose up --build
3.9.4 使用 Kubernetes 进行生产部署
为了在生产环境中部署,我们可以使用 Kubernetes。首先,确保你已经安装了 Kubernetes 和 kubectl 工具。
3.9.4.1 创建 Kubernetes 部署文件
为每个微服务创建一个 Kubernetes 部署文件。这里以 Product Service
为例:
Yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: product-service
spec:replicas: 3selector:matchLabels:app: product-servicetemplate:metadata:labels:app: product-servicespec:containers:- name: product-serviceimage: product-service:latestports:- containerPort: 8080env:- name: SPRING_DATASOURCE_URLvalue: jdbc:mysql://mysql:3306/seckill_system?useSSL=false&serverTimezone=UTC- name: SPRING_DATASOURCE_USERNAMEvalue: root- name: SPRING_DATASOURCE_PASSWORDvalue: password
---
apiVersion: v1
kind: Service
metadata:name: product-service
spec:type: ClusterIPselector:app: product-serviceports:- protocol: TCPport: 80targetPort: 8080
为其他微服务创建类似的部署文件。
3.9.4.2 创建 ConfigMap 和 Secret
创建 ConfigMap 和 Secret 来管理配置和敏感信息。
Yaml
apiVersion: v1
kind: ConfigMap
metadata:name: database-config
data:spring.datasource.url: jdbc:mysql://mysql:3306/seckill_system?useSSL=false&serverTimezone=UTCspring.datasource.username: root---
apiVersion: v1
kind: Secret
metadata:name: database-secret
type: Opaque
data:spring.datasource.password: cGFzc3dvcmQ= # base64 encoded 'password'
3.9.4.3 创建 MySQL 和 Redis 的 StatefulSet 和 Headless Service
Yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:name: mysql
spec:serviceName: "mysql"replicas: 1selector:matchLabels:app: mysqltemplate:metadata:labels:app: mysqlspec:containers:- name: mysqlimage: mysql:8.0env:- name: MYSQL_ROOT_PASSWORDvalueFrom:secretKeyRef:name: database-secretkey: spring.datasource.password- name: MYSQL_DATABASEvalueFrom:configMapKeyRef:name: database-configkey: spring.datasource.databaseports:- containerPort: 3306volumeMounts:- name: mysql-persistent-storagemountPath: /var/lib/mysqlvolumeClaimTemplates:- metadata:name: mysql-persistent-storagespec:accessModes: [ "ReadWriteOnce" ]resources:requests:storage: 10Gi---
apiVersion: v1
kind: Service
metadata:name: mysql
spec:ports:- port: 3306clusterIP: Noneselector:app: mysql---
apiVersion: apps/v1
kind: StatefulSet
metadata:name: redis
spec:serviceName: "redis"replicas: 1selector:matchLabels:app: redistemplate:metadata:labels:app: redisspec:containers:- name: redisimage: redis:latestports:- containerPort: 6379volumeMounts:- name: redis-persistent-storagemountPath: /datavolumeClaimTemplates:- metadata:name: redis-persistent-storagespec:accessModes: [ "ReadWriteOnce" ]resources:requests:storage: 5Gi---
apiVersion: v1
kind: Service
metadata:name: redis
spec:ports:- port: 6379clusterIP: Noneselector:app: redis
3.9.4.4 创建 RabbitMQ 的 StatefulSet 和 Headless Service
Yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:name: rabbitmq
spec:serviceName: "rabbitmq"replicas: 1selector:matchLabels:app: rabbitmqtemplate:metadata:labels:app: rabbitmqspec:containers:- name: rabbitmqimage: rabbitmq:managementports:- containerPort: 5672- containerPort: 15672volumeMounts:- name: rabbitmq-persistent-storagemountPath: /var/lib/rabbitmqvolumeClaimTemplates:- metadata:name: rabbitmq-persistent-storagespec:accessModes: [ "ReadWriteOnce" ]resources:requests:storage: 5Gi---
apiVersion: v1
kind: Service
metadata:name: rabbitmq
spec:ports:- port: 5672- port: 15672clusterIP: Noneselector:app: rabbitmq
3.9.4.5 应用 Kubernetes 配置
将所有 YAML 文件保存到一个目录中,然后应用这些配置:
bash
kubectl apply -f .
4. 性能优化
4.1 数据库索引
确保数据库表上有适当的索引,以加速查询。例如,在 Product
表的 id
和 stock
字段上创建索引。
sql
CREATE INDEX idx_product_id ON product(id);
CREATE INDEX idx_product_stock ON product(stock);
4.2 分页查询
对于大量数据的查询,使用分页查询来减少每次查询的数据量。在 ProductService
中添加分页查询方法:
java
package com.seckillsystem.service;import com.seckillsystem.model.Product;
import com.seckillsystem.repository.ProductRepository;
import org.redisson.api.RedissonClient;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;import java.util.Optional;@Service
public class ProductService {@Autowiredprivate ProductRepository productRepository;@Autowiredprivate RedissonClient redissonClient;public Optional<Product> getProductById(Long id) {return productRepository.findById(id);}public boolean reduceStock(Long productId) {RLock lock = redissonClient.getLock("product:" + productId + ":lock");try {if (lock.tryLock()) {Product product = productRepository.findById(productId).orElse(null);if (product != null && product.getStock() > 0) {product.setStock(product.getStock() - 1);productRepository.save(product);return true;}}} finally {if (lock.isHeldByCurrentThread()) {lock.unlock();}}return false;}public Page<Product> getAllProducts(Pageable pageable) {return productRepository.findAll(pageable);}
}
4.3 响应式编程
使用 Spring WebFlux 进行响应式编程,提高非阻塞 I/O 的性能。首先,将项目转换为 Spring WebFlux 项目。
在 pom.xml
中添加 Spring WebFlux 依赖:
xml
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
修改 ProductController
使用 WebFlux:
java
package com.seckillsystem.controller;import com.seckillsystem.model.Product;
import com.seckillsystem.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;@RestController
@RequestMapping("/api/products")
public class ProductController {@Autowiredprivate ProductService productService;@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)public Flux<Product> getAllProducts(@RequestParam int page, @RequestParam int size) {return Flux.fromIterable(productService.getAllProducts(PageRequest.of(page, size)).getContent());}@GetMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE)public Mono<Product> getProductById(@PathVariable Long id) {return Mono.justOrEmpty(productService.getProductById(id));}@PostMapping(value = "/seckill/{productId}/{userId}/{quantity}", produces = MediaType.TEXT_PLAIN_VALUE)public Mono<String> seckill(@PathVariable Long productId, @PathVariable Long userId, @PathVariable Integer quantity) {if (productService.reduceStock(productId)) {Order order = new Order();order.setProductId(productId);order.setUserId(userId);order.setQuantity(quantity);productService.createOrder(order);return Mono.just("Seckill successful!");} else {return Mono.just("Seckill failed! Out of stock.");}}
}
4.4 日志监控
使用 ELK Stack (Elasticsearch, Logstash, Kibana) 或 Prometheus + Grafana 进行日志收集和监控。
4.4.1 配置 ELK Stack
在 Kubernetes 中部署 Elasticsearch、Logstash 和 Kibana。
Elasticsearch Deployment YAML:
Yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:name: elasticsearch
spec:serviceName: "elasticsearch"replicas: 1selector:matchLabels:app: elasticsearchtemplate:metadata:labels:app: elasticsearchspec:containers:- name: elasticsearchimage: docker.elastic.co/elasticsearch/elasticsearch:7.10.1ports:- containerPort: 9200- containerPort: 9300env:- name: discovery.typevalue: single-nodevolumeMounts:- name: elasticsearch-persistent-storagemountPath: /usr/share/elasticsearch/datavolumeClaimTemplates:- metadata:name: elasticsearch-persistent-storagespec:accessModes: [ "ReadWriteOnce" ]resources:requests:storage: 10Gi---
apiVersion: v1
kind: Service
metadata:name: elasticsearch
spec:ports:- port: 9200clusterIP: Noneselector:app: elasticsearch
Logstash Deployment YAML:
Yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: logstash
spec:replicas: 1selector:matchLabels:app: logstashtemplate:metadata:labels:app: logstashspec:containers:- name: logstashimage: docker.elastic.co/logstash/logstash:7.10.1ports:- containerPort: 5044volumeMounts:- name: logstash-configmountPath: /usr/share/logstash/pipeline/volumes:- name: logstash-configconfigMap:name: logstash-config
---
apiVersion: v1
kind: ConfigMap
metadata:name: logstash-config
data:logstash.conf: |input {beats {port => 5044}}output {elasticsearch {hosts => ["http://elasticsearch:9200"]index => "logstash-%{+YYYY.MM.dd}"}stdout { codec => rubydebug }}
Kibana Deployment YAML:
Yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: kibana
spec:replicas: 1selector:matchLabels:app: kibanatemplate:metadata:labels:app: kibanaspec:containers:- name: kibanaimage: docker.elastic.co/kibana/kibana:7.10.1ports:- containerPort: 5601env:- name: ELASTICSEARCH_HOSTSvalue: http://elasticsearch:9200---
apiVersion: v1
kind: Service
metadata:name: kibana
spec:ports:- port: 5601type: LoadBalancerselector:app: kibana
4.4.2 配置 Prometheus and Grafana
在 Kubernetes 中部署 Prometheus 和 Grafana。
Prometheus Deployment YAML:
Yaml
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:name: prometheus
spec:serviceAccountName: prometheusserviceMonitorSelector:matchLabels:team: frontendruleSelector:matchLabels:role: alert-rulesteam: frontendalertingRulesNamespaceSelector: {}alertingRulesSelector: {}enableAdminAPI: falseexternalUrl: ""routePrefix: /webRoutePrefix: /---
apiVersion: v1
kind: Service
metadata:name: prometheus
spec:ports:- name: webport: 9090targetPort: webselector:app: prometheus-servertype: LoadBalancer---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:name: prometheus-clusterrole-binding
roleRef:apiGroup: rbac.authorization.k8s.iokind: ClusterRolename: prometheus-clusterrole
subjects:
- kind: ServiceAccountname: prometheusnamespace: default---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:name: prometheus-clusterrole
rules:
- apiGroups: [""]resources:- nodes- services- endpoints- podsverbs: ["get", "list", "watch"]
- apiGroups: [""]resources:- configmapsverbs: ["get"]
- nonResourceURLs: ["/metrics"]verbs: ["get"]---
apiVersion: v1
kind: ServiceAccount
metadata:name: prometheusnamespace: default
Grafana Deployment YAML:
Yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: grafana
spec:replicas: 1selector:matchLabels:app: grafanatemplate:metadata:labels:app: grafanaspec:containers:- name: grafanaimage: grafana/grafana:latestports:- containerPort: 3000env:- name: GF_SECURITY_ADMIN_PASSWORDvalue: admin---
apiVersion: v1
kind: Service
metadata:name: grafana
spec:ports:- port: 3000type: LoadBalancerselector:app: grafana
4.5 消息队列
使用 RabbitMQ 处理订单创建等耗时操作,避免阻塞主线程。这部分已经在前面的章节中详细说明了。
5. 测试
编写单元测试和集成测试来确保代码质量和稳定性。
5.1 单元测试
使用 JUnit 和 Mockito 进行单元测试。以下是一个简单的示例:
java
package com.seckillsystem.service;import com.seckillsystem.model.Product;
import com.seckillsystem.repository.ProductRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.redisson.api.RedissonClient;
import org.redisson.api.RLock;import java.util.Optional;import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.*;class ProductServiceTest {@Mockprivate ProductRepository productRepository;@Mockprivate RedissonClient redissonClient;@Mockprivate RLock rLock;@InjectMocksprivate ProductService productService;@BeforeEachvoid setUp() {MockitoAnnotations.openMocks(this);when(redissonClient.getLock(anyString())).thenReturn(rLock);}@Testvoid testReduceStock_Success() {Product product = new Product();product.setId(1L);product.setStock(10);when(productRepository.findById(1L)).thenReturn(Optional.of(product));assertTrue(productService.reduceStock(1L));verify(productRepository, times(1)).findById(1L);verify(productRepository, times(1)).save(product);verify(rLock, times(1)).tryLock();verify(rLock, times(1)).unlock();}@Testvoid testReduceStock_OutOfStock() {Product product = new Product();product.setId(1L);product.setStock(0);when(productRepository.findById(1L)).thenReturn(Optional.of(product));assertFalse(productService.reduceStock(1L));verify(productRepository, times(1)).findById(1L);verify(productRepository, never()).save(product);verify(rLock, times(1)).tryLock();verify(rLock, times(1)).unlock();}@Testvoid testReduceStock_ProductNotFound() {when(productRepository.findById(1L)).thenReturn(Optional.empty());assertFalse(productService.reduceStock(1L));verify(productRepository, times(1)).findById(1L);verify(productRepository, never()).save(any(Product.class));verify(rLock, times(1)).tryLock();verify(rLock, times(1)).unlock();}
}
5.2 集成测试
使用 Spring Boot Test 进行集成测试。以下是一个简单的示例:
java
package com.seckillsystem.service;import com.seckillsystem.SeckillSystemApplication;
import com.seckillsystem.model.Product;
import com.seckillsystem.repository.ProductRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;@SpringBootTest(classes = SeckillSystemApplication.class)
@Transactional
class ProductServiceIntegrationTest {@Autowiredprivate ProductService productService;@Autowiredprivate ProductRepository productRepository;@BeforeEachvoid setUp() {Product product = new Product();product.setName("Sample Product");product.setPrice(100.0);product.setStock(10);productRepository.save(product);}@Testvoid testReduceStock_Success() {Long productId = productRepository.findByName("Sample Product").getId();assertTrue(productService.reduceStock(productId));Product updatedProduct = productRepository.findById(productId).orElseThrow(() -> new RuntimeException("Product not found"));assertEquals(9, updatedProduct.getStock());}@Testvoid testReduceStock_OutOfStock() {Long productId = productRepository.findByName("Sample Product").getId();for (int i = 0; i < 10; i++) {assertTrue(productService.reduceStock(productId));}assertFalse(productService.reduceStock(productId));Product updatedProduct = productRepository.findById(productId).orElseThrow(() -> new RuntimeException("Product not found"));assertEquals(0, updatedProduct.getStock());}
}
6.1 添加限流
注册拦截器:
java
package com.seckillsystem.config;import com.seckillsystem.interceptor.RateLimitingInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate RateLimitingInterceptor rateLimitingInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(rateLimitingInterceptor).addPathPatterns("/api/products/seckill/**");}
}
6.2 使用消息队列处理订单
使用 RabbitMQ 处理订单创建等耗时操作,避免阻塞主线程。
在 pom.xml
中添加 RabbitMQ 依赖:
xml
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
配置 RabbitMQ 连接:
properties
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
创建消息队列和交换机配置:
java
package com.seckillsystem.config;import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RabbitMqConfig {public static final String ORDER_QUEUE = "order_queue";@Beanpublic Queue orderQueue() {return new Queue(ORDER_QUEUE, true);}
}
修改 OrderService
以支持消息队列:
java
package com.seckillsystem.service;import com.seckillsystem.model.Order;
import com.seckillsystem.repository.OrderRepository;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class OrderService {@Autowiredprivate OrderRepository orderRepository;@Autowiredprivate RabbitTemplate rabbitTemplate;public void createOrder(Order order) {rabbitTemplate.convertAndSend(RabbitMqConfig.ORDER_QUEUE, order);}public Order saveOrder(Order order) {return orderRepository.save(order);}
}
创建消息监听器来处理订单:
java
package com.seckillsystem.listener;import com.seckillsystem.model.Order;
import com.seckillsystem.service.OrderService;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
public class OrderListener {@Autowiredprivate OrderService orderService;@RabbitListener(queues = RabbitMqConfig.ORDER_QUEUE)public void processOrder(Order order) {orderService.saveOrder(order);}
}
8. 总结
通过以上步骤,我们成功搭建了一个基于微服务架构的高并发秒杀系统后端,并实现了容器化和部署。以下是整个架构的概览图:
这个架构展示了各个组件之间的关系和交互。你可以根据实际需求进一步扩展和完善这个架构。
相关文章:
微服务实现高并发 秒杀系统,前后端实现
一、前端实现 前端项目初始化 首先,我们需要创建一个新的 Vue 3 项目。你可以使用 Vue CLI 来快速搭建项目。 安装 Vue CLI(如果尚未安装) bash npm install -g vue/cli 创建 Vue 项目 bash vue create seckill-frontend cd seckill-f…...
Eureka缓存机制
一、Eureka的CAP特性 Eureka是一个AP系统,它优先保证可用性(A)和分区容错性(P),而不保证强一致性(C)。这种设计使得Eureka在分布式系统中能够应对各种故障和分区情况,保…...
PHP语言的学习路线
PHP语言的学习路线 PHP(Hypertext Preprocessor)是一种广泛使用的开源服务器端脚本语言,尤其适用于Web开发。由于其易学易用、功能强大,PHP成为了许多动态网站和Web应用程序开发的首选语言。随着Web3.0和云计算的兴起,…...
python学opencv|读取图像(二十八)使用cv2.warpAffine()函数平移图像
【1】引言 前序已经对图像操作进行了广泛的学习,包括读取、放大缩小,改变BGR通道值等,相关链接包括且不限于: python学opencv|读取图像-CSDN博客 python学opencv|读取图像(三)放大和缩小图像_python(1)使…...
[Linux]Mysql9.0.1服务端脱机安装配置教程(redhat)
前言 本教程适用于在yum源不可用的LInux主机上安装Mysql的场景。 以redhat系主机做操作示例,debian系主机可参照步骤,将对应的rpm -ivh命令换成dpkg -i。 1. 官网下载安装包 https://dev.mysql.com/downloads/mysql/ 1.1 版本分类 MySQL Enterprise…...
个人 ALL IN ONE 方案搭建方案分享(从硬件到软件)及内网穿透方案
这里只做大概方案分享,每个虚拟机的部署细节滤过。 个人 ALL IN ONE 方案搭建方案分享 本指南将详细介绍如何基于现有硬件搭建一体化家庭/个人服务器解决方案,涵盖从软硬件配置、系统安装到功能实现以及性能优化的全过程。实现集 软路由、旁路由、NAS 网…...
TrustRAG:增强RAG系统鲁棒性与可信度的创新框架
在人工智能飞速发展的今天,大语言模型(LLMs)凭借其强大的语言处理能力在诸多领域大放异彩。检索增强生成(RAG)系统(面向企业RAG(Retrieval Augmented Generation)系统的多维检索框架…...
使用证件照制作软件的常见问题及解决方案
在数字化时代,证件照的制作变得越来越简单。借助各种证件照制作软件,我们可以轻松在家中制作出符合要求的证件照。然而,用户在使用这些软件时,可能会遇到一些常见问题。为了帮助您顺利制作出满意的证件照,我们整理了一…...
通过gradle发布aar或jar携带sources-jar到maven nexus
找了很久,没有找到满意的。终于找到一个好的办法。 gradle7.x适用。比以前的写法简洁。 发布传统的jar工程 比如okhttp,fastjson等项目,纯java工程。 直接创建新文件publish.gradle: apply plugin: maven-publishProperties properties …...
SAP推出云端ERP解决方案,加速零售行业数字化转型
2025年1月9日,SAP发布了一款专为零售行业设计的云端ERP行业解决方案——S/4HANA Cloud Public Edition,进一步推动企业向云端迁移。这款解决方案旨在集中运营数据,整合财务、采购和商品管理流程,以帮助零售企业优化运营效率。 核…...
RK3568 Android 13 内置搜狗输入法小计
问:为什么写? 答:网上搜出来的都试过了,不行!下面直接上代码和注意事项! 首先到这个目录(/RK3568/Rockchip_Android13_SDK_Release/device/rockchip/rk356x/tl3568_evm/preinstall)…...
微服务-Nacos(注册中心)
Nacos Nacos可以看作注册中心配置中心,比Eureka更加强大。 注册中心 在父工程中引入SpringCloudAlibaba的版本依赖 <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId&g…...
【数据结构:前缀树Trie】
目录 前言前缀树介绍和应用一、前缀树的定义前缀树的问题和思考前缀树的映射思想前缀树三大性质 二.前缀树节点结构三. 前缀树接口介绍和实现四个接口API1. insert(String word)2. search(String word)3. startsWith(String pre)4. delete(String word) API实现1. 查询操作sear…...
如何让QPS提升20倍
一、什么是QPS QPS,全称Queries Per Second,即每秒查询率,是用于衡量信息检索系统(例如搜索引擎或数据库)或请求-响应系统(如Web服务器)每秒能够处理的请求数或查询次数的一个性能指标。以下是…...
时间复杂度简介
定义 时间复杂度是用来衡量算法运行时间随着输入规模增长而增长的量级。简单来说,它描述了算法执行时间与数据规模之间的关系。我们通常用大O符号( O O O)来表示时间复杂度。例如,对于一个简单的加法运算,它的执行时间…...
记一次sealos部署k8s集群之delete了第一台master如何恢复
记一次sealos部署k8s集群之delete了第一台master如何恢复 一、背景描述 使用sealos部署了一套K8S集群 master信息:172.27.100.1、172.27.100.2、172.27.100.3 node信息:172.27.100.4、172.27.100.5 sealos安装在172.27.100.1节点,根目录下/root/.sealos/文件还在! [root…...
【json】
JSON JSON是一种轻量级的,按照指定的格式去组织和封装数据的数据交互格式。 本质上是一个带有特定格式的字符串(py打印json时认定为str类型) 在各个编程语言中流通的数据格式,负责不同编程语言中的数据传递和交互,类似于计算机普通话 python与json关系及相互转换…...
TypeScript语言的并发编程
TypeScript语言的并发编程 引言 随着现代应用程序的复杂性不断增加,性能和用户体验的重要性显得尤为突出。在这种背景下,并发编程应运而生,成为提升应用程序效率的重要手段。在JavaScript及其超集TypeScript中,尽管语言本身是单…...
左值引用(Lvalue Reference)和右值引用(Rvalue Reference)详解
左值引用(Lvalue Reference)和右值引用(Rvalue Reference)详解 文章目录 左值引用(Lvalue Reference)和右值引用(Rvalue Reference)详解1. 什么是左值和右值?左值&#x…...
音视频入门基础:RTP专题(1)——RTP官方文档下载
一、引言 实时传输协议(Real-time Transport Protocol,简写RTP)是一个网络传输协议,由IETF的多媒体传输工作小组1996年在《RFC 1889》中公布的。 RTP作为因特网标准在《RFC 3550》有详细说明。而《RFC 3551》详细描述了使用最小…...
【Flutter】使用ScrollController配合EasyRefresh实现列表预加载:在还未滑动到底部时加载下一页数据
需求/背景 在我们的业务场景中,列表的加载使用easy_refresh组件: https://pub.dev/packages/easy_refresh 大概效果是往上滑动到一定的offset会触发一个上滑加载,可以触发一些网络请求拉取列表后面的数据来展示。 这种模式一般在一页翻完…...
js实现md5加密
要在JavaScript中实现MD5加密并截取特定位置的字符,你可以使用像crypto-js这样的库。首先,你需要确保你的项目中包含了crypto-js库。如果你是在浏览器环境中,可以通过CDN引入;如果是在Node.js环境中,可以通过npm安装。…...
[java基础-集合篇]LinkedList源码粗析
LinkedList 的数据结构 实现List、Deque 接口,基于 双向链表实现的列表。与基于数组的 ArrayList 不同,基于链表的LinkedList 允许在列表的任何位置快速地插入和删除元素。 Java中LinkedList实现了Deque,它提供了 add, offer, remove, poll, …...
【Rust自学】11.1. 编写和运行测试
喜欢的话别忘了点赞、收藏加关注哦,对接下来的教程有兴趣的可以关注专栏。谢谢喵!(・ω・) 11.1.1. 什么是测试 在Rust里一个测试就是一个函数,它被用于验证非测试代码的功能是否和预期一致。 在一个测试的函数体里通…...
移动端屏幕分辨率rem,less
谷歌模拟器:能直接看到移动端效果 屏幕分辨率 右键电脑桌面 ,点击显示设置 PC端是逻辑分辨率,移动端代码也是参考逻辑分辨率 网页端宽度和逻辑分辨率尺寸相同 手机屏幕尺寸不同,网页宽度均为 100% 所以就需要添加视口标签&#x…...
rk3568 , buildroot , qt ,使用sqlite, 动态库, 静态库
问题说明: 客户反馈 ,buildroot 系统 ,使用qt 使用sqlite ,有报错,无法使用sqlite. 测试情况说明: 我自己测试,发现, buildroot 自己默认就是 使能了 sqlite 的。 是否解决说明&…...
web-app uniapp监测屏幕大小的变化对数组一行展示数据作相应处理
web-app uniapp监测屏幕大小的变化对数组一行展示数据作相应处理 1.uni.getSystemInfoSync().screenWidth; 获取屏幕宽度 2.uni.onWindowResize() 实时监测屏幕宽度变化 3.根据宽度的大小拿到每行要展示的数量itemsPerRow 4.为了确保样式能够根据 items…...
Airflow:TimeSensor感知时间条件
在数据管道工作流中,任务可能需要在特定的时间执行,或者在继续之前等待一定的时间。为了满足这些需求,Apache Airflow提供了TimeSensor,这是一种内置Sensor,可以监控当前时间,并在达到指定时间时触发后续任…...
使用Python和Neo4j驱动程序来实现小规模数据的CSV导入
要将CSV数据导入到Neo4j数据库中,你可以使用Neo4j提供的工具,比如neo4j-admin import命令(适用于大规模数据导入),或者使用Python的Neo4j驱动程序通过Cypher查询逐行插入数据(适用于小规模数据导入…...
网络安全测评技术与标准
网络安全测评概况 网络安全测评是网络信息系统和IT技术产品的安全质量保障。本节主要阐述网络安全测评的概念,给出网络安全测评的发展状况。 18.1.1 网络安全测评概念 网络安全测评是指参照一定的标准规范要求,通过一系列的技术和管理方法,获…...
某漫画网站JS逆向反混淆流程分析
文章目录 1. 写在前面1. 接口分析2. 反混淆分析 【🏠作者主页】:吴秋霖 【💼作者介绍】:擅长爬虫与JS加密逆向分析!Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致力于Pyth…...
如何获取文件的MIME类型
文章目录 1. 概念介绍2. 方法与类型2.1 使用方法2.2 常见类型3. 示例代码4. 内容总结我们在上一章回中介绍了"如何加载本地图片"相关的内容,本章回中将介绍如何获取文件类型.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 我们在本章回中提到的文件类型是指MI…...
Three.js 基础概念:构建3D世界的核心要素
文章目录 前言一、场景(Scene)二、相机(Camera)三、渲染器(Renderer)四、物体(Object)五、材质(Material)六、几何体(Geometry)七、光…...
Linux web服务器
Linux 作为 Web 服务器操作系统 安装 Web 服务器软件(以 Apache 为例) 步骤一:更新系统软件包列表 在 CentOS 系统中,使用命令 yum update -y 这个命令会连接到 CentOS 的软件包仓库,检查所有已安装软件包是否有更…...
Linux 下信号的保存和处理
信号的几个状态 信号抵达: 当接收到的信号被处理时, 此时就成为信号的抵达信号的未决: 从信号的产生到信号抵达这个时间段之间, 称为信号未决信号阻塞: 当进程设置了某个信号为阻塞后, 这个进程就不会在接收到这个信号信号忽略: 将信号设置为忽略后, 接收到这个信号, 对这个信…...
宝塔安装教程,bt怎么安装 linux
Centos安装脚本 yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh 37a09b35 Ubuntu/Deepin安装脚本 wget -O install.sh http://download.bt.cn/install/install-ubuntu_6.0.sh && sudo b…...
java通过ocr实现识别pdf中的文字
需求:识别pdf文件中的中文 根据github项目mymonstercat 改造,先将pdf文件转为png文件存于临时文件夹,然后通过RapidOcr转为文字,最后删除临时文件夹 1、引入依赖 <dependency><groupId>org.apache.pdfbox</groupId><artifactId&g…...
基于SpringBoot的养老院管理系统
作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏:…...
阿里云发现后门webshell,怎么处理,怎么解决?
当收到如下阿里云通知邮件时,大部分管理员都会心里一惊吧!出现Webshell,大概是网站被入侵了。 尊敬的 xxxaliyun.com: 云盾云安全中心检测到您的服务器:47.108.x.xx(xx机)出现了紧急安全事件…...
韩顺平老师Linux学习笔记【持续更新...】
1、课程内容 1.1、课程大纲 1.2、Linux使用在哪些地方 Linux运维工程师Linux嵌入式工程师Linux下开发项目:JavaEE、大数据、Python、PHP、C/C、Go 1.3、Linux的应用领域 个人桌面领域服务器领域(最强领域)嵌入式领域 2、Linux入门 2.1、…...
Cognitive architecture 又是个什么东东?
自Langchain: https://blog.langchain.dev/what-is-a-cognitive-architecture/ https://en.wikipedia.org/wiki/Cognitive_architecture 定义 A cognitive architecture refers to both a theory about the structure of the human mind and to a computational…...
【css】浏览器强制设置元素状态(hover|focus……)
直接上步骤: 打开浏览器控制台 → 找到样式选项 → 找到:hov选项 → 点击:hov选项,会展开【设置元素状态】。 只要选中就会展示出自己写在css里面的该种状态下的样式了。...
leetcode热题100——NO.160相交链表——JAVA
一、题目描述 题目:给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。题目数据 保证 整个链式结构中不存在环。 注意,函数返回结果后,链表必…...
基于Media+Unity的手部位姿三维位姿估计
使用mediapipe Unity 手部位姿三维位姿估计 参考文章 基于Mediapipe的姿势识别并同步到Unity人体模型中 MediapipeUnity3d实现虚拟手_unity mediapipe-CSDN博客 需求 我的需求就是快速、准确的跟踪手部位姿并实现一个三维显示。 主要思路 搭建mdeiapipe系统,…...
cJson——序列化格式json和protobuf对比
cJson——序列化格式json和protobuf对比 1. 更小的消息体积2. 更快的序列化与反序列化速度3. 类型安全4. 向后和向前兼容性5. 更低的带宽消耗6. 高效的编码方式7. 易于跨语言支持8. 支持复杂的数据结构9. 更好的支持大型数据交换总结 Protocol Buffers (Protobuf) 和 JSON 都是…...
STM32F1学习——ADC模数转换器
一、ADC模数转换器 ADC的全称 Analog-Digital Converter 模拟-数字转换器,他可以用来将引脚上连续变换的模拟电压转换为内存中存储的数字变量。 ADC有两个重要指标,分辨率和频率。 STM32的ADC是 12位 逐次逼近型,1us转换时间,也就…...
2025-1-10-sklearn学习(36、37) 数据集转换-无监督降维+随机投影 沙上并禽池上暝。云破月来花弄影。
文章目录 sklearn学习(36、37) 数据集转换-无监督降维随机投影sklearn学习(36) 数据集转换-无监督降维36.1 PCA: 主成份分析36.2 随机投影36.3 特征聚集 sklearn学习(37) 数据集转换-随机投影37.1 Johnson-Lindenstrauss 辅助定理37.2 高斯随机投影37.3 稀疏随机矩阵 sklearn学…...
Linux之线程池与单例模式
目录 线程池 线程池代码 单例模式 饿汉模式单例模式 懒汉模式单例模式 在前几期,我们已经学习了多线程的创建和控制,学习了多线程中的同步和互斥,学习了多线程中的条件变量和信号量,基于此我们实现了基于阻塞队列和基于环形队…...
LabVIEW调用不定长数组 DLL数组
在使用 LabVIEW 调用 DLL 库函数时,如果函数中的结构体包含不定长数组,直接通过 调用库函数节点(Call Library Function Node) 调用通常会遇到问题。这是因为 LabVIEW 需要与 DLL 中的数据结构完全匹配,而包含不定长数…...
计算机的错误计算(二百零七)
摘要 利用两个数学大模型计算 arccot(0.125664e2)的值,结果保留16位有效数字。 实验表明,它们的输出中分别仅含有3位和1位正确数字。 例1. 计算 arccot(0.125664e2)的值,结果保留16位有效数字。 下面是与一个数学解题器的对话。 以上为与…...