高性能Go消息队列实战:go-nsq完全指南2025

高性能Go消息队列实战:go-nsq完全指南2025

【免费下载链接】go-nsq The official Go package for NSQ 【免费下载链接】go-nsq 项目地址: https://gitcode.com/gh_mirrors/go/go-nsq

引言:为什么选择go-nsq?

你是否还在为分布式系统中的消息传递延迟而困扰?是否正在寻找一款专为Go语言优化的高性能消息队列解决方案?本文将带你全面掌握go-nsq——NSQ的官方Go客户端,助你轻松构建高可用、低延迟的分布式消息系统。

读完本文,你将获得:

  • 快速上手go-nsq的完整步骤
  • 核心API的深入解析与实战示例
  • 性能优化与最佳实践指南
  • 常见问题解决方案与版本迁移技巧

1. 项目概述

1.1 什么是go-nsq?

go-nsq是NSQ(一种实时分布式消息处理平台)的官方Go语言客户端库,提供了生产消息(Producer)和消费消息(Consumer)的完整功能。作为NSQ生态系统的重要组成部分,go-nsq经过精心优化,充分发挥Go语言的并发特性,为构建高性能分布式系统提供可靠的消息传递能力。

1.2 核心特性

特性描述优势
高性能利用Go的goroutine和channel特性,支持高并发消息处理单机轻松处理数十万消息/秒
可靠性支持消息确认机制、重试策略和死信队列确保消息不丢失,可追溯
灵活性丰富的配置选项,支持TLS加密、压缩、认证等适应各种复杂场景需求
自动发现集成nsqlookupd,支持服务自动发现简化集群管理,动态扩缩容
背压机制智能流量控制,防止消费者过载保护系统稳定性,避免级联故障

1.3 应用场景

  • 日志收集:高吞吐量的日志聚合与处理
  • 实时分析:流数据处理与实时计算
  • 服务解耦:微服务架构中的异步通信
  • 任务队列:分布式任务调度与执行
  • 事件驱动:构建响应式应用架构

2. 快速开始

2.1 环境准备

安装go-nsq

go get -u gitcode.com/gh_mirrors/go/go-nsq

启动NSQ服务

# 启动nsqlookupd
nsqlookupd

# 启动nsqd,连接到lookupd
nsqd --lookupd-tcp-address=127.0.0.1:4160

# 可选:启动nsqadmin(Web管理界面)
nsqadmin --lookupd-http-address=127.0.0.1:4161

2.2 第一个生产者示例

package main

import (
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"
	
	"gitcode.com/gh_mirrors/go/go-nsq"
)

func main() {
	// 创建配置
	config := nsq.NewConfig()
	config.MaxInFlight = 100
	config.DialTimeout = 10 * time.Second
	
	// 创建生产者
	producer, err := nsq.NewProducer("127.0.0.1:4150", config)
	if err != nil {
		log.Fatal(err)
	}
	
	// 设置日志
	producer.SetLogger(log.New(os.Stdout, "PRODUCER: ", log.LstdFlags), nsq.LogLevelInfo)
	
	// 测试连接
	if err := producer.Ping(); err != nil {
		log.Fatalf("Ping failed: %v", err)
	}
	
	// 捕获退出信号
	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
	
	// 发送消息
	go func() {
		for i := 0; i < 100; i++ {
			msg := []byte(fmt.Sprintf("message %d", i))
			err := producer.Publish("test_topic", msg)
			if err != nil {
				log.Printf("Publish error: %v", err)
			} else {
				log.Printf("Published message: %s", msg)
			}
			time.Sleep(100 * time.Millisecond)
		}
		log.Println("Message publishing completed")
	}()
	
	<-sigChan
	log.Println("Exiting...")
	producer.Stop()
}

2.3 第一个消费者示例

package main

import (
	"log"
	"os"
	"os/signal"
	"syscall"
	
	"gitcode.com/gh_mirrors/go/go-nsq"
)

// 自定义消息处理器
type MyHandler struct {
	consumer *nsq.Consumer
}

