RabbitMQ: 基于 Direct Exchange 的微服务通信与数模设计

COT Buck和普通Buck的区别 传统的电流模控制的调制原理,由时钟脉冲信号 clk 的上升沿触发开始一个新的开关周期,d 由低变高,主开关闭合,流过它的电流和电感电流相等,并以固定斜率逐渐增大,直至 iL *Ri 与斜坡补偿信号 se 的和等于控制信号 vc;此时,比较器的输出电平由低变高,导通时间产生器被触发,其输出 d 由低变高,并产生一个固定的导通时间 Ton;然后 PWM 比较器的输出由低变高,导通时间产生器被触发,主开关闭合,电感电流逐渐增大,直到导通时间产生器计满固定的时间 Ton,d 变为低电平,主开关断开,周期结束。 阅读详情

微服务架构设计与开发准备


  • Direct Exchange(直连交换机)通过 Routing Key 精确路由消息:
    • 当消息的 Routing Key 与队列绑定的 Binding Key 完全匹配时,消息会被投递到对应队列
  • 例如:
    • 订单微服务发送消息至餐厅微服务时,需指定 Routing Key 为 restaurant_route
    • 骑手微服务监听队列需绑定相同 Binding Key

关键术语:

  • Routing Key:消息的路由标识(如 order_created)
  • Binding Key:队列与交换机绑定的匹配规则(需与 Routing Key 一致)

核心目标:使用 RabbitMQ Direct Exchange 实现订单、餐厅、骑手微服务的协同通信

业务流程:用户下单 → 商家校验商品 → 分配骑手 → 状态流转(创建中 → 商户确认 → 骑手确认 → 结
算完成)

1 ) 微服务拆分

  • 订单服务:核心业务服务,处理用户下单、订单状态查询等 RESTful 接口
    • 新建订单 POST /orders、查询订单 GET /orders/{id}
  • 餐厅服务:校验商品库存、接单状态管理
    • 职责:校验商品库存、处理订单确认
  • 骑手服务:分配骑手、更新配送状态
    • 关键点:Direct Exchange 通过 routingKey 与 bindingKey 精确匹配实现消息路由

2 ) 业务流程关键阶段:

用户下单
订单微服务创建订单
餐厅微服务校验商品
骑手微服务分配骑手

3 ) 消息路由机制

routingKey=order.create
bindingKey=order.create
bindingKey=order.dispatch
订单服务
Direct Exchange
餐厅服务队列
骑手服务队列

4 ) 环境配置:

安装 MySQL (Windows)
下载 MySQL Community Server (400MB+ 安装包) → 安装后任务栏出现 MySQL Notifier 图标

数据库初始化 (Navicat)
1. 新建连接:主机 localhost,端口 3306,用户/密码自定义
2. 创建数据库 `food_delivery`:
   - 字符集:utf8mb4
   - 排序规则:utf8mb4_general_ci
3. 执行建表 SQL(需提前准备商品表、商户表)

5 )数据表初始化

-- 商户表
CREATE TABLE `merchant` (
 `id` INT NOT NULL AUTO_INCREMENT,
 `name` VARCHAR(50) NOT NULL COMMENT '商户名称',
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 商品表
INSERT INTO `product` (`id`, `name`, `price`) 
VALUES (1, '珍珠奶茶', 15.00);

5 )NestJS 项目配置:

数据库连接配置(.env 文件):

DB_HOST=localhost
DB_PORT=3306
DB_USERNAME=root
DB_PASSWORD=your_password
DB_DATABASE=food_delivery
DB_SYNCHRONIZE=false  # 生产环境禁用自动同步

应用启动配置(app.module.ts):

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Order } from './order/order.entity';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: process.env.DB_HOST,
      port: parseInt(process.env.DB_PORT),
      username: process.env.DB_USERNAME,
      password: process.env.DB_PASSWORD,
      database: process.env.DB_DATABASE,
      entities: [Order], // 引入实体类
      synchronize: false, // 重要!生产环境需关闭
      extra: { 
        charset: 'utf8mb4',           // 修复字符集名称
        charset: 'utf8mb4_general_ci',
        timezone: '+08:00' 
      }
    }),
  ],
})
export class AppModule {}

注意:

  • 各微服务需监听不同端口(如订单服务 :3000,餐厅服务 :3001)
  • 金额字段使用 DECIMAL(10,2) 类型(避免浮点精度损失)

重点:

  • 服务端口需唯一(例:订单服务 3000,餐厅服务 3001,骑手服务 3002)
  • 时区配置 +08:00 避免时间戳错误

核心数据结构设计


采用分层模型确保数据一致性:

