Prometheus教程四

一、配置Kubernetes借助于Prometheus-Adapter收集自定义指标,并由HPA v2基于自定义指标完成应用的自动扩缩容

# 部署prometheus以及相关监控组件
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl apply -f 1.monitoring-namespace.yaml 
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl apply -f 2.daemonset-deploy-cadvisor.yaml 
daemonset.apps/cadvisor created
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl apply -f 3.daemonset-deploy-node-exporter.yaml 
daemonset.apps/node-exporter created
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl apply -f 4.metrics-server-v0.5.2.yaml 
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl apply -f 5.1.prometheus-cfg.yaml 
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl create serviceaccount monitor -n monitoring
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl create clusterrolebinding monitor-clusterrolebinding -n monitoring --clusterrole=cluster-admin --serviceaccount=monitoring:monitor

[root@k8s-deployer ~]# mkdir -p /data/k8sdata/prometheus-data
[root@k8s-deployer prometheus-data]# chown -R 65534.65534 /data/k8sdata/prometheus-data
[root@k8s-deployer ~]# vim /etc/exports
/data/k8sdata/prometheus-data *(rw,no_root_squash)
[root@k8s-deployer prometheus-data]# systemctl restart nfs-server
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl apply -f 5.2.prometheus-deployment.yaml 
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl apply -f 5.3.prometheus-svc.yaml 
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl apply -f 6.1.myserver-namespace.yaml 
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl apply -f 6.2.sample-httpserver.yaml 
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl apply -f 6.3.sample-httpserver-svc.yaml 
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl apply -f 6.4.tomcat/1.tomcat-yaml/tomcat-deploy.yaml 
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl apply -f 6.4.tomcat/1.tomcat-yaml/tomcat-svc.yaml 


# 部署Prometheus-Adapter
[root@k8s-master1 adapter]# git clone -b release-0.10 https://github.com/kubernetes-sigs/prometheus-adapter.git
[root@k8s-master1 adapter]# cd prometheus-adapter/deploy
[root@k8s-master1 deploy]# ls
manifests  README.md
[root@k8s-master1 deploy]# export PURPOSE=serving
[root@k8s-master1 deploy]# openssl req -x509 -sha256 -new -nodes -days 365 -newkey rsa:2048 -keyout ${PURPOSE}.key -out ${PURPOSE}.crt -subj "/CN=ca"
Generating a 2048 bit RSA private key
........................................................................................................................................+++
..........................+++
writing new private key to 'serving.key'
-----
[root@k8s-master1 deploy]# echo '{"signing":{"default":{"expiry":"43800h","usages":["signing","key encipherment","'${PURPOSE}'"]}}}' > "${PURPOSE}-ca-config.json"
[root@k8s-master1 deploy]# kubectl -n monitoring create secret generic cm-adapter-serving-certs --from-file=./serving.crt --from-file=./serving.key
secret/cm-adapter-serving-certs created
[root@k8s-master1 deploy]# sed -i 's/namespace: custom-metrics/namespace: monitoring/g' manifests/*.yaml
[root@k8s-master1 deploy]# vim manifests/custom-metrics-apiserver-deployment.yaml 
[root@k8s-master1 deploy]# vim manifests/custom-metrics-config-map.yaml 
[root@k8s-master1 deploy]# kubectl apply -f manifests/
#验证custom-metrics-apiserver pod状态为running状
[root@k8s-master1 deploy]#  kubectl get pod -n monitoring
NAME                                        READY   STATUS    RESTARTS      AGE
cadvisor-9qbql                              1/1     Running   4 (18m ago)   12d
cadvisor-hzpb7                              1/1     Running   4 (18m ago)   12d
custom-metrics-apiserver-6d8b8f8769-stg9m   1/1     Running   0             40s
node-exporter-9stt4                         1/1     Running   3 (18m ago)   8d
node-exporter-kt7h8                         1/1     Running   3 (18m ago)   8d
prometheus-server-d7fcd9dd5-2l27z           1/1     Running   1 (18m ago)   28h

