linux 守护进程:PM2、systemd、Forever、Daemontools、supervisor

linux 进程工具


 

1、什么是守护进程

守护进程(Daemon Process),也就是通常说的 Daemon 进程(精灵进程),是 Linux 中的后台服务进程。它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。

守护进程是个特殊的孤儿进程,这种进程脱离终端,为什么要脱离终端呢?之所以脱离于终端是为了避免进程被任何终端所产生的信息所打断,其在执行过程中的信息也不在任何终端上显示。由于在 Linux 中,每一个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依附于这个终端,这个终端就称为这些进程的控制终端,当控制终端被关闭时,相应的进程都会自动关闭。

在生产环境的,有些任务是不能停止的,否则业务就会受到影响,那么如何保证这些任务的高可用呢?那就需要用到我们的守护进程了,比方说我们的进程运行挂掉之后自动恢复等等,这些都可以利用工具来实现,针对不同的项目可以使用不同的工具。

Linux 的大多数服务器就是用守护进程实现的。比如,Internet 服务器 inetd,Web 服务器 httpd 等。

linux 常用的守护进程软件:PM2、systemd、Forever、 Daemontools、Python底层写的 supervisor 等等。

2、linux 常用的守护进程软件

PM2

文档:https://pm2.keymetrics.io/docs/usage/quick-start/

pm2 是一款守护进程管理工具,可以用来管理和守护应用程序,包括启动、停止、重启、开机启动应用进程等。进程状态的监控和守护,对应用服务来说非常重要。业务应用一般运行在服务器上,不可能人工时刻值守。如果应用出现异常错误,可能会使整个进程崩溃,导致业务服务中断。守护进程可以代替人,实现实时值守、自动重启。使用pm2,可以很方便地完成前、后端应用服务的部署、管理和守护。省时省力,堪称神器!

pm2 基于Node.js开发,需要Node.js运行环境。
pm2支持Linux、MacOS、Windows等多种平台。
pm2 不仅可以守护Node应用,也可以守护Java、Python等多种其他类型的应用进程。

安装:npm install -g pm2。(-g选项采用全局安装,这之后,就可以直接使用pm2命令)。
升级:pm2 update

管理进程状态

https://pm2.keymetrics.io/docs/usage/process-management/

pm2 可以启动 js 脚本,也可以启动其他应用。如果需要传入启动参数,可以使用 -- 选项(注意中间的空格)。

pm2 一些常用的管理命令

pm2 start [options] 启动指定应用。
        示例:pm2 start index.js --name httpServer;   配置应用名称为 httpServer
              pm2 start app.js
              pm2 start java -- -jar app.jar
              pm2 start npm -- run dev
停止指定应用:pm2 stop <id|name|namespace|all|json|stdin...>  
        示例:pm2 stop httpServer;
重启指定应用:pm2 reload|restart <id|name|namespace|all|json|stdin...> 
        示例:pm2 restart httpServer;
删除指定应用:pm2 delete <id|name|namespace|script|all|json|stdin...>
        如果修改应用配置行为,最好先删除应用后,重新启动。
        示例:pm2 delete httpServer
显示指定应用:pm2 show [options]  示例:pm2 show httpServer;

pm2 list   可以展示应用的名称、进程ID、命名空间、状态(status)等信息。
pm2 kill   杀掉 pm2 管理的所有进程;
pm2 logs   查看指定应用的日志,即标准输出和标准错误;
pm2 monit  监控各个应用进程cpu和memory使用情况;

更多的操作方法,可以查看 pm2 --help 获取

pm2 常用配置

pm2 配置方式有如下两种:

  • 命令行方式。示例:pm2 start index.js --name HttpServer --interpreter node   此处通过命令的选项配置应用名称为httpServer,index.js脚本文件解释器为node,更多选项可查看pm2 --help获取;
  • 配置文件方式。pm2 配置文件方式支持 yml 与 json 格式

processes.yml 文件

processes.json

配置项

name 应用进程名称;

script 启动脚本路径;