类型作用示例字段
VO (View Object)前端交互数据accountId, address, productId
DTO (Data Transfer Object)微服务间消息体orderId, status, price (BigDecimal)
PO (Persistent Object)数据库实体与表结构严格对应

1 ) VO (前端请求结构)

// order-create.vo.ts
export class OrderCreateVO {
  accountId: number;   // 用户ID
  address: string;     // 配送地址
  productId: number;   // 产品ID
}

2 ) DTO (消息传输结构)

// order-message.dto.ts
import { OrderStatus } from '../enum/order-status.enum';

export class OrderMessageDTO {
  orderId: number;         // 订单ID
  status: OrderStatus;     // 订单状态(枚举)
  price: number;           // 价格(避免浮点型,用整数分存储)
  deliverymanId?: number;  // 骑手ID(可选)
  settlementId?: number;   // 结算ID
  pointsAwarded?: number;  // 积分奖励
  isConfirmed?: boolean;   // 确认状态(必须为包装类,允许null)
}
// order-message.dto.ts
export class OrderMessageDTO {
  orderId: number;                // 订单ID
  status: OrderStatus;            // 订单状态(使用枚举)
  price: number;                  // 订单金额(实际应用应使用 Decimal)
  deliverymanId?: number;         // 骑手ID(可为空)
  productId: number;              // 产品ID
  userId: number;                 // 用户ID
  settlementId?: number;          // 结算ID
  rewardPoints?: number;          // 积分奖励数量
  isConfirmed: boolean;           // 确认状态(必须为包装类型 boolean)
}

3 )订单状态枚举

// order-status.enum.ts
export enum OrderStatus {
  CREATING = 'CREATING',              // 创建中
  RESTAURANT_CONFIRMED = 'RESTAURANT_CONFIRMED',  // 餐厅已确认
  DELIVERYMAN_CONFIRMED = 'DELIVERYMAN_CONFIRMED',// 骑手已确认
  SETTLEMENT_CONFIRMED = 'SETTLEMENT_CONFIRMED',  // 结算完成
  COMPLETED = 'COMPLETED',            // 订单完成
  FAILED = 'FAILED'                   // 订单失败
}

4 )PO (数据库实体)

// order.entity.ts
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
import { OrderStatus } from '../enum/order-status.enum';

@Entity()
export class Order {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ type: 'enum', enum: OrderStatus })
  status: OrderStatus;

  @Column()
  accountId: number;

  @Column({ type: 'decimal', precision: 10, scale: 2 })
  price: number;

  @Column({ type: 'timestamp' })
  createdAt: Date;
}

关键设计原则:

  • 金额存储:使用 decimal 类型(或整数分)避免浮点精度问题
  • 枚举映射:数据库用 ENUM 或 VARCHAR 存储状态字符串,代码层强类型校验
  • 字段命名:数据库下划线分隔(account_id),代码驼峰命名(accountId)
  • 空值处理:DTO 中可选字段使用 ?(如 deliverymanId?)

工程示例:1


前置 RabbitMQ 配置命令:

创建 Direct Exchange
rabbitmqadmin declare exchange name=order_exchange type=direct durable=true arguments='{"x-message-ttl":60000}'

创建队列并绑定 Routing Key
rabbitmqadmin declare queue name=restaurant_queue durable=true
rabbitmqadmin declare queue name=deliveryman_queue durable=true
rabbitmqadmin declare binding source=order_exchange destination=restaurant_queue routing_key=restaurant
rabbitmqadmin declare binding source=order_exchange destination=deliveryman_queue routing_key=deliveryman

1 ) 方案 1:基础 Direct Exchange 通信

// order.service.ts
import { Injectable } from '@nestjs/common';
import { RabbitMQService } from '@golevelup/nestjs-rabbitmq';
import { OrderMessageDTO } from './dto/order-message.dto';

@Injectable()
export class OrderService {
  constructor(private readonly rabbitmqService: RabbitMQService) {}

  async notifyRestaurant(order: OrderMessageDTO) {
    await this.rabbitmqService.publish('order_exchange', 'restaurant', {
      ...order,
      status: OrderStatus.RESTAURANT_CONFIRMED,
    });
  }
}

// restaurant.consumer.ts
import { RabbitSubscribe } from '@golevelup/nestjs-rabbitmq';

@Controller()
export class RestaurantConsumer {
  @RabbitSubscribe({
    exchange: 'order_exchange',
    routingKey: 'restaurant',
    queue: 'restaurant_queue',
  })
  handleOrderEvent(message: OrderMessageDTO) {
    console.log('餐厅收到订单:', message.orderId);
    // 业务逻辑:校验商品库存
  }
}