# HPA弹性伸缩测试,创建HPA控制器
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl apply -f 7.1.tomcat-hpa.yaml 
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl get pod -n myserver
NAME                                 READY   STATUS              RESTARTS   AGE
sample-httpserver-85f78fff6d-ms2mr   1/1     Running             0          25m
tomcat-deployment-5f664dd496-5mz85   1/1     Running             0          2m22s # 新扩容的
tomcat-deployment-5f664dd496-jpt56   1/1     Running             0          7m10s

在这里插入图片描述

# 当带宽消耗达到阈值的时候就会触发自动扩容
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# while true;do curl 172.18.10.102:31080/myapp/index.jsp;sleep 1 ;done
<h1>tomcat app1</h1>
<h1>tomcat app1</h1>
<h1>tomcat app1</h1>
<h1>tomcat app1</h1>
...
# 取消测试命令后验证

在这里插入图片描述

二、Prometheus基于VictoriaMetrics Cluster实现数据持久化

# 单机版部署
root@redis-1:/usr/local/src# tar -xvf victoria-metrics-amd64-v1.71.0.tar.gz 
root@redis-1:/usr/local/src# mv victoria-metrics-prod /usr/local/bin/
root@redis-1:/usr/local/src# vim /etc/systemd/system/victoria-metrics-prod.service
[Unit]
Description=For Victoria-metrics-prod Service
After=network.target

[Service]
ExecStart=/usr/local/bin/victoria-metrics-prod -httpListenAddr=0.0.0.0:8428 -storageDataPath=/data/victoria -retentionPeriod=3

[Install]
WantedBy=multi-user.target

root@redis-1:/usr/local/src# systemctl daemon-reload && systemctl restart victoria-metrics-prod.service 

在这里插入图片描述

# prometheus
root@redis-1:/usr/local/src# vim /apps/prometheus/prometheus/prometheus.yml 
remote_write:
  - url: http://172.18.10.141:8428/api/v1/write
root@redis-1:/usr/local/src# systemctl restart prometheus

在这里插入图片描述

grafana设置,添加数据源,类型为 prometheus,地址及端口为 VictoriaMetrics:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

# 官方 docker-compsoe
root@redis-1:/usr/local/src#  git clone https://github.com/VictoriaMetrics/VictoriaMetrics.git
root@redis-1:/usr/local/src#  cd VictoriaMetrics/deployment/docker/
# 验证
# 集群版部署
# 环境 172.18.10.142、172.18.10.143、172.18.10.144
# 分别在各个 VictoriaMetrics 服务器进行安装配置
root@node2:~# tar xf victoria-metrics-linux-amd64-v1.94.0-cluster.tar.gz 
root@node2:~# mv vminsert-prod vmselect-prod vmstorage-prod  /usr/local/bin/

# 部署 vmstorage-prod 组件:负责数据的持久化,监听端口:API 8482 ,数据写入端口:8400,数据读取端口:8401

root@redis-3:~# vim /etc/systemd/system/vmstorage.service
[Unit]
Description=Vmstorage Server
After=network.target

[Service]
Restart=on-failure
WorkingDirectory=/tmp
ExecStart=/usr/local/bin/vmstorage-prod -loggerTimezone Asia/Shanghai -storageDataPath /data/vmstorage-data -httpListenAddr :8482 -vminsertAddr :8400 -vmselectAddr :8401

[Install]
WantedBy=multi-user.target
root@redis-3:~# systemctl daemon-reload && systemctl restart vmstorage.service && systemctl enable vmstorage.service 
root@redis-3:~# scp /etc/systemd/system/vmstorage.service root@172.18.10.142:/etc/systemd/system/vmstorage.service
root@redis-3:~# scp /etc/systemd/system/vmstorage.service root@172.18.10.144:/etc/systemd/system/vmstorage.service

# 142和144执行
root@node2:~# systemctl daemon-reload && systemctl restart vmstorage.service && systemctl enable vmstorage.service
root@ubuntu-virtual-machine:~# systemctl daemon-reload && systemctl restart vmstorage.service && systemctl enable vmstorage.service