cwd 应用启动的路径,关于script与cwd的区别举例说明:在/home/polo/目录下运行/data/release/node/index.js,此处script为/data/release/node/index.js,cwd为/home/polo/;

  • args 传递给脚本的参数;
  • interpreter 指定的脚本解释器;
  • interpreter_args 传递给解释器的参数;
  • instances 应用启动实例个数,仅在cluster模式有效,默认为fork;
  • exec_mode 应用启动模式,支持fork和cluster模式;
  • watch 监听重启,启用情况下,文件夹或子文件夹下变化应用自动重启;
  • ignore_watch 忽略监听的文件夹,支持正则表达式;
  • max_memory_restart 最大内存限制数,超出自动重启;
  • env 环境变量,object类型,如{"NODE_ENV":"production", "ID": "42"};
  • log_date_format 指定日志日期格式,如YYYY-MM-DD HH:mm:ss;
  • error_file 记录标准错误流,$HOME/.pm2/logs/XXXerr.log),代码错误可在此文件查找;
  • out_file 记录标准输出流,$HOME/.pm2/logs/XXXout.log),如应用打印大量的标准输出,会导致pm2日志过大;
  • min_uptime 应用运行少于时间被认为是异常启动;
  • max_restarts 最大异常重启次数,即小于min_uptime运行时间重启次数;
  • autorestart 默认为true, 发生异常的情况下自动重启;
  • cron_restart crontab时间格式重启应用,目前只支持cluster模式;
  • force 默认false,如果true,可以重复启动一个脚本。pm2不建议这么做;
  • restart_delay 异常重启情况下,延时重启时间;

下面是结合自己实践中遇到的一些坑做的思考总结。

fork 与 cluster 启动模式

pm2启动进程的支持两种模式:fork与cluster,对于了解node的人知道,node的多进程编程api: child_process.fork与cluster。关于pm2的fork与cluster两者的本质区别,个人认为就是node API的child_process.fork与cluster的区别,stackoverflow有关于这个问题的讨论 http://stackoverflow.com/questions/34682035/cluster-and-fork-mode-difference-in-pm2。下面做个粗浅的归纳:cluster是fork的派生,cluster支持所有cluster拥有的特性;

fork不支持socket地址端口复用,cluster支持地址端口复用。因为只有node的cluster模块支持socket选项SO_REUSEADDR;

fork不可以启动多个实例进程,cluster可以启动多个实例。但node的child_process.fork是可以实现启动多个进程的,但是为什么没有实现呢?就个人理解,node多为提供网络服务,启动多个实例需要地址端口复用,此时便可使用cluster模式实现,但fork模式并不支持地址端口复用,多实例进程启动会产生异常错误。但对于常驻任务脚本而言,不需要提供网络服务,此时多进程启动可以实现,同时也提高了任务处理效率。对于上述需求,可以两种方式实现,一是配置app0,app1,app2方式启动多个进程,二是通过应用实例自身调用child_process.fork多进程编程实现;

fork 模式可以应用于其他语言,如php,python,perl,ruby,bash,coffee, 而cluster只能应用于node,fork不支持定时重启,cluster支持定时重启。定时重启也就是配置中的cron_restart配置项。

官网文档注明说,fork模式的定时重启这个功能不久将实现,期待中吧... ...

pm2的监控

pm2的监控有两种方式:

cli方式监控。pm2 monit 是专门用来监控的命令,监控项包括cpu与内存。缺点是 monit 展示内容太过粗糙,不够详细。pm2 list展示当前所有pm2的管理项目,可以查看出每个进程的运行状态。

daemontools

官网安装 ( 很简陋,但很有用 ):https://cr.yp.to/daemontools/install.html

daemontools 是一款 unix 服务管理软件,提供一组工具来进行管理用户的一系列进程。Daemontools 包含 svscanboot,svscan,supervise,svc,svok,svstat 等一系列工具。daemontools 主要有一下特点:

  • 增加删除 service:只需要在 /service 中删除或增加 link 即可
  • 快速启动:在 /service 中增加服务, 即可自动在五秒内完成启动
  • 可靠重启:service down 掉之后,自动重启
  • 简单可靠的控制:配置好 /service 之后, 使用 svc 命令,可以控制 service daemon。
  • 干净的进程状态:重启的 service 进程,跟第一次启动的一样干净,纯洁无暇
  • 可移植:通过配置 /service,程序能在各个 linux 系统(Linux, BSD, Solaris, etc)上,按相同的方式运行