2 ) 方案 2:双向确认机制(RPC 模式)

// 订单服务发送带回调的消息
async requestDeliveryman(order: OrderMessageDTO) {
  const response = await this.rabbitmqService.request({
    exchange: 'order_exchange',
    routingKey: 'deliveryman',
    payload: order,
  });
  console.log('骑手分配结果:', response);
}

// 骑手服务处理并回复
@RabbitSubscribe({
  exchange: 'order_exchange',
  routingKey: 'deliveryman',
  queue: 'deliveryman_rpc_queue',
})
async assignDeliveryman(message: OrderMessageDTO) {
  const assignedId = Math.floor(Math.random() * 100); // 模拟分配骑手
  return { success: true, deliverymanId: assignedId }; // 自动回传结果
}

3 ) 方案 3:死信队列(DLX)保障可靠性

// 创建死信交换机和队列
rabbitmqadmin declare exchange name=dlx_exchange type=direct
rabbitmqadmin declare queue name=dead_letter_queue durable=true
rabbitmqadmin declare binding source=dlx_exchange destination=dead_letter_queue routing_key=dead_letter

// 订单队列绑定 DLX
rabbitmqadmin declare queue name=order_queue durable=true arguments='{"x-dead-letter-exchange":"dlx_exchange", "x-dead-letter-routing-key":"dead_letter"}'

// NestJS 消费端配置
@RabbitSubscribe({
  exchange: 'order_exchange',
  routingKey: 'order',
  queue: 'order_queue',
  allowNonJsonMessages: true,
  queueOptions: { deadLetterExchange: 'dlx_exchange' },
})
async processOrder(message: OrderMessageDTO) {
  if (message.status === OrderStatus.FAILED) {
    throw new Error('触发死信'); // 异常消息自动转入死信队列
  }
}

工程示例:2


1 ) RabbitMQ 配置与连接

安装依赖:

npm install @nestjs/microservices amqplib

RabbitMQ 连接配置(rabbitmq.config.ts):

import { RabbitMQConfig } from '@nestjs/microservices';

export const rabbitmqConfig: RabbitMQConfig = {
  transport: Transport.RMQ,
  options: {
    urls: ['amqp://localhost:5672'],
    queue: 'order_queue',
    queueOptions: {
      durable: true, // 持久化队列(服务重启后消息不丢失)
    },
    exchange: 'direct_exchange',
    exchangeType: 'direct',
  },
};

2 )消息生产者(订单微服务)

// order.service.ts
import { Inject, Injectable } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';
import { OrderMessageDTO } from './dto/order-message.dto';

@Injectable()
export class OrderService {
  constructor(
    @Inject('RABBITMQ_SERVICE') private readonly client: ClientProxy,
  ) {}

  async createOrder(createOrderDto: OrderCreateVO) {
    // 1. 创建订单(数据库操作)
    const order = await this.orderRepository.save(createOrderDto);

    // 2. 发送消息至餐厅微服务
    const message: OrderMessageDTO = {
      orderId: order.id,
      status: OrderStatus.CREATING,
      productId: createOrderDto.productId,
      userId: createOrderDto.accountId,
      isConfirmed: false,
    };
    this.client.emit('restaurant_route', message); // Routing Key = restaurant_route
  }
}

3 )消息消费者(餐厅微服务)

// restaurant.controller.ts
import { Controller } from '@nestjs/common';
import { EventPattern, Payload } from '@nestjs/microservices';
import { OrderMessageDTO } from 'shared-dtos';

@Controller()
export class RestaurantController {
  @EventPattern('restaurant_route') // 监听指定 Routing Key
  async handleOrderEvent(@Payload() data: OrderMessageDTO) {
    // 1. 校验商品库存
    const isAvailable = await this.checkProductStock(data.productId);

    // 2. 更新订单状态
    if (isAvailable) {
      await this.updateOrderStatus(data.orderId, OrderStatus.RESTAURANT_CONFIRMED);
      // 通知骑手微服务
      this.client.emit('delivery_route', { ...data, status: OrderStatus.RESTAURANT_CONFIRMED });
    }
  }

  private async checkProductStock(productId: number): Promise<boolean> {
    // 数据库查询逻辑
  }
}

4 )RabbitMQ 管理命令示例

创建 Direct Exchange
rabbitmqadmin declare exchange name=direct_exchange type=direct durable=true

创建队列并绑定 Exchange
rabbitmqadmin declare queue name=restaurant_queue durable=true
rabbitmqadmin declare binding source=direct_exchange destination=restaurant_queue routing_key=restaurant_route

5 )容错与扩展设计