# 部署 vminsert-prod 组件  接收外部的写请求,默认端口 8480。
root@node2:~# vim /etc/systemd/system/vminsert.service
[Unit]
Description=Vminsert Server
After=network.target

[Service]
Restart=on-failure
WorkingDirectory=/tmp
ExecStart=/usr/local/bin/vminsert-prod -httpListenAddr :8480 -storageNode=172.18.10.142:8400,172.18.10.143:8400,172.18.10.144:8400

[Install]
WantedBy=multi-user.target

root@node2:~# systemctl daemon-reload && systemctl restart vminsert && systemctl enable vminsert 
root@node2:~# scp /etc/systemd/system/vminsert.service root@172.18.10.143:/etc/systemd/system/vminsert.service
root@node2:~# scp /etc/systemd/system/vminsert.service root@172.18.10.143:/etc/systemd/system/vminsert.service

# 143和144执行
root@redis-3:~# systemctl daemon-reload && systemctl restart vminsert && systemctl enable vminsert 
root@ubuntu-virtual-machine:~# systemctl daemon-reload && systemctl restart vminsert && systemctl enable vminsert 

# 部署 vmselect-prod 组件:
root@node2:~#  vim /etc/systemd/system/vmselect.service
[Unit]
Description=Vminsert Server
After=network.target
[Service]
Restart=on-failure
WorkingDirectory=/tmp
ExecStart=/usr/local/bin/vmselect-prod -httpListenAddr :8481 -storageNode=172.18.10.142:8401,172.18.10.143:8401,172.18.10.144:8401
[Install]
WantedBy=multi-user.target

root@node2:~#  systemctl daemon-reload && systemctl restart vmselect && systemctl enable vmselect

root@node2:~# scp /etc/systemd/system/vmselect.service root@172.18.10.143:/etc/systemd/system/vmselect.service  
root@node2:~# scp /etc/systemd/system/vmselect.service root@172.18.10.144:/etc/systemd/system/vmselect.service

# prometheus配置
remote_write:
  - url: http://172.18.10.142:8480/insert/0/prometheus
  - url: http://172.18.10.143:8480/insert/0/prometheus
  - url: http://172.18.10.144:8480/insert/0/prometheus
root@redis-1:~# systemctl restart prometheus

三、总结单体应用与微服务优缺点

单体应用的优点:
1)单体应用通常使用一个 jar/war 文件部署(如Jenkins),结构简单、部署也简单。
2)与微服务架构相比,单体应用程序的设计、开发与测试更加容易和简单。
3)与微服务设计相比,使用单体应用程序时网络延迟和安全问题相对较小(因为都是本机调用)。
单体应用的缺点:
1)随着时间的推移,单体应用程序会变得过于庞大并且变得难以管理。
2)即使是单独的更新也需要重新部署整个应用程序。
3)随着应用程序规模的增大,管理和部署的时间也会增加(200兆的Java单体服务启动要花费好几分钟)。
4)影响团队协作、新开发人员很难理解大型整体应用程序的逻辑。
5)某一个功能的扩展,需要部署整个程序。
6)稳定性不可控、一个功能出现异常,会影响当前APP的所有功能甚至崩溃。
7)横向扩展效率慢。

微服务应用的缺点:
1)微服务通常是一个分布式服务,架构设计较难。
2)网络通信延迟比单体应用高。
3)跨主机通信的安全性问题。
4)故障排查、日志收集和监控相对复杂。
微服务应用的优点:
1)单个服务体积小,部署效率快、启动速度快、几乎秒级启动。
2)方便后期快速横向扩容。
3)如果要更新一个功能,那么只更新对应的APP即可。
4)不同的功能可以使用不同的数据库,方便分库分表。
5)只要提前定义好接口调用方式、每个应用可以使用不同的开发语言。
6)单个服务的宕机对整体业务影响较低。
7)开发者只需要维护自身的应用代码,甚至对其他服务可以完全不用关注。
8)去中心化,不依赖于任何一个中心服务。