// 实现Handler接口
func (h *MyHandler) HandleMessage(msg *nsq.Message) error {
	if len(msg.Body) == 0 {
		// 空消息,直接确认
		return nil
	}
	
	log.Printf("Received message: %s", msg.Body)
	
	// 模拟处理时间
	// time.Sleep(10 * time.Millisecond)
	
	return nil // 返回nil表示成功处理,会自动发送FIN
}

func main() {
	// 创建配置
	config := nsq.NewConfig()
	config.MaxInFlight = 100
	config.LookupdPollInterval = 15 * time.Second
	
	// 创建消费者
	consumer, err := nsq.NewConsumer("test_topic", "test_channel", config)
	if err != nil {
		log.Fatal(err)
	}
	
	// 设置日志
	consumer.SetLogger(log.New(os.Stdout, "CONSUMER: ", log.LstdFlags), nsq.LogLevelInfo)
	
	// 设置消息处理器
	handler := &MyHandler{consumer: consumer}
	consumer.AddHandler(handler)
	
	// 连接到nsqlookupd
	err = consumer.ConnectToNSQLookupd("127.0.0.1:4161")
	if err != nil {
		log.Fatal(err)
	}
	
	// 或者直接连接到nsqd
	// err = consumer.ConnectToNSQD("127.0.0.1:4150")
	// if err != nil {
	// 	log.Fatal(err)
	// }
	
	// 等待退出信号
	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
	<-sigChan
	
	// 优雅关闭消费者
	consumer.Stop()
	<-consumer.StopChan
	log.Println("Consumer stopped")
}

2.4 运行示例

  1. 先启动消费者:
go run consumer.go
  1. 再启动生产者:
go run producer.go

你将看到生产者发送消息,消费者接收并处理消息的完整过程。

3. 核心概念与API解析

3.1 核心组件

3.1.1 Config (配置)

Config是go-nsq的配置中心,所有客户端参数都通过它设置。必须使用NewConfig()创建,确保正确初始化默认值。

常用配置项

配置项类型默认值描述
MaxInFlightint1最大在飞行消息数(并发处理数)
LookupdPollIntervaltime.Duration60snsqlookupd轮询间隔
MaxAttemptsuint165消息最大重试次数
DefaultRequeueDelaytime.Duration90s默认消息重排队延迟
MaxBackoffDurationtime.Duration2m最大退避延迟
TLSv1boolfalse是否启用TLS加密
Deflateboolfalse是否启用Deflate压缩
Snappyboolfalse是否启用Snappy压缩
AuthSecretstring""认证密钥

配置示例

config := nsq.NewConfig()
config.MaxInFlight = 200
config.LookupdPollInterval = 30 * time.Second
config.MaxAttempts = 10
config.DefaultRequeueDelay = 2 * time.Minute
config.TLSv1 = true
config.AuthSecret = "your-secret-key"

// 使用Set方法设置
config.Set("deflate_level", 5)
config.Set("max_msg_size", 1024*1024)
3.1.2 Producer (生产者)

Producer用于向NSQ集群发布消息,主要API:

  • NewProducer(addr string, config *Config) (*Producer, error): 创建生产者实例
  • Publish(topic string, body []byte) error: 同步发布消息
  • PublishAsync(topic string, body []byte, doneChan chan *ProducerTransaction, args ...interface{}) error: 异步发布消息
  • MultiPublish(topic string, body [][]byte) error: 批量发布消息
  • DeferredPublish(topic string, delay time.Duration, body []byte) error: 延迟发布消息
  • Stop() error: 停止生产者

生产者工作流程

mermaid

3.1.3 Consumer (消费者)

Consumer用于从NSQ集群消费消息,主要API:

  • NewConsumer(topic string, channel string, config *Config) (*Consumer, error): 创建消费者实例
  • AddHandler(handler Handler): 添加消息处理器
  • ConnectToNSQD(addr string) error: 连接到指定nsqd
  • ConnectToNSQLookupd(addr string) error: 连接到nsqlookupd
  • Stats() *ConsumerStats: 获取消费者统计信息
  • Stop() error: 停止消费者
  • ChangeMaxInFlight(max int): 动态调整最大并发数

消费者工作流程

mermaid

3.1.4 Message (消息)

Message是消息的封装,包含消息ID、正文、时间戳等元数据。