方案适用场景实现方式
消息重试临时性网络故障NestJS 微服务模块内置 retry 策略(配置重试次数与间隔)
死信队列(DLX)处理无法消费的消息声明死信交换机,绑定异常队列,设置消息 TTL
服务熔断下游服务持续不可用集成 @nestjs/circuit-breaker,监控错误率触发熔断

关键配置(rabbitmq.config.ts 扩展):

options: {
  // ...其他配置
  prefetchCount: 10, // 每次预取消息量(避免单节点过载)
  noAck: false,      // 手动确认消息(确保消费成功后才移除)
}

工程示例:3


1 ) 方案1:基础Direct Exchange实现

// order.service.ts
import { RabbitMQService } from '@golevelup/nestjs-rabbitmq';

@Injectable()
export class OrderService {
  constructor(private readonly rabbitmq: RabbitMQService) {}

  async createOrder(vo: OrderCreateVO) {
    // 1. 创建本地订单
    const order = await this.orderRepo.save({...vo, status: OrderState.CREATING});
    
    // 2. 推送餐厅验证请求
    this.rabbitmq.publish('order.direct', 'restaurant.verify', {
      orderId: order.id,
      productId: vo.productId
    });
    
    // 3. 推送骑手分配请求
    this.rabbitmq.publish('order.direct', 'deliveryman.assign', {
      orderId: order.id,
      address: vo.address
    });
  }
}

// restaurant.service.ts
@RabbitRPC({
  exchange: 'order.direct',
  routingKey: 'restaurant.verify',
  queue: 'restaurant_queue'
})
handleRestaurantVerify(msg: { orderId: number, productId: number }) {
  // 验证商品库存
  const result = await this.productService.verifyStock(msg.productId);
  
  // 回传验证结果
  this.rabbitmq.publish('order.direct', 'order.update', {
    orderId: msg.orderId,
    status: result ? OrderState.RESTAURANT_CONFIRMED : OrderState.FAILED
  });
}

2 ) 方案2:消息持久化与ACK确认

// 消息发布配置
this.rabbitmq.publish('order.direct', 'deliveryman.assign', 
  { orderId: 123 },
  {
    persistent: true, // 消息持久化
    headers: { 'retry-count': 0 } // 自定义重试标记
  }
);

// 消息消费配置
@RabbitSubscribe({
  exchange: 'order.direct',
  routingKey: 'order.update',
  queue: 'order_update_queue',
  queueOptions: {
    durable: true, // 队列持久化
    arguments: { 'x-message-ttl': 60000 } // 消息TTL
  },
  allowNonJsonMessages: true
})
async handleOrderUpdate(msg: any) {
  try {
    await this.orderService.updateStatus(msg.orderId, msg.status);
    return { ack: true }; // 显式ACK确认
  } catch (e) {
    return { nack: true, requeue: msg.headers['retry-count'] < 3 }; // 限制重试
  }
}

3 ) 方案3:死信队列与错误处理

// 创建死信交换器
await this.rabbitmq.createExchange({
  name: 'order.dlx',
  type: 'direct',
  durable: true
});

// 队列绑定死信交换器
await this.rabbitmq.createQueue({
  name: 'restaurant_queue',
  options: {
    durable: true,
    deadLetterExchange: 'order.dlx', // 死信路由
    deadLetterRoutingKey: 'error.restaurant'
  }
});

// 死信处理器
@RabbitRPC({
  exchange: 'order.dlx',
  routingKey: 'error.*',
  queue: 'error_handler_queue'
})
handleError(msg, headers) {
  const service = headers['routingKey'].split('.')[1];
  this.errorService.log({
    service,
    payload: msg,
    timestamp: Date.now()
  });
}

RabbitMQ 运维命令手册


1 ) 队列状态检查

rabbitmqctl list_queues name messages_ready messages_unacknowledged

2 )交换器绑定关系查询

rabbitmqctl list_bindings source_name source_kind destination_name routing_key

3 )消息积压告警

# 监控 restaurant_queue 消息积压
rabbitmqctl eval 'rabbitmq_management:get_queue_metrics("/", <<"restaurant_queue">>).messages_ready.'

4 )强制重试死信

rabbitmqadmin publish routing_key="restaurant" payload='{"orderId":1001}' \
  exchange=dlx_exchange \
  properties='{"headers": {"retry_count": 0}}'

关键优化实践


1 ) 消息确认机制

// 生产者消息确认
this.amqpConnection.publish('direct.order', 'order.create', 
  { orderId: 1001 },
  { persistent: true, mandatory: true } // 开启持久化与路由失败回调
);

2 ) 消费者限流配置