四、总结服务的注册机发现机制、实现微服务的几个要素

服务的注册机发现机制:
容器化服务启动后,把信息注册到注册中心,消费服务会订阅注册中心,从中拿到地址信息,之后进行调用,监控组件做微服务的监控个管理。

实现微服务的要素:
1)微服务如何落地(容器化、容器编排工具)
2)微服务之间如何发现对方(注册中心、服务发现)
3)微服务之间如何访问对方(服务访问-> resetfulAPI)
4)微服务如何快速扩容(服务治理)
5)微服务如何监控(服务监控)
6)微服务如何升级与回滚(CI/CD)
7)微服务访问日志如何查看(ELK)

五、总结消息分发系统发展历史及对比、消息分发机制;

发展历史:
Message Queue的需求由来已久,最初的Message queuing软件叫做(the information
bus(TIB),后来IBM公司开发了MQSeries,微软也开发了MSMQ,但是价格昂贵,2004年摩根大通和iMatrix开始着手Advanced Message Queuing Protocol (AMQP)开放标准的开发,2006年,AMQP规范发布,2007年,
Rabbit技术公司基于AMQP标准开发的RabbitMQ 1.0 发布。
Java Message Service (JMS)规范首次发布于1998年,是一个Java平台中关于面向消息中间件(MOM,message oriented middleware)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信,Java消息服务应用程序结构支持两种模型:点对点或队列模型、发布/订阅模型。
MQ(Message queuing):消息队列的目的是为了实现各个APP之间的通讯,APP基于MQ实现消息的发送和接收实现应用程序之间的通讯,这样多个应用程序可以运行在不同的主机上,通过MQ就可以实现夸网络通信,因此MQ实现了业务的解耦和异步机制。

消息系统对比:

特性ActiveMQRabbitMQRocketMQKafka
单机吞吐量万级,比 RocketMQ、Kafka 低一个数量级万级,比 RocketMQ、Kafka低一个数量级10 万级,支撑高吞吐10 万级,高吞吐,一般配合大数据类的系统来进行实时数据计算、日志采集等场景
topic 数量对吞吐量的影响topic 可以达到几百/几千的级别,吞吐量会有较小幅度的下降,这是 RocketMQ 的一大优势,在同等机器下,可以支撑大量的 topictopic 从几十到几百个时候,吞吐量会大幅度下降,在同等机器下,Kafka 尽量保证 topic 数量不要过多,如果要支撑大规模的 topic,需要增加更多的机器资源
时效性ms 级微秒级,这是RabbitMQ 的一大特点,延迟最低ms 级延迟在 ms 级以内
可用性高,基于主从架构实现高可用高,基于主从架构实现高可用非常高,分布式架构非常高,分布式,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用
消息可靠性有较低的概率丢失数据主从环境保证消息高可用经过参数优化配置,可以做到 0丢失经过参数优化配置,可以做到 0 丢失
功能支持MQ 领域的功能非常完成MQ 领域的功能非常完成MQ 功能较为完善功能较为简单,主要支持简单的 MQ功能,在大数据领域的实时计算以及日志采集被大规模使用

消息分发机制:JMS模型
点对点或队列模型,也叫生产者消费者模型,生产者向消息队列发送消息,但是只有一个消费者可以消费,基于异步机制发型消息,同时消息有确认机制,确保消息可以成功发送及消费。
发布/订阅模型:发布者发送消息到消息队列中,订阅改队列的多个消费者都可以消费,在发布者和订阅者之间存在时间依赖性,既已经发送的过的消息,后续新启动的消费者将无法消费。

六、总结Kafka简介及优缺点、Kafka逻辑架构详解

消息队列特点:
1)削峰填谷(主要解决瞬时写压力大于应用服务能力导致消息丢失、系统奔溃等问题)
2)系统解耦(解决不同重要程度、不同能力级别系统之间依赖导致一死全死)
3)提升性能(当存在一对多调用时,可以发一条消息给消息系统,让消息系统通知相关系统)
4)蓄流压测(线上有些链路不好压测,可以通过堆积一定量消息再放开来压测
5)FIFO机制:基于FIFO(first in first out,先进先出)机制保证业务消息的顺序处理