安  装

新建 文件夹
        mkdir -p /package
        chmod 1755 /package
        cd /package
下载 Daemontools 然后解压
        gunzip daemontools-0.76.tar
        tar -xpf daemontools-0.76.tar
        rm -f daemontools-0.76.tar
        cd admin/daemontools-0.76
安装
        package/install

        装完后,会自动创建会创建两个目录,分别是 /service 和 /command

安装报错:/usr/bin/ld: errno: TLS definition in /lib64/libc.so.6 section .tbss mismatches non-TLS reference in envdir.o

解决方法:vim src/conf-cc ,在 gcc  这一行末尾增加 -include /usr/include/errno.h

在 /service 目录下添加一个文件夹(或者创建软连接),然后再在其中创建 run 可执行文件,并在run 文件中设置自己想启动的服务就可以了,写好 run 服务之后,daemontools 会自动发现并且启动起来。

示例:run 文件,输出1-49

#!/bin/bash

for i in {1..49}
do
	echo $i >> test.log
done

可以直接使用 supervise 来对进程保护:

  • 1)创建run脚本,启动你的服务;
  • 2)创建start.sh脚本,内容:

使用 suerpvise 来启动你的服务,supervise 会自动找到 run 脚本( start.sh脚本中表示run和start.sh在同一个目录 )

安装后 svscanboot 不能正常启动问题。

1) 按照官方说明,在安装完成后,会自动增加到 /etc/init.tab中 , 增加自动启动功能, 代码如下, 但是重启后发现程序并未拉起,daemotool 服务不能正常使用

官方解释参考。开机启动说明:https://cr.yp.to/daemontools/start.html

cat /etc/inittab
id:5:initdefault:
SV:123456:respawn:/command/svscanboot

2) 解决, 参考官方说明

vim /etc/init/svscan.conf
#增加以下命令以支持自启动
start on runlevel [12345]
stop on runlevel [^12345]
respawn
exec /command/svscanboot
 
#加载配置文件,并启动(不需要重启机器)
initctl reload-configuration
initctl start svscan

服务异常被拉起

 "#!/bin/sh" 必须放在 run 文件的第一行,否则 daemontool 启动时执行错误, 进程会不断被拉起。

[root@centosx1 prometheus.service]# svstat /service/prometheus.service/
/service/prometheus.service/: up (pid 6449) 0 seconds
[root@centosx1 prometheus.service]#
[root@centosx1 prometheus.service]#
[root@centosx1 prometheus.service]# svstat /service/prometheus.service/
/service/prometheus.service/: up (pid 6452) 0 seconds
[root@centosx1 prometheus.service]#
[root@centosx1 prometheus.service]#
[root@centosx1 prometheus.service]# svstat /service/prometheus.service/
/service/prometheus.service/: up (pid 6455) 0 seconds
[root@centosx1 prometheus.service]#
[root@centosx1 prometheus.service]# svstat /service/prometheus.service/
/service/prometheus.service/: up (pid 6458) 0 seconds

帮 助

安装 daemontools
升级 daemontools
经常被问的问题

怎么开始 daemontools
The svscanboot program
The svscan program
The supervise program
The svc program
The svok program
The svstat program
The fghack program
The pgrphack program

The readproctitle program
The multilog program
The tai64n program
The tai64nlocal program

The setuidgid program
The envuidgid program
The envdir program
The softlimit program
The setlock program

示 例:

建立测试文件 /test/test.py

import time

index = 1

while True:
    print(f'index ---> {index}')
    index += 1
    time.sleep(1)
pass

然后建立 "目录的软连接" 到 /service 下。执行:sudo ln -s /test .

软连接建立后,就可以启动,然后进行验证

进入 /service 目录,执行:sudo svc -u ./ 即启动当前目录下的服务。

要停止服务使用 -d 参数:sudo svc -d ./