@RabbitSubscribe({
 exchange: 'direct.order',
 routingKey: 'order.*',
 queue: 'rider_queue',
 queueOptions: {
   channel: 'rider_channel',
   prefetchCount: 5 // 每次处理5条消息
 }
})

3 )错误重试策略

# .env
RABBIT_RETRY_INTERVAL=3000
RABBIT_MAX_RETRIES=5

架构验证要点


1 ) 使用 curl 测试订单创建:

curl -X POST http://localhost:3000/orders -d '{"productId":1, "userId":1001}'

2 ) 通过 RabbitMQ Management 插件(http://localhost:15672)观察消息流向

3 ) 数据库事务验证:订单状态与库存扣减的原子性操作

核心注意事项


1 ) 金融计算安全

订单金额必须使用Decimal类型(安装decimal.js库):

import { Decimal } from 'decimal.js';

const price = new Decimal(19.99);
const total = price.mul(2).add('0.01'); // 39.99

2 ) 跨服务ID一致性
使用分布式ID生成方案:

// 安装 snowflake-id(Twitter雪花算法)
import { Snowflake } from 'snowflake-id';
const snowflake = new Snowflake();
const orderId = snowflake.generate().toString();

3 )消息幂等性设计

@Entity()
export class ProcessedMessage {
 @PrimaryColumn()
 messageId: string; // 唯一消息ID
}

async handleMessage(msg) {
 if (await this.messageRepo.exist(msg.id)) return;
 // 业务处理...
 this.messageRepo.save({ id: msg.id });
}

关键问题与优化策略


1 ) 消息序列化:

使用 JSON 序列化消息,配置 RabbitMQ 的 content_type 为 application/json

this.rabbitmqService.publish('exchange', 'routingKey', payload, {
  contentType: 'application/json',
});

2 ) 连接池管理:

// main.ts 中初始化
const app = await NestFactory.createMicroservice(AppModule, {
  strategy: new RabbitMQServer({
    uri: 'amqp://localhost:5672',
    connectionInitOptions: { wait: true },
    connectionManagerOptions: { heartbeatInterval: 30 },
  }),
});

3 )错误处理:

  • 消息重试:通过 @RabbitRPC 的 retry 选项实现指数退避重试。
  • 死信队列:捕获未处理消息,人工介入排查。

4 ) 性能优化:

  • 消息批处理:使用 batchSize 参数批量消费消息。
  • 通道复用:单个连接创建多通道(Channel)并行处理。

术语解释:

  • Direct Exchange:根据 routingKey 精确路由消息到队列。
  • 死信队列(DLX):当消息消费失败或超时,自动转发到备用队列。
  • BigDecimal:精确数值类型,避免金融场景的浮点误差(如用整数分存储金额)。

初学者指导:核心概念解析


术语说明
Direct Exchange通过精确匹配路由键投递消息,用于精准路由场景(如订单状态更新)
消息持久化通过persistent:true和队列durable:true双配置防止消息丢失
死信队列(DLX)处理多次重试失败的消息,避免阻塞主业务流
RESTful资源导向的API设计风格,URI表示资源,HTTP方法表示操作类型
UTC+8时区中国标准时间(Asia/Shanghai),所有服务器必须统一时区配置

架构演进建议:

  • 初期使用方案1快速实现核心流程
  • 业务量增长后升级方案2确保消息可靠性
  • 生产环境必须配置方案3的死信处理机制
  • 消息体压缩(如gzip)可降低带宽占用30%以上

总结


本文通过以下步骤实现基于 Direct Exchange 的微服务通信:

  1. 消息路由机制:使用 RabbitMQ Direct Exchange 实现服务间精确路由。
  2. 领域模型设计:
    • 严格区分 DTO(传输)、Entity(持久化)、VO(前端交互)。
    • 枚举类型强化状态机流转(如 OrderStatus)。
  3. 工程实践:
    • NestJS 集成 RabbitMQ 的模块化配置。
    • 生产者-消费者模式的异步解耦。
  4. 容错保障:
    • 死信队列处理异常消息。
    • 熔断机制防止雪崩效应。

扩展建议:

  • 结合 API 网关(如 Kong)统一管理微服务入口。
  • 使用 TypeORM 迁移工具 管理数据库 Schema 变更。
  • 集成 Prometheus + Grafana 监控消息队列吞吐量与延迟。
auto.js梦幻西游游戏脚本,梦幻西游脚本开发思路 本篇文章给大家谈谈梦幻西游脚本用什么语言写,以及auto.js梦幻西游游戏脚本,希望对各位有所帮助,不要忘了收藏本站喔。 阅读详情

相关推荐

云服务器安装ros教程