主要方法

  • Finish(): 标记消息处理成功
  • Requeue(delay time.Duration): 重新排队消息,带延迟
  • RequeueWithoutBackoff(delay time.Duration): 重新排队消息,不带退避
  • Touch(): 延长消息处理超时时间
  • DisableAutoResponse(): 禁用自动响应,手动控制消息确认

消息结构

type Message struct {
    ID        MessageID  // 消息唯一ID
    Body      []byte     // 消息正文
    Timestamp int64      // 时间戳(纳秒)
    Attempts  uint16     // 已尝试次数
    NSQDAddress string   // 发送消息的NSQD地址
}

3.2 消息处理模式

3.2.1 自动响应模式 (默认)

处理器返回nil表示成功,会自动发送FIN;返回错误则自动发送REQ,使用默认延迟。

func (h *MyHandler) HandleMessage(msg *nsq.Message) error {
    // 处理消息
    if err := process(msg.Body); err != nil {
        log.Printf("处理失败: %v", err)
        return err // 自动REQ,使用默认延迟
    }
    return nil // 自动FIN
}
3.2.2 手动响应模式

调用DisableAutoResponse()禁用自动响应,手动调用Finish()Requeue()

func (h *MyHandler) HandleMessage(msg *nsq.Message) error {
    msg.DisableAutoResponse() // 禁用自动响应
    
    // 异步处理消息
    go func() {
        err := process(msg.Body)
        if err != nil {
            msg.Requeue(5 * time.Second) // 手动重排队
        } else {
            msg.Finish() // 手动确认
        }
    }()
    
    return nil // 这里返回nil不影响手动响应
}
3.2.3 批量处理模式

通过设置适当的MaxInFlight和批处理大小,实现消息批量处理。

type BatchHandler struct {
    batchSize int
    messages  chan *nsq.Message
    wg        sync.WaitGroup
}

func NewBatchHandler(batchSize int) *BatchHandler {
    h := &BatchHandler{
        batchSize: batchSize,
        messages:  make(chan *nsq.Message, batchSize*2),
    }
    h.startWorker()
    return h
}

func (h *BatchHandler) startWorker() {
    h.wg.Add(1)
    go func() {
        defer h.wg.Done()
        batch := make([]*nsq.Message, 0, h.batchSize)
        ticker := time.NewTicker(100 * time.Millisecond)
        defer ticker.Stop()
        
        for {
            select {
            case msg, ok := <-h.messages:
                if !ok {
                    // 处理剩余消息
                    if len(batch) > 0 {
                        h.processBatch(batch)
                    }
                    return
                }
                batch = append(batch, msg)
                if len(batch) >= h.batchSize {
                    h.processBatch(batch)
                    batch = batch[:0]
                }
            case <-ticker.C:
                if len(batch) > 0 {
                    h.processBatch(batch)
                    batch = batch[:0]
                }
            }
        }
    }()
}

func (h *BatchHandler) processBatch(batch []*nsq.Message) {
    // 处理批量消息
    for _, msg := range batch {
        // 处理单条消息
        // ...
        msg.Finish() // 手动确认
    }
}

func (h *BatchHandler) HandleMessage(msg *nsq.Message) error {
    msg.DisableAutoResponse() // 禁用自动响应
    select {
    case h.messages <- msg:
        return nil
    default:
        // 缓冲区满,立即重排队
        return errors.New("batch buffer full")
    }
}

4. 高级特性

4.1 安全通信 (TLS)

go-nsq支持TLS加密通信,确保消息在传输过程中的安全性。

配置TLS

config := nsq.NewConfig()
config.TLSv1 = true

// 加载CA证书
caCertPool := x509.NewCertPool()
caCert, err := os.ReadFile("ca.pem")
if err != nil {
    log.Fatal(err)
}
caCertPool.AppendCertsFromPEM(caCert)

// 加载客户端证书(如果需要双向认证)
clientCert, err := tls.LoadX509KeyPair("client.pem", "client.key")
if err != nil {
    log.Fatal(err)
}

config.TlsConfig = &tls.Config{
    RootCAs:            caCertPool,
    Certificates:       []tls.Certificate{clientCert},
    InsecureSkipVerify: false, // 生产环境中设为false
    ServerName:         "nsqd.example.com",
}