kafka简介:
	kafka被称为下一代的分布式消息系统,是apache基金会开源软件。具有高吞吐量,即使是普通硬件也可以支持每秒上百万的消息。kafka通过O(1)的磁盘结构提供消息的持久化,这种结构对于TB级别的消息存储也能够保持长时间的稳定性能。kafka支持分区消息,再Hadoop等大数据环境被广泛使用。

kafka逻辑架构详解:
	Producer:生产者,负责发布消息到Kafka broker。
	Consumer:消费者,消费消息,每个consumer属于一个特定的consuer group(可为每个consumer指定group name,若不指定group name则属于默认的group),使用consumer high level API时,同一topic的一条消息只能被同一个consumer group内的一个consumer消费,但多个consumer group可同时消费这一消息。
	Broker:Kafka集群包含一个或多个服务器,这种服务器被称为broker。
	Topic :每条发布到Kafka集群的消息都有一个类别,这个类别被称为topic,(物理上不同topic的消息分开存储在不同的文件夹,逻辑上一个topic的消息虽然保存于一个或多个broker上但用户只需指定消息的topic即可生产或消费数据而不必关心数据存于何处),topic在逻辑上对record(记录、日志)进行分组保存,消费者需要订阅相应的topic才能消费topic中的消息。
	Partition :是物理上的概念,每个topic包含一个或多个partition,创建topic时可指定parition数量,每个partition对应于一个文件夹,该文件夹下存储该partition的数据和索引文件,为了实现实现数据的高可用,比如将分区0的数据分散到不同的kafka节点,每一个分区都有一个broker作为leader和一个broker作为Follower。

kafka选举简介:
	kafka有两种集群管理方式(不能同时使用):
	1)基于zookeeper进行集群角色管理
	2)基于Raft算法改进的kfaft进行集群角色管理,使用Raft的还有Consul、InfluxDB、etcd等。
Raft节点角色:集群中每个节点只能处于 Leader、Follower 和 Candidate 三种状态的一种
	Leader:主节点,类似于redis的master
	Follower:追随者,类似于redis cluster中的slave节点
	Candidate:候选节点,只存在于选举过程中。
节点启动后基于termID(任期ID)进行相互投票,termID是一个整数默认值为0,在Raft算法中,一个term代表leader的一段任期周期,每当一个节点成为leader时,就会进入一个新的term, 然后每个节点都会在自己的term ID上加1,以便与上一轮选举区分开来。

配置详解:
Process.Roles:
	如果Process.Roles = Broker, 服务器在KRaft模式中充当 Broker角色。
	如果Process.Roles = Controller, 服务器在KRaft模式下充当 Controller角色
	如果Process.Roles = Broker,Controller,服务器在KRaft模式中同时充当 Broker 角色和Controller角色。
	如果process.roles 没有设置,那么集群就假定是运行在ZooKeeper模式下。

Kafka 分区与 Leader 选举规则:
	分区中的所有副本的累计列表统称为AR(Assigned Repllicas)
Topic: myserver8 Partition: 0 Leader: 102 Replicas: 102,103,101 Isr: 102,103,101
Topic: myserver8 Partition: 1 Leader: 103 Replicas: 103,101,102 Isr: 103,101,102
Topic: myserver8 Partition: 2 Leader: 101 Replicas: 101,102,103 Isr: 101,102,103
	所有与leader保持同步的副本(包括Leader)组成一组ISR(In-Sync Replicas),ISR集合是AR集合中的一个子集。
	与leader同步延迟过多的副本(不包括leader),组成了OSR(Out-Sync Relipcas),由此可见:AR=ISR+OSR,但是在在正常情况下,所有的follower副本都应该与leader副本保持尽可能的同步,即正常情况下AR=ISR, 而OSR集合通常没有(即使宕机、只要还有主机资源很快就会自动修复)
	在 ISR 中存活的副本为前提, 按照 AR 中排在前面的优先 。 例如 AR[ 101,102,103], ISR [ 101,102,103], 那么 Leader 就会按照 101,102,103 的顺序轮询。