要在 CentOS 7 系统上安装 RouterOS,您需要将 RouterOS 安装为虚拟机或直接安装到物理硬盘上。这里提供的是将 RouterOS 安装到物理硬盘上的步骤,这将完全替换现有的 CentOS 7 系统。请确保您已经备份了所有重要数据。

qq_37662563的博客 2145

RabbitMQ的四种交换机使用及死信队列

RabbitMQ的四周交换机使用及死信队列

weixin_44301905的博客 2681

OKCC呼叫中心部署实战指南:从零搭建高效外呼系统

本文提供OKCC呼叫中心系统的完整部署实战指南,从服务器选型、操作系统准备到详细安装步骤和性能优化,帮助企业从零搭建高效外呼系统。重点介绍FreeSWITCH核心组件的安装配置技巧,以及常见问题排查方法,助力企业提升客户服务效率。

weixin_29275257的博客 164

7.用DockerCompose接入RabbitMQ实现异步推理

本文介绍如何用 Docker Compose 部署 RabbitMQ,结合 FastAPI 与 Worker 实现异步推理。通过消息队列解耦任务提交与执行,确保大文件、视频等耗时任务不阻塞 HTTP 请求。关键实践包括:使用小体积消息传递任务标识、启用持久化与确认机制、手动 ACK 防止丢失、配置重试与死信队列、保障幂等性,并通过 PostgreSQL 管理任务状态。强调异步系统需兼顾消息可靠性、结果可查与容错能力,为算法工程化落地提供完整链路参考。

像风一样自由的博客 397

【ChatGPT实战案例】ChatGPT如何帮助产品经理高效工作?

1. 产品经理主要工作方向, 2. 具体工作中,向ChatGPT提问参考

weixin_62909516的博客 1902

基于Open Cluster Management构建企业级多Kubernetes集群管理平台OpenClaw

在云原生架构中,Kubernetes已成为容器编排的事实标准。随着业务规模扩大,企业往往需要管理分布在多个云环境或数据中心的Kubernetes集群,这带来了集群管理、应用分发、策略统一和监控运维等复杂挑战。多集群管理技术通过提供统一控制平面,实现了对分布式资源的集中管控,其核心价值在于提升运维效率、保障安全合规并降低管理成本。Open Cluster Management(OCM)作为CNCF沙箱项目,采用Kubernetes原生架构,通过自定义资源定义(CRD)和控制器模式,为构建多集群管理平台提供了标

weixin_33747129的博客 369

消息队列入门:RabbitMQ 与 Kafka 核心概念与运维要点

BIOS→GRUB→内核→systemd→target 全链路解读,root 密码忘了解锁、文件系统损坏修复、单用户模式与救援模式实战,服务器起不来时的救命指南。

2502_91473995的博客 414

addBumpConnectTargetConstraint 命令详解

本文介绍了Cadence Innovus中用于倒装芯片设计的addBumpConnectTargetConstraint命令的核心功能和使用方法。该命令主要用于为凸点(Bump)添加连接目标约束,通过绑定实例、引脚/网络和端口号等属性,实现凸点与电源/信号网络的精准映射。文章详细解析了命令语法结构、参数说明及使用场景,包括必选参数(指定凸点方式)、分支选择(实例连接或电源连接类型)以及互斥参数(引脚名与网络名)等重要注意事项,并提供了典型应用示例。该命令特别适用于倒装芯片设计中凸点与PG网络、IO实例的连接

u013620135的博客 395

从0到1掌握Kafka与RabbitMQ在IM即时聊天中的

本文从理论出发,结合《Designing Data-Intensive Applications》一书的知识体系,通过实际代码演示了如何利用Kafka与RabbitMQ来支撑IM系统的不同模块。无论是私聊还是群聊场景都可以找到对应解决方案。接下来你可以尝试以下几个方向进行深入学习: 1. 实现多节点集群部署,并了解如何设置HA机制。2. 学习如何在Spring Boot等框架中整合这两种中间件。3. 探索使用Flink或Spark Streaming对接Kafka做实时分析。

qq_41106321的博客 221

SIMULINK开发项目实例 1000 例专栏之第960例--基于电力系统稳定性的建模与仿真场景:-含分布式电源的配电网电压稳定性研究

间歇性与随机性:例如,太阳能依赖于日照强度,风能依赖于风速,这使得它们的输出功率具有不确定性。逆变器接口:大多数分布式电源通过逆变器接入电网,这对电网的动态响应特性产生了影响。位置分散:通常分布在用户侧或靠近负荷中心的位置。本文详细介绍了如何使用Simulink结合Simscape Electrical 构建一个用于研究含分布式电源配电网电压稳定性的模型,并提供了详细的仿真流程说明。