// 使用配置创建生产者或消费者
producer, err := nsq.NewProducer("127.0.0.1:4150", config)
// 或
consumer, err := nsq.NewConsumer("topic", "channel", config)

4.2 消息压缩

go-nsq支持Deflate和Snappy两种压缩算法,减少网络传输带宽。

启用压缩

config := nsq.NewConfig()

// 启用Deflate压缩
config.Deflate = true
config.DeflateLevel = 5 // 压缩级别(1-9),越高压缩率越好但CPU消耗越大

// 或启用Snappy压缩
// config.Snappy = true

producer, err := nsq.NewProducer("127.0.0.1:4150", config)

4.3 认证与授权

对于需要访问控制的场景,go-nsq支持基于密钥的认证机制。

配置认证

config := nsq.NewConfig()
config.AuthSecret = "your-secret-key" // 设置认证密钥

// 创建生产者或消费者
producer, err := nsq.NewProducer("127.0.0.1:4150", config)

4.4 消息延迟与重试

go-nsq提供灵活的消息重试机制,确保消息最终被正确处理。

自定义重试策略

config := nsq.NewConfig()
config.MaxAttempts = 10 // 最大重试次数
config.DefaultRequeueDelay = 30 * time.Second // 默认重试延迟
config.MaxRequeueDelay = 5 * time.Minute // 最大重试延迟

// 使用完全抖动退避策略(FullJitter)
config.BackoffStrategy = &nsq.FullJitterStrategy{}

// 或使用指数退避策略(默认)
// config.BackoffStrategy = &nsq.ExponentialStrategy{}

consumer, err := nsq.NewConsumer("topic", "channel", config)

处理失败消息

实现FailedMessageLogger接口,处理达到最大重试次数的消息:

type MyHandler struct{}

func (h *MyHandler) HandleMessage(msg *nsq.Message) error {
    // 处理消息
    // ...
    if err != nil {
        return err // 消息将被重试
    }
    return nil
}

func (h *MyHandler) LogFailedMessage(msg *nsq.Message) {
    // 处理最终失败的消息
    log.Printf("Message failed after %d attempts: %s", msg.Attempts, msg.Body)
    
    // 可以将失败消息写入数据库或死信队列
    // saveToDeadLetterQueue(msg)
}

4.5 动态调整

go-nsq支持运行时动态调整消费者的并发处理能力,适应流量变化。

动态调整示例

// 创建消费者时设置初始MaxInFlight
config := nsq.NewConfig()
config.MaxInFlight = 100
consumer, _ := nsq.NewConsumer("topic", "channel", config)

// 运行时动态调整
go func() {
    // 监控系统负载或其他指标
    for {
        load := getSystemLoad()
        newMax := calculateNewMaxInFlight(load)
        
        // 调整MaxInFlight
        consumer.ChangeMaxInFlight(newMax)
        log.Printf("Changed MaxInFlight to %d", newMax)
        
        time.Sleep(30 * time.Second)
    }
}()

5. 最佳实践

5.1 性能优化

5.1.1 合理设置MaxInFlight

MaxInFlight控制并发处理的消息数量,是最重要的性能调优参数:

  • 过小会导致吞吐量低,资源利用率不足
  • 过大会增加内存消耗,可能导致消息积压

推荐设置:根据系统资源和消息处理耗时调整,一般设置为(预期QPS * 平均处理耗时)的1.5-2倍。

5.1.2 批量操作

对于数据库写入等IO密集型操作,使用批量处理能显著提升性能:

type BatchHandler struct {
    batchSize int
    buffer    []*nsq.Message
    mutex     sync.Mutex
    ticker    *time.Ticker
}

// 实现批量处理逻辑
// ...
5.1.3 异步处理

充分利用Go的并发特性,将消息处理逻辑异步化:

func (h *AsyncHandler) HandleMessage(msg *nsq.Message) error {
    msg.DisableAutoResponse()
    
    // 提交到工作池异步处理
    go func(m *nsq.Message) {
        defer m.Finish()
        
        // 处理消息
        // ...
    }(msg)
    
    return nil
}

5.2 可靠性保障

5.2.1 优雅关闭

确保应用退出时正确关闭消费者,避免消息丢失:

// 设置信号处理
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)

// 等待退出信号
<-sigChan