该命令还支持以下参数:

  • -u : up, 如果services没有运行的话,启动它,如果services停止了,重启它。 
  • -d : down, 如果services正在运行的话,给它发送一个TERM(terminate)信号,然后再发送一个CONT(continue)信号,在它停止后,不再启动它。 
  • -o : once, 如果services没有运行,启动它,但是在它停止后不再启动了。就是只运行一次。 
  • -p : pause, 给services发送一个停止信号。 
  • -c : continue, 给services发送一个CONT信号。 
  • -h : hang up, 给services发送一个HUP信号。 
  • -a : alarm, 给services发送一个ALRM信号。 
  • -i : interrupt, 给services发送一个INT信号。 
  • -t : Terminate, 给services发送一个TERM信号。 
  • -k : kill, 给services发送一个KILL信号。 
  • -x : exit, supervise在services停止后会立刻退出, 但是值得注意的是,如果你在一个稳定的系统中使用了这个选项,你已经开始犯错了:supervise被设计成为永远运行的。 

最常用的还是 -d、-u ,毕竟组合起来就是重启,重启大法好

supervisor

Supervisor 安装与配置(linux/unix进程管理工具) Supervisor(http://supervisord.org/)是用 Python开发的一个 client/server 服务,是 Linux/Unix 系统下的一个进程管理工具,不支持 Windows 系统。它可以很方便的监听、启动、停止、重启一个或多个进程。用Supervisor管理的进程,当一个进程意外被杀死,supervisort 监听到进程死后,会自动将它重新拉起,很方便的做到进程自动恢复的功能,不再需要自己写shell脚本来控制。

因为 Supervisor 是 Python 开发的,安装前先检查一下系统否安装了 Python

安装 Supervisor

Debian / Ubuntu 可通过 apt 安装:sudo apt-get install supervisor
yum 安装:yum install supervisor
pip 安装:pip install supervisor
easy_install 安装:easy_install supervisor

supervisor 安装完成后会生成三个执行程序:

  • supervisortd:用于管理 supervisor 本身服务
  • supervisorctl:用于管理我们需要委托给 superviso 工具的服务
  • echo_supervisord_conf:用于生成 superviso 的配置文件

supervisor 的守护进程服务(用于接收进程管理命令)

客户端(用于和守护进程通信,发送管理进程的指令)

[root@Jumpserver /]# which supervisord
/bin/supervisord
[root@Jumpserver /]# which supervisorctl
/bin/supervisorctl
[root@Jumpserver /]# which echo_supervisord_conf
/bin/echo_supervisord_conf

配置 Supervisor

Supervisor 基础配置可以在 /etc/supervisor/supervisord.conf 进行配置
任务配置通常存放在 /etc/supervisor/conf.d 目录,在该目录下,
可以创建多个配置文件指示 Supervisor 如何监视进程

supervisor.conf 说明

[unix_http_server]
file=/tmp/supervisor.sock   ;UNIX socket 文件,supervisorctl 会使用
;chmod=0700                 ;socket文件的mode,默认是0700
;chown=nobody:nogroup       ;socket文件的owner,格式:uid:gid
 
;[inet_http_server]         ;HTTP服务器,提供web管理界面
;port=127.0.0.1:9001        ;Web管理后台运行的IP和端口,如果开放到公网,需要注意安全性
;username=user              ;登录管理后台的用户名
;password=123               ;登录管理后台的密码
 
[supervisord]
logfile=/tmp/supervisord.log ;日志文件,默认是 $CWD/supervisord.log
logfile_maxbytes=50MB        ;日志文件大小,超出会rotate,默认 50MB,如果设成0,表示不限制大小
logfile_backups=10           ;日志文件保留备份数量默认10,设为0表示不备份
loglevel=info                ;日志级别,默认info,其它: debug,warn,trace
pidfile=/tmp/supervisord.pid ;pid 文件
nodaemon=false               ;是否在前台启动,默认是false,即以 daemon 的方式启动
minfds=1024                  ;可以打开的文件描述符的最小值,默认 1024
minprocs=200                 ;可以打开的进程数的最小值,默认 200
 
[supervisorctl]
serverurl=unix:///tmp/supervisor.sock ;通过UNIX socket连接supervisord,路径与unix_http_server部分的file一致
;serverurl=http://127.0.0.1:9001 ; 通过HTTP的方式连接supervisord
 
;包含其它配置文件 
[include]
files = /etc/supervisor/conf.d/*.conf    ;这里也就是包含了我们的任务配置

1、通过运行 echo_supervisord_conf 程序生成 supervisor 的初始化配置文件

如果使用 yum 安装则此步骤省略,直接进行修改配置文件步骤
mkdir /etc/supervisord.d
echo_supervisord_conf > /etc/supervisord.conf

2、修改配置文件

supervisor 的配置文件内容有很多,不过好多都不需要修改就行使用,我这里只修改了以下两项
#修改socket文件的mode,默认是0700
sed -i 's/;chmod=0700/chmod=0766/g' /etc/supervisord.conf   
#在配置文件最后添加以下两行内容来包含/etc/supervisord目录
sed -i '$a [include] \
files = /etc/supervisord.d/*.conf' /etc/supervisord.conf

示例:管理 redis

应用如果需要被 Supervisor 管理,就需要在/etc/supervisord目录下编写配置文件

redis 默认不在配置文件中添加daemonize yes参数则是前台启动的,所以也可以被我们的的Supervisor所管理 redis 配置文件如下:

cat redis6001.conf
port 6001
bind 192.168.31.230
protected-mode yes
pidfile "/usr/local/redis/run/redis6001.pid"
loglevel notice
logfile "/usr/local/redis/logs/redis6001.log"
save 900 1
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum  yes
dbfilename dump.rdb
dir "/usr/local/redis/data/rdb/"
timeout 0
tcp-keepalive 300

编写 redis 被 Supervisor 管理的案例

vim /etc/supervisord.d/redis.conf
[program:redis]
directory=/usr/local/redis
command=/usr/local/redis/bin/redis-server /usr/local/redis/etc/redis6001.conf
autostart=true
startsecs=10
autorestart=true
startretries=3
user=root
priority=999
stopsignal=INT
redirect_stderr=true
stdout_logfile_maxbytes=200MB
stdout_logfile_backups = 100
stdout_logfile=/usr/local/redis/logs/redis6001.log
stopasgroup=false
killasgroup=false

使用 super 启动 redis

#关闭tomcat
supervisorctl stop tomcat
tomcat: stopped

#杀掉supervisord
ps -ef|grep supervisord
root     26927     1  0 10:47 ?        00:00:00 /usr/bin/python /bin/supervisord -c /etc/supervisord.conf
root     27549 27402  0 11:07 pts/2    00:00:00 grep --color=auto super
kill -9 26927

#重新启动supervisord使其重新加载配置文件,supervisord默认会把redis和tomcat都拉起来
supervisord -c /etc/supervisord.conf

程序管理

supervisorctl status redis                              #redis状态
supervisorctl stop redis                                #停止redis
supervisorctl start redis                               #启动redis
supervisorctl restart reids                             #重启redis
supervisorctl reoload redis                             #重载redis

示例:管理 Nginx

Supervisor 只能管理非 Daemon 进程,Nginx 默认是 Daemon 进程,所以需要配置为 非 Daemon

[program:nginx] #  设置进程的名称,使用 supervisorctl 来管理进程时需要使用该进程名 我这里就叫做nginx了!
command=/usr/sbin/nginx -g 'daemon off;' # 需要执行的命令。配置为 非Daemon进程
directory=/etc/nginx # 命令执行的目录或者说执行 command 之前,先切换到工作目录 可以理解为在执行命令前会切换到这个目录 在我这基本没啥用
autostart=true #是否自动启动
autorestart=true #程序意外退出是否自动重启
redirect_stderr=true # 如果为true,则stderr的日志会被写入stdout日志文件中  理解为重定向输出的日志
priority=10 # 启动优先级
stdout_logfile=/data/logs/supervisord/nginx.log # 子进程的stdout的日志路径 输出日志文件
stderr_logfile=/data/logs/supervisord/nginx.err.log # 错误日志文件 当redirect_stderr=true。这个就不用

最终配置 /etc/supervisor/conf.d/nginx.conf

[program:nginx]
command=/usr/sbin/nginx -g 'daemon off;'
directory=/etc/nginx
autostart=true
autorestart=true
redirect_stderr=true
priority=10
stdout_logfile=/data/logs/supervisord/nginx.log

修改后更新 Supervisor

supervisorctl reread # 重新读取配置
supervisorctl update # 更新配置
supervisorctl restart nginx  # 重启 nginx
killall nginx  # 杀掉所有的 nginx 进程. 已经杀不死了 说明守护进程配置成功

查看任务:supervisorctl status

程序  管理

supervisorctl status all                            #查看所有进程状态
supervisorctl stop   all                            #停止所有进程
supervisorctl start  all                            #启动所有进程
supervisorctl restart all                           #重启所有进程
supervisorctl reoload all                           #重载所有进程

Supervisord 开启启动配置

vim /usr/lib/systemd/system/supervisord.service
[Unit]
Description=Process Monitoring and Control Daemon
After=rc-local.service nss-user-lookup.target

[Service]
Type=forking
ExecStart=/usr/bin/supervisord -c /etc/supervisord.conf

[Install]
WantedBy=multi-user.target


systemctl enable supervisord
systemctl is-enabled supervisord

systemd

systemd 是目前Linux系统上主要的系统守护进程管理工具,由于init一方面对于进程的管理是串行化的,容易出现阻塞情况,另一方面init也仅仅是执行启动脚本,并不能对服务本身进行更多的管理。所以从CentOS 7开始也由systemd取代了init作为默认的系统进程管理工具。

systemd 所管理的所有系统资源都称作Unit,通过systemd命令集可以方便的对这些Unit进行管理。比如:systemctl、hostnamectl、timedatectl、localctl 等命令,这些命令虽然改写了init 时代用户的命令使用习惯(不再使用 chkconfig、service 等命令),但确实也提供了很大的便捷性。

systemd 语法

systemctl [command]      [unit](配置的应用名称)
command可选项
        start:启动指定的unit          systemctl start nginx
        stop:关闭指定的unit           systemctl stop nginx
        restart:重启指定unit          systemctl restart nginx
        reload:重载指定unit           systemctl reload nginx
        enable:开机时自动启动指定unit (配置文件中有相关配置)  systemctl enable nginx
        disable:开机时不自动运行指定unit   systemctl disable nginx
        status:查看指定unit当前运行状态 systemctl status nginx

systemd 配置文件说明:

  • 每一个Unit都需要有一个配置文件用于告知systemd对于服务的管理方式
  • 配置文件存放于 /usr/lib/systemd/system/,设置开机启动后会在 /etc/systemd/system 目录建立软链接文件
  • 每个Unit的配置文件配置默认后缀名为.service
  • 在/usr/lib/systemd/system/目录中分为system和user两个目录,一般将开机不登陆就能运行的程序存在系统服务里,也就是/usr/lib/systemd/system
  • 配置文件使用方括号分成了多个部分,并且区分大小写

示例:

启动 nginx
        /usr/local/nginx/sbin/nginx  #启动
        /usr/local/nginx/sbin/nginx  -s reload  #重启
        /usr/local/nginx/sbin/nginx -s   quit   #关闭nginx

systemd 管理控制启动模式
        vim /usr/lib/systemd/system/nginx.service
        [Unit]
        Description=nginx
        After=network.target
          
        [Service]
        Type=forking
        ExecStart=/usr/local/nginx/sbin/nginx
        ExecReload=/usr/local/nginx/sbin/nginx -s reload
        ExecStop=/usr/local/nginx/sbin/nginx -s quit
        PrivateTmp=true
          
        [Install]
        WantedBy=multi-user.target
参数详解
        systemctl restart nginx
        systemctl enable  nginx
        systemctl stop  nginx

forever

forever可以看做是一个 nodejs 的守护进程,能够启动,停止,重启我们的 app 应用。forever 的用途就是帮我们更好的管理 node App 服务,本质上就是在 forever 进程之下,创建一个node app 的子进程。

安装 forever,记得加 -g,forever 要求安装到全局环境下:npm install forever -g

安装完成后,cd 进入需要启动的 node 程序,使用 forever start xx.js 启动程序即可。

start [程序名]     启动程序
stop [程序名]    关闭程序
list             查看所有已启动的程序

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值