xiaoheshang_123的博客 156

小程序数据采集(3):PC端微信小程序降维调试与流量数据获取详解

本文提出了一种针对PC端微信小程序的逆向分析方法,通过利用PC端基于Chromium架构的天然优势,实现无需Root的降维打击。文章详细介绍了如何开启CEF远程调试协议、基于DevTools Protocol实现流量劫持、对抗PC端安全防线以及获取小程序本地存储数据的技术方案。相比移动端严苛的环境,PC端小程序在调试接口、网络拦截和数据存储等方面存在显著漏洞,为爬虫开发提供了更便捷的突破口。

数据知道的博客 831

Docker Compose 模块化多环境配置规范指南:示例搭建RabbitMQ 4.4.0-management

本文介绍Docker Compose模块化多环境配置规范,以RabbitMQ 4.4.0-management为例,采用双层配置隔离:根目录.env管理全局变量(如环境、网络),服务私有.env定义版本、密码、端口等专属参数。通过环境目录物理隔离(dev/test/prod),实现配置与数据的可移植性与安全性,支持一键部署与迁移。

郝开的博客 105

【FPGA教程案例49】控制案例1——基于FPGA的PID控制器verilog实现

PID控制器产生于1915年,PID控制律的概念最早是由LYAPIMOV提出的,到目前为止,PID控制器以及改进的PID控制器在工业控制领域里最为常见。PID控制器(比例-积分-微分控制器),由比例单元 P、积分单元 I 和微分单元 D 组成。通过Kp,Ki和Kd三个参数的设定。PID控制器主要适用于基本线性和动态特性不随时间变化的系统。图1为PID控制器的基本结构框图。PID控制器以其结构简单、稳定性好、工作可靠、调整方便而成为工业控制的主要技术之一。...

FPGA/MATLAB学习教程/源码/项目合作开发 4532

RabbitMQ 消费端幂等:唯一索引、条件更新、Redis 去重三种方案的真实代价

MQ 只承诺至少投递一次,重复消息只能消费端自己吃掉。这篇对比唯一索引、条件更新、Redis 短路三种去重方案在 AI 任务场景下的实际代价,附三个踩过的坑。

zhangpan 259

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

【RabbitMQ】认识RabbitMQ

本文系统介绍MQ消息队列的核心概念、四大作用(异步解耦、流量削峰、消息分发、延迟通知)及主流产品对比,重点讲解RabbitMQ的安装部署、核心组件(生产者、消费者、交换机、队列、虚拟主机)与AMQP协议原理,并通过Java原生客户端实现简单消息通信,适用于中小型项目快速上手。

记录了从0学习Java技术栈的日常 178

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

微服务与单体的取舍

微服务非技术升级,而是组织与运维能力的变现。收益(故障隔离、独立扩展、发布、边界清晰)随规模放大,成本却一次性支付。拆分需满足团队超十人、负载差异大、发布互阻、领域稳定四条件。否则应优先采用模块化单体——代码分层、接口约束,边界清晰,未来可平滑拆分。避免按技术层划分服务,坚持“一服务一数据所有权”。拆分前确保基础设施完备,且以具体痛点为信号,逐步推进,先拆最痛处,验证后再行扩展。

2401_89855466的博客 301

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

微服务 + Spring AI 全栈实战避坑笔记

方法里,不要直接返回 List 或对象,一定要用 StringBuilder 或 JSON 工具转成可读文本再返回。:Nacos 和 Gateway 的配置缓存极深,改完配置不彻底 Stop 再 Start,等于没改。如果真实端口通了,绝对不要在微服务里找代码问题,死死盯住网关配置。:Spring AI 里程碑版本包不在阿里云镜像中,或者 IDEA 拦截了 HTTPS 证书。端口(绕过网关),如果通了,说明 100% 是网关配置或没重启的问题。:完全不用管,这是浏览器请求网页图标,不影响任何业务逻辑。

2503_93626619的博客 249

微服务链路追踪实战

链路追踪不是「装个 Agent 就完事」的工具,而是一套需要标准、规范、流程共同支撑的可观测性基础设施。标准先行:以 OpenTelemetry 为埋点与数据标准,避免厂商锁定;自动打底、手动补充:保证覆盖的同时提升业务语义;上下文传播是生命线:线程池、MQ、异步回调是高频断点,必须专项治理;采样是成本与可观测性的平衡点:核心链路高采样,异常慢请求强制采样;价值不止排障:链路追踪还能驱动架构治理、容量规划和故障演练;常见问题有章可循。

流水账 647

C++ 微服务 IM 用户管理子服务:架构拆分与 MySQL ODB 数据层落地