// 优雅关闭消费者
consumer.Stop()
log.Println("Waiting for consumer to stop...")
<-consumer.StopChan
log.Println("Consumer stopped gracefully")
5.2.2 监控与告警

利用Stats()接口实现监控:

// 定期收集统计信息
go func() {
    ticker := time.NewTicker(10 * time.Second)
    for range ticker.C {
        stats := consumer.Stats()
        log.Printf("Stats: Received=%d, Finished=%d, Requeued=%d, Connections=%d",
            stats.MessagesReceived,
            stats.MessagesFinished,
            stats.MessagesRequeued,
            stats.Connections)
        
        // 发送到监控系统
        // sendToMonitoring(stats)
        
        // 设置告警阈值
        if stats.MessagesRequeued > threshold {
            sendAlert("High requeue rate detected")
        }
    }
}()
5.2.3 消息持久化

确保NSQ正确配置持久化,防止服务重启导致消息丢失:

# 启动nsqd时启用持久化
nsqd --lookupd-tcp-address=127.0.0.1:4160 --data-path=/path/to/persist --mem-queue-size=100000

5.3 常见问题解决

5.3.1 消息重复消费

原因

  • 消费者处理超时,消息被重新投递
  • 消费者异常退出,未确认的消息被重新投递
  • 网络分区导致NSQ集群状态不一致

解决方案

  • 设计幂等的消息处理逻辑
  • 设置合理的MsgTimeout(大于实际处理时间)
  • 使用消息ID实现去重机制
// 基于消息ID的去重示例
type DedupHandler struct {
    processedIDs *cache.Cache // 使用缓存记录已处理的消息ID
}

func (h *DedupHandler) HandleMessage(msg *nsq.Message) error {
    msgID := string(msg.ID[:])
    
    // 检查是否已处理
    if h.processedIDs.Exists(msgID) {
        return nil // 已处理,直接返回成功
    }
    
    // 处理消息
    // ...
    
    // 记录已处理ID,设置过期时间
    h.processedIDs.Set(msgID, true, 24*time.Hour)
    return nil
}
5.3.2 消费者积压

原因

  • 生产者速度超过消费者处理能力
  • 消费者处理逻辑效率低
  • 资源限制(CPU、内存、IO)

解决方案

  • 增加消费者实例,水平扩展
  • 优化消息处理逻辑,提高单实例处理能力
  • 调整MaxInFlight,提高并发处理能力
  • 实施流量控制,保护消费者
// 监控并告警消息积压
go func() {
    for {
        stats := consumer.Stats()
        pending := getPendingMessages(consumer) // 需要通过NSQ admin API获取
        
        log.Printf("Pending messages: %d", pending)
        if pending > 10000 {
            sendAlert(fmt.Sprintf("High pending messages: %d", pending))
            
            // 可以动态调整MaxInFlight
            // consumer.ChangeMaxInFlight(200)
        }
        
        time.Sleep(10 * time.Second)
    }
}()
5.3.3 网络分区处理

解决方案

  • 配置多个nsqlookupd实例,避免单点故障
  • 实现自定义的NSQD发现过滤器
  • 监控连接状态,及时告警
// 自定义NSQD发现过滤器
type MyDiscoveryFilter struct{}

func (f *MyDiscoveryFilter) Filter(nsqdAddrs []string) []string {
    // 过滤不可用的NSQD节点
    filtered := []string{}
    for _, addr := range nsqdAddrs {
        if isNSQDReachable(addr) { // 检查NSQD是否可达
            filtered = append(filtered, addr)
        }
    }
    return filtered
}

// 设置过滤器
consumer.SetBehaviorDelegate(&MyDiscoveryFilter{})

6. 版本迁移指南

6.1 从v0.3.x迁移到v1.x

go-nsq在v1.0.0版本有较大的API变更,主要变化包括:

  1. 类型重命名

    • ReaderConsumer
    • WriterProducer
  2. 配置方式

    • 统一使用Config结构体,通过NewConfig()创建
  3. 处理接口

    • 合并HandlerAsyncHandler为单一Handler接口
    • 通过DisableAutoResponse()控制手动/自动响应

迁移示例

v0.3.x代码