zk与kraft模式对比:

场景ZK模式问题kraft模式
Controller故障转移控制器赢得选举后,它会获取所有主题和分区,并将LeaderAndISR和UpdateMetaData发送给所有broker节点假设有一个包含大量分区的大型kafka集群,此过程可能需要很长时间,并且在此期间集群将不可用使用 KRaft 模式,一旦控制器赢得选举,它就会开始从代理获取请求,因此无需等待时间即可再次加载所有主题等
节点重启滚动节点启动时期内当前节点没有元数,只有在重启完成并重新获取所有元数据后才可用当集群中有很多可用分区时,获取元数据可能会花费更长的时间,这将导致节点在一段时间内不可用使用 KRaft 模式,滚动更新过程中节点只需要获取本地缓存中没有的元数据,它使用元数据偏移量来做到实现元数据的更新
Zookeeper 依赖需同时部署Kafka 和 ZooKeeper 是两种不同的服务,因此为了管理 Kafka 集群,我们还需要额外运行并管理zookeeper集群需要关注zookeeper的状态,比如为了保证zk集群的安全,还必须为Zookeeper 设置安全、监控等通过KRaft模式,Kafka已经标准化不再依赖Zookeeper来存储元数据,因此不需要部署和管理zookeeper集群
可扩展架性在 ZooKeeper 模式下,Kafka 必须将其元数据存储在 zNode 中,每次集群启动或控制器选举发生时,Kafka控制器都必须从Zookeeper服务读取所有元数据,效率比较低获取所有元数据期间kafka集群不可用,无法支持大规模的topic信息(超过一定分片后集群会变慢)动态横向扩展,kafka node只需要更新本地没有的元数据,支持的分片更多
易用性需要时部署和维护zookeeper及kafka需要额外学习zookeeper相关知识只需要维护kafka集群即可

七、基于kafka实现生产者与消费者的消息发送与接收(上课演示的python脚本)

[root@k8s-harbor 1.prometheus-case-files]# git clone https://gitee.com/jiege-gitee/kafka.git
[root@k8s-harbor kafka]# docker-compose up -d

root@redis-1:~/pydir# cat myserver-KafkaConsumer.py 
#/usr/bin/env python3
#coding=utf-8
#pip3 install --index-url https://mirrors.aliyun.com/pypi/simple/ kafka-python

from kafka import KafkaConsumer

conn = KafkaConsumer('myserver',bootstrap_servers=['172.18.10.130:9092','172.18.10.130:9092','172.18.10.130:9092'])
for message in conn:
    print ("%s:%d:%d: key=%s value=%s" % (message.topic, message.partition,
    message.offset, message.key,message.value))
conn.close()root@redis-1:~/pydir# cat myserver-KafkaProducer.py 
#/usr/bin/env python3
#coding=utf-8 
#pip3 install --index-url https://mirrors.aliyun.com/pypi/simple/ kafka-python

from kafka import KafkaProducer
conn = KafkaProducer(bootstrap_servers=['172.18.10.130:9092','172.18.10.130:9092','172.18.10.130:9092'],compression_type='gzip')
conn.send('foobar', key=b'foo', value=b'bar')
for i in range(3):
    msg = "msg%d" % i
    #conn.send('myserver', msg)
    conn.send('myserver',key=b'myserver-key', value=b'msg%d' % i)
    print('topic-->myserver: msg%d发送成功!' % i)

root@redis-1:~/pydir# apt install python3-pip
root@redis-1:~/pydir# pip3 install --index-url https://mirrors.aliyun.com/pypi/simple/ kafka-python
root@redis-1:~/pydir# python3 myserver-KafkaConsumer.py # 消费者
root@redis-1:~/pydir# python3  myserver-KafkaProducer.py  # 生产者

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值