面向 C++ 即时通讯系统,给出用户管理子服务的边界拆分、契约定义与 ODB 编译期数据层方案,含构建脚本、事务封装和排错对照表。

2301_78967866的博客 354

带着小白学习-微服务-6 实战:网关

地址栏输入:http://localhost:8088/goods/index,这时候就不是到8100端口去调用了,而是8088直接通过路由转发,分别到nacos对应的goods对应的服务中区调用。** 可以看出,这里将前面已经正常运行的server-store子工程(库存服务,服务提供方),server-goods子工程(商品服务,服务消费方)。(1)uri: lb://store 代表要到nacos的注册中心的服务列表中找到服务名为store的微服务;,网关是做路由转发,不是服务调用;

wdyan297的博客 242

【C++ 基于微服务的即时通讯系统】用户管理子服务架构设计与MySQL ODB数据层落地

前面我们陆续落地了语音识别、文件存储两个独立子服务,把微服务的标准开发流程完整跑通了一遍。从这篇开始,我们正式进入核心业务模块的开发,第一个要啃的就是用户管理子服务。用户服务是整个IM系统的账号基石,所有业务都依赖用户身份体系。它也是目前为止依赖最复杂的服务:既要用MySQL存用户元数据,用Redis存会话和验证码,用ES做用户搜索,还要跨服务调用文件服务管理头像。内容比较多,我们分两篇来写,这一篇先讲整体架构设计,再重点拆解最基础的MySQL数据层,基于ODB框架完成完整的ORM封装和测试验证。

会当凌绝顶,一览众山小 5930

从微服务到 AI Agent 全栈实战笔记

基础框架:Spring Boot 3.3.x / 3.4.x微服务组件:Spring Cloud 2023.0.x / Spring Cloud Alibaba 2023.0.xAI 框架:Spring AI 1.0.x + Spring AI Alibaba (DashScope)核心中间件:Nacos (注册/配置中心)、MySQL、MyBatis-Plus服务注册与发现:所有服务启动时向 Nacos 报到,互相调用时通过服务名(如 )去 Nacos 查询真实 IP。配置中心:废弃 ,统一使用 中的

2503_93626619的博客 179

从线上故障看 Shell 脚本在微服务限流熔断中的 3 个

在高并发系统中,微服务网关承担着流量控制与熔断的重要职责,而 Shell 脚本作为自动化运维工具的常见形式,在某些场景下被用于触发限流规则或辅助监控。然而,近期我们在某大型电商平台的网关模块中遭遇了一个因 Shell 脚本使用不当而导致的严重故障。本文将围绕该真实案例,从问题复现、原因定位到解决方案,探讨 Shell 脚本在微服务限流熔断场景下的三个典型陷阱。

qq_41106321的博客 136

基于Spring Boot 2.x开发的微服务访问Redis的方案

回到最初的问题:Spring Boot 2.x 微服务该用哪个 Redis 客户端?默认选 Lettuce:Boot 2.x 官方默认,Netty 异步模型,线程安全,单连接高并发,是绝大多数场景的最优解。Jedis 不是不能用:历史项目、简单同步场景依然可靠,但要把连接池参数调好,并清楚它的阻塞模型限制。Redisson 是能力补充:分布式锁、限流、布隆过滤器等开箱即用,建议与 Lettuce 共存而非替换。客户端选型只是起点,真正决定线上稳定性的,是序列化统一、连接池合理、超时可控、监控到位。

流水账 762

Rust如何实现微服务网关的高并发与限流熔断机制

在现代互联网系统中,微服务架构已成为主流,而微服务网关则是整个系统的重要组成部分。当面对高并发、高可用性需求时,很多开发者对如何用 Rust 实现一个稳定可靠的网关存在疑惑,尤其是处理请求的幂等性、限流和熔断机制。本文将以 Rust 的实际案例为基础,结合生产环境中的具体经验,讲解如何设计和实现一个具备限流与熔断能力的微服务网关。

wuchangjian的专栏 112

C++ 微服务 IM 骨架开箱:目录规划、架构分层与全量接口清单

梳理 C++ 即时通讯微服务的开箱骨架:先回顾服务分层与调用链,再给出单仓目录规划、proto 契约与 CMake 装配,附全量接口表和冒烟排错清单。

2301_78967866的博客 211
上一篇: RabbitMQ: 数据访问层开发与队列交换机绑定
下一篇: RabbitMQ: 订单→餐厅→骑手→结算的消息驱动架构设计
Wang's Blog
博客等级 码龄12年 7438粉丝 2421原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

Wang's Blog

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

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

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

打赏作者

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

抵扣说明:

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

余额充值