// 创建Reader
r, err := nsq.NewReader("topic", "channel")
if err != nil {
    log.Fatal(err)
}

// 设置配置
r.SetMaxInFlight(100)
r.SetMaxAttempts(5)

// 设置处理函数
r.AddHandler(nsq.HandlerFunc(func(m *nsq.Message) error {
    // 处理消息
    return nil
}))

// 连接到nsqd
err = r.ConnectToNSQD("127.0.0.1:4150")
if err != nil {
    log.Fatal(err)
}

v1.x代码

// 创建配置
config := nsq.NewConfig()
config.MaxInFlight = 100
config.MaxAttempts = 5

// 创建Consumer
consumer, err := nsq.NewConsumer("topic", "channel", config)
if err != nil {
    log.Fatal(err)
}

// 设置处理函数
consumer.AddHandler(nsq.HandlerFunc(func(m *nsq.Message) error {
    // 处理消息
    return nil
}))

// 连接到nsqd
err = consumer.ConnectToNSQD("127.0.0.1:4150")
if err != nil {
    log.Fatal(err)
}

6.2 版本历史与变更

go-nsq保持活跃开发,重要版本变更包括:

版本发布日期主要变化
v1.1.02021-10-25支持每个日志级别独立Logger,优化RDY更新逻辑
v1.0.82019-12-24支持Go Modules,修复多个稳定性问题
v1.0.02014-08-11重大API重构,重命名Reader/Writer为Consumer/Producer
v0.3.72014-05-25最后一个使用旧API的稳定版本

升级建议

  • 从v0.3.x升级到v1.x需要修改代码,建议逐步迁移
  • 新版本保持API稳定性, minor版本间可平滑升级
  • 关注CHANGELOG.md,了解版本间的breaking changes

7. 总结与展望

7.1 核心优势回顾

go-nsq作为NSQ的官方Go客户端,凭借其卓越的性能、可靠性和易用性,成为构建分布式消息系统的理想选择。其核心优势包括:

  • 高性能:充分利用Go语言特性,实现高并发、低延迟的消息处理
  • 可靠性:完善的消息确认机制和重试策略,确保消息不丢失
  • 灵活性:丰富的配置选项和扩展机制,适应各种应用场景
  • 易集成:简洁直观的API设计,降低开发和维护成本

7.2 未来发展趋势

  • 更智能的流量控制:基于AI/ML的自适应流量调节
  • 增强的监控能力:更细粒度的性能指标和诊断信息
  • 与云原生生态融合:更好地支持Kubernetes等容器编排平台
  • 安全增强:更丰富的认证授权机制,符合企业级安全要求

7.3 学习资源

  • 官方文档:https://godoc.org/gitcode.com/gh_mirrors/go/go-nsq
  • 源代码:https://gitcode.com/gh_mirrors/go/go-nsq
  • NSQ官网:https://nsq.io/
  • 社区支持:GitHub Issues和Stack Overflow

7.4 结语

go-nsq为Go开发者提供了构建高性能分布式消息系统的强大工具。通过本文介绍的核心概念、API解析和最佳实践,你已经具备了使用go-nsq构建可靠消息传递系统的基础知识。

无论是构建简单的任务队列,还是复杂的分布式事件处理平台,go-nsq都能为你的项目提供稳定、高效的消息传递能力。立即开始探索,体验go-nsq带来的强大功能!


如果你觉得本文对你有帮助,请点赞、收藏并关注,以便获取更多关于go-nsq和分布式系统的优质内容。下期预告:《深入NSQ内部:架构解析与性能调优》

附录:参考资料

  1. NSQ官方文档:https://nsq.io/
  2. go-nsq API文档:https://godoc.org/gitcode.com/gh_mirrors/go/go-nsq
  3. NSQ: From Design to Deployment:https://www.oreilly.com/library/view/nsq-from-design/9781491942489/
  4. Go Concurrency Patterns:https://talks.golang.org/2012/concurrency.slide
  5. Distributed Systems Observability:https://www.oreilly.com/library/view/distributed-systems-observability/9781492033431/

【免费下载链接】go-nsq The official Go package for NSQ 【免费下载链接】go-nsq 项目地址: https://gitcode.com/gh_mirrors/go/go-nsq

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

抵扣说明:

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

余额充值