Upsync介绍,以及基于 consul + upsync 的动态upstream管理

http://www.yunweipai.com/archives/16211.html

       Upsync是新浪微博开源的基于Nginx实现动态配置的三方模块。Nginx-Upsync-Module的功能是拉取Consul的后端server的列表,并动态更新Nginx的路由信息。此模块不依赖于任何第三方模块。Consul作为Nginx的DB,利用Consul的KV服务,每个Nginx Work进程独立的去拉取各个upstream的配置,并更新各自的路由。

Upsync模块工作原理

        在Nginx的设计中,每一个upstream维护了一张静态路由表,存储了backend的ip、port以及其他的meta信息。每次请求到达后,会依据location检索路由表,然后依据具体的调度算法(如round robin )选择一个backend转发请求。但这张路由表是静态的,如果变更后,则必须reload,经常reload的话这对SLA有较大影响。

为了达到减少reload的目的,大多通过动态更新维护路由表来解决这个问题。通常路由表的维护有Push与Pull两种方式。

  • Push方案

通过Nginx API向Nginx发出请求,操作简单、便利。

架构图如下

http api除了操作简单、方便,而且实时性好;缺点是有多台Nginx时,不同Nginx路由表的一致性难于保证,如果某一条注册失败,便会造成服务配置的不一致,容错复杂。另外扩容Nginx服务器,需要从其他的Nginx中同步路由表。

  • Pull方案

      路由表中所有的backend信息(含meta)存储到Consul,所有的Nginx从Consul拉取相关信息。有变更则更新路由表,利用Consul解决一致性问题,同时利用Consul的wait机制解决实时性问题。利用Consul的index进行增量摘取,解决带宽占用问题。

      在Consul中,一个K/V对代表一个backend信息,增加一个即视作扩容,减少一个即为缩容。调整meta信息,如权重,也可以达到动态流量调整的目的。

架构图如下:

  • 基于动态路由的方案实现

Upsync模块使用了第二种模式,通过拉取Consul的后端Server的列表,并动态更新Nginx的路由信息。Upsync模块工作流程图如下:

 

      每个Work进程定时的去Consul拉取相应upstream的配置,若Consul发现对应upstream的值没有变化,便会hang住这个请求五分钟(默认值)。在这五分钟内对此upstream的任何操作,都会立刻返回给Nginx对相应路由进行更新。

      upstream变更后,除了更新Nginx的缓存路由信息,还会把本upstream的后端server列表dump到本地,保持本地server信息与consul的一致性。

      除了注册/注销后端的server到consul,会更新到Nginx的upstream路由信息外,对后端server属性的修改也会同步到nginx的upstream路由。

Upsync模块支持修改的属性有:weight、max_fails、fail_timeout、down。

  1. 修改server的权重可以动态的调整后端的流量。
  2. 若想要临时移除server,可以把server的down属性置为1。
  3. 若要恢复流量,可重新把down置为0。

每个work进程各自拉取、更新各自的路由表,采用这种方式的原因:

  1. 基于Nginx的进程模型,彼此间数据独立、互不干扰。
  2. 若采用共享内存,需要提前预分配,灵活性可能受限制,而且还需要读写锁,对性能可能存在潜在的影响。
  3. 若采用共享内存,进程间协调去拉取配置,会增加它的复杂性,拉取的稳定性也会受到影响。

Upsync模块高可用性

Nginx的后端列表更新依赖于Consul,但是不强依赖于它,具体表现为:

  1. 即使中途Consul意外挂了,也不会影响Nginx的服务,Nginx会沿用最后一次更新的服务列表继续提供服务。
  2. 若Consul重新启动提供服务,这个时候Nginx会继续去Consul探测,这个时候Consul的后端服务列表发生了变化,也会及时的更新到Nginx。
  3. work进程每次更新都会把后端列表dump到本地,目的是降低对Consul的依赖性,即使在consul不可用时,也可以Reload Nginx。

Nginx启动流程图如下:

      Nginx启动时,master进程首先会解析本地的配置文件,解析完成功,接着进行一系列的初始化,之后便会开始work进程的初始化。work初始化时会去Consul拉取配置,进行work进程upstream路由信息的更新,若拉取成功,便直接更新,若拉取失败,便会打开配置的dump后端列表的文件,提取之前dump下来的server信息,进行upstream路由的更新,之后便开始正常的提供服务。

      每次去拉取Consul都会设置连接超时,由于Consul在无更新的情况下默认会hang五分钟,所以响应超时配置时间应大于五分钟。大于五分钟之后,Consul依旧没有返回,便直接做超时处理。

Upsync模块安装

安装Consul

Consul是HashiCorp公司推出的开源工具,用于实现分布式系统的服务发现与配置。

Upsync最新版本是支持ectd,这里用ectd做为后端存储。有关consule的讲解后面单独来讲。如果你还没有etcd环境,可参考「etcd使用入门」一文搭建一个。

安装配置Nginx

  • 下载对应软件包

这里使用的是Upsync最新版本,目前支持Nginx 1.9+。nginx-upstream-check-module是Tengine中的模块,主要用于upstream的健康检查。由于nginx-upstream-check-module最新版本只支持1.9.2,所以这里Nginx选用1.9.2。

1
2
3
4
$ cd /root
$ wget 'http://nginx.org/download/nginx-1.9.2.tar.gz'
$ git clone https://github.com/weibocom/nginx-upsync-module
$ git clone https://github.com/xiaokai-wang/nginx_upstream_check_module
  • 编译安装Nginx
1
2
3
4
5
6
$ apt-get install libreadline-dev libncurses5-dev libpcre3-dev libssl-dev perl make build-essential
$ tar xzvf nginx-1.9.2.tar.gz
$ cd nginx-1.9.2
$ patch -p0 < ~/nginx_upstream_check_module/check_1.9.2+.patch
$ ./configure --add-module=/root/nginx_upstream_check_module --add-module=/root/nginx-upsync-module
$ make && make install
  • 配置Nginx

Nginx会默认安装到/usr/local/nginx目录下。

创建用户和相应目录

1
2
3
4
5
$ useradd -M nginx -s /sbin/nologin
$ mkdir -p /var/log/nginx
$ chown -R nginx.nginx /var/log/nginx
$ mkdir /usr/local/nginx/conf/conf.d
$ mkdir -p /usr/local/nginx/conf/servers

修改Nginx主配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 备份原配置文件
$ cd /usr/local/nginx
$ mv conf/nginx.conf conf/nginx.conf.bak

# 修改配置
$ vim /usr/local/nginx/conf/nginx.conf

user  nginx;
worker_processes  5;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /usr/local/nginx/conf/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /usr/local/nginx/conf/conf.d/*.conf;
}

创建站点配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
$ vim /usr/local/nginx/conf/conf.d/site.conf

upstream test {
  # fake server otherwise ngx_http_upstream will report error when startup
  server 127.0.0.1:11111;

  # all backend server will pull from consul when startup and will delete fake server

  # 后端使用consul存储
  # upsync 192.168.2.210:8500/v1/kv/upstreams/test upsync_timeout=6m upsync_interval=500ms upsync_type=consul strong_dependency=off;


  # 后端使用etcd存储
  upsync 192.168.2.210:2379/v2/keys/upstreams/test upsync_timeout=6m

  upsync_interval=500ms upsync_type=etcd strong_dependency=off;
  upsync_dump_path /usr/local/nginx/conf/servers/servers_test.conf;

  #配置健康检查
  check interval=1000 rise=2 fall=2 timeout=3000 type=http default_down=false;
  check_http_send "HEAD / HTTP/1.0\r\n\r\n";
  check_http_expect_alive http_2xx http_3xx;

}

upstream bar {
  server 192.168.2.210:8080 weight=1 fail_timeout=10 max_fails=3;
}

server {
  listen 80;

  location = / {
    proxy_pass http://test;
  }

  location = /bar {  
    proxy_pass http://bar;
  }

  location = /upstream_show {
    upstream_show;
  }

  location = /upstream_status {
    check_status;
    access_log off;
  }
}
  • 创建Nginx Systemd服务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ vi /lib/systemd/system/nginx.service

[Unit]
Description=The NGINX HTTP and reverse proxy server
Documentation=http://nginx.org/en/docs/
After=syslog.target network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf
ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target

修改权限及加入开机启动

1
2
$ sudo chmod +x /lib/systemd/system/nginx.service
$ sudo systemctl enable nginx.service

现在可以使用下面的指令来管理Nginx服务。

1
2
3
4
$ systemctl start nginx.service
$ systemctl reload nginx.service
$ systemctl restart nginx.service
$ systemctl stop nginx.service
  • 启动Nginx
1
$ systemctl start nginx.service

验证Nginx服务是否正常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ systemctl status  nginx.service
● nginx.service - The NGINX HTTP and reverse proxy server
   Loaded: loaded (/lib/systemd/system/nginx.service; disabled; vendor preset: enabled)
   Active: active (running) since Mon 2017-05-08 10:58:06 CST; 1min 6s ago
     Docs: http://nginx.org/en/docs/
  Process: 22966 ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf (code=exited, status=0/SUCCESS)
  Process: 22963 ExecStartPre=/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf (code=exited, status=0/SUCCESS)
 Main PID: 22971 (nginx)
    Tasks: 6
   Memory: 24.5M
      CPU: 517ms
   CGroup: /system.slice/nginx.service
           ├─22971 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.con
           ├─22972 nginx: worker process
           ├─22973 nginx: worker process
           ├─22974 nginx: worker process
           ├─22975 nginx: worker process
           └─22976 nginx: worker process

May 08 10:58:06 dev-master-01 systemd[1]: Starting The NGINX HTTP and reverse proxy server...
May 08 10:58:06 dev-master-01 nginx[22963]: nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
May 08 10:58:06 dev-master-01 nginx[22963]: nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
May 08 10:58:06 dev-master-01 systemd[1]: Started The NGINX HTTP and reverse proxy server.

如果要单独查看Nginx服务日志,可以使用以下命令:

1
$ journalctl -f -u nginx.service

验证Upsync模块

启动一个Web服务

这里在Nginx默认站点目录,用Python启动一个SimpleHTTPServer进行验证。

1
2
$ cd /usr/local/nginx/html
$ python -m SimpleHTTPServer 8080

后端存储增加数据

  • 后端存储使用etcd

增加一个后端服务器

1
$ curl -X PUT http://192.168.2.210:2379/v2/keys/upstreams/test/192.168.2.210:8080

其它Upstream模块中其它属性的默认值为:weight=1 max_fails=2 fail_timeout=10 down=0 backup=0;。如果你要调整这些值,可以用以下命令格式进行提交:

1
$ curl -X PUT -d value="{\"weight\":1, \"max_fails\":2, \"fail_timeout\":10}" http://$etcd_ip:$port/v2/keys/$dir1/$upstream_name/$backend_ip:$backend_port

删除一个后端服务器

1
$ curl -X DELETE http://192.168.2.210:2379/v2/keys/upstreams/test/192.168.2.210:8080
  • 后端存储使用Consul

增加一个后端服务器

1
$ curl -X PUT http://192.168.2.210:8500/v1/kv/upstreams/test/192.168.2.210:8080

删除一个后端服务器

1
$ curl -X DELETE http://192.168.2.210:8500/v1/kv/upstreams/test/192.168.2.210:8080

测试站点是否正常访问

  • 访问站点

页面自动根据proxy_pass http://test;成功转到了后端服务器。

  • 访问upstream列表

  • 访问upstream状态

  • 查看添加的后端服务是否被dump到本地
1
2
$ cat /usr/local/nginx/conf/servers/servers_test.conf
server 192.168.2.210:8080 weight=1 max_fails=2 fail_timeout=10s;

参考文档

http://www.google.com
http://t.cn/Ra2WfSR
https://my.oschina.net/liucao/blog/470344
http://blog.csdn.net/yueguanghaidao/article/details/52801043
https://www.nginx.com/resources/wiki/start/topics/examples/systemd/

 

########################################################

基于 consul + upsync 的动态upstream管理

upsync介绍

      upsync是微博开源的基于nginx的动态流量管理方案. github地址: https://github.com/weibocom/nginx-upsync-module.

      nginx-upsync-module,它的功能是拉取 consul 的后端 server 的列表,并更新 Nginx 的路由信息。此模块不依赖于任何第三方模块。 consul 作为 Nginx 的 db,利用 consul 的 KV 服务,每个 Nginx work 进程独立的去拉取各个 upstream 的配置,并更新各自的路由。

 

upsync arch

consul简介

      Consul是HashiCorp公司推出的开源工具,用于实现分布式系统的服务发现与配置. consul是分布式的, 高可用的, 可横向扩展的. 它具备以下特性:

  • 服务发现: consul提供了通过DNS或者HTTP接口的方式来注册服务和发现服务. 一些外部的服务通过consul很容易的找到它所依赖的服务.

  • 健康检测: consul的client提供了健康检查的机制, 可以通过用来避免流量被转发到有故障的服务上.

  • Key/Value存储: 应用程序可以根据自己的需要使用Consul提供的Key/Value存储. Consul提供了简单易用的HTTP接口, 结合其他工具可以实现动态配置, 功能标记, 领袖选举等等功能.

  • 多数据中心: Consul支持开箱即用的多数据中心. 这意味着用户不需要担心需要建立额外的抽象层让业务扩展到多个区域.

consul架构

  • consul cluster由部署和运行了consul agent的节点组成. 在cluster中有两种角色: server 和 client.

  • server 和 client 的角色和consul cluster上运行的应用服务无关, 是基于consul层面的一种角色划分.

  • consul server: 用于维护consul cluster的状态信息. 官方文档中给出的建议是: 至少要运行3个或者3个以上的consul server. 多个server之中需要选举一个leader, 这个选举过程consul基于raft协议实现. 多个server节点上的consul数据信息保持强一致性.

  • consul client: 只维护自身的状态, 并上报请求给server.

 

consul arch

consul的安装和启动

启动两台consul server:

consul agent -server -bootstrap-expect 1 -data-dir /tmp/consul -client 0.0.0.0 -bind=192.168.100.123 -ui-dir /root/consul_ui -node=server01 -dc=upstream
consul agent -server -data-dir /tmp/consul -client 0.0.0.0 -bind=192.168.100.125 -node=server02 -dc=upstream

一台 consul client:

consul agent -data-dir /tmp/consul -client 0.0.0.0 -bind=192.168.100.127 -node=client01 -dc=upstream
  • 查看集群成员:
[root@ruby-100-123 ~]# consul members
Node      Address               Status  Type    Build  Protocol  DC
client01  192.168.100.127:8301  alive   client  0.7.3  2         upstream
server01  192.168.100.123:8301  alive   server  0.7.3  2         upstream
server02  192.168.100.125:8301  alive   server  0.7.3  2         upstream

通过以上命令可以查看集群中的地址信息, 健康状态, 启动的角色, 版本信息等.

如果需要查看一些元数据的话, 可以通过加 -detailed 参数查看:

[root@ruby-100-123 ~]# consul members --detailed
Node      Address               Status  Tags
client01  192.168.100.127:8301  alive   build=0.7.3:'a90bb8f,dc=upstream,id=64ff71ab-465d-1d7e-22f6-9df6860c0293,role=node,vsn=2,vsn_max=3,vsn_min=2
server01  192.168.100.123:8301  alive   bootstrap=1,build=0.7.3:'a90bb8f,dc=upstream,id=7e1a3bed-2474-898f-275b-212d5fb8f646,port=8300,role=consul,vsn=2,vsn_max=3,vsn_min=2
server02  192.168.100.125:8301  alive   build=0.7.3:'a90bb8f,dc=upstream,id=ad7549e5-b1b6-7d52-a04f-1efd4e0fd58a,port=8300,role=consul,vsn=2,vsn_max=3,vsn_min=2

服务注册

服务注册有两种方式: 通过服务定义配置文件 和 通过HTTP接口. consul推荐使用第一种配置方式.

mkdir /etc/consul.d
echo '{"service": {"name": "web", "tags": ["rails"], "port": 80}}' >/etc/consul.d/web.json

consul agent -server -data-dir /tmp/consul -client 0.0.0.0 -bind=192.168.100.125 -node=server02 -dc=upstream  -config-dir /etc/consul.d/

然后我们可以通过HTTP接口查询注册的服务:

-bash: Python: command not found
[root@ruby-2-1-source ~]# curl -s http://localhost:8500/v1/catalog/service/web | python -m json.tool
[
    {
        "Address": "192.168.100.125",
        "CreateIndex": 186121,
        "ID": "ad7549e5-b1b6-7d52-a04f-1efd4e0fd58a",
        "ModifyIndex": 186121,
        "Node": "server02",
        "NodeMeta": {},
        "ServiceAddress": "",
        "ServiceEnableTagOverride": false,
        "ServiceID": "web",
        "ServiceName": "web",
        "ServicePort": 80,
        "ServiceTags": [
            "rails"
        ],
        "TaggedAddresses": {
            "lan": "192.168.100.125",
            "wan": "192.168.100.125"
        }
    }
]

健康监测

同样地, 我们可以通过定义配置文件 或 HTTP接口来定义健康监测.

我们定义一个简单的ping检查, 每隔30s一次, 然后重新启动client.

echo '{"check": {"name": "ping", "script": "ping -c1 www.zhe800.com >/dev/null", "interval": "30s"}}' >/etc/consul.d/ping.json

consul agent -server -data-dir /tmp/consul -client 0.0.0.0 -bind=192.168.100.125 -node=server02 -dc=upstream  -config-dir /etc/consul.d/

定义完健康监测的配置之后, 我们可以通过HTTP接口来检查各个agent的运行状态.

curl -s http://localhost:8500/v1/health/state/any | python -m json.tool

Key/Value存储

consul 提供了一个简单易用的Key/Value存储系统, 并提供了相关的HTTP接口, 可以用来动态获取配置(我们的动态upstream项目就是这种应用)、进行服务协调、主节点选举等.

可以通过HTTP接口查看K/V系统中存储了哪些内容:

curl -v http://127.0.0.1:8500/v1/kv/?recurse

通过HTTP接口往K/V系统写入数据:

curl -X PUT -d 'test' http://127.0.0.1:8500/v1/kv/key1/
curl -X PUT -d 'test' http://127.0.0.1:8500/v1/kv/key1/key2?param1=test
curl -X PUT -d 'test' http://127.0.0.1:8500/v1/kv/key1/key2/key3

写入数据之后, 可以通过上面的命令查看. 其value采用Base64加密.

另外, 也可以查看某个单个的key:

curl -s http://127.0.0.1:8500/v1/kv/key1 |python -m json.tool

WEB界面

URL: http://192.168.100.123:8500/ui

启动命令需要增加: -ui-dir 参数, 用于指前端相关的文件位置.

动态upsteams管理系统

 

动态upsteams管理系统

结合zhe800自身的业务来说:

  1. 降低运维配置的复杂度:

原本的配置方式:

upstream test {
server 127.0.0.1:9601 weight=40 max_fails=10 fail_timeout=30s;
server 127.0.0.1:9602 weight=20 max_fails=10 fail_timeout=30s;
server 127.0.0.1:9603 weight=5 max_fails=10 fail_timeout=30s;
server 127.0.0.1:9604 weight=20 max_fails=10 fail_timeout=30s;
server 127.0.0.1:9605 weight=10 max_fails=10 fail_timeout=30s;
server 127.0.0.1:9606 weight=20 max_fails=10 fail_timeout=30s;
keepalive 166;
}

使用 upsync 之后的配置方式:

upstream test {
server 127.0.0.1:11111;
upsync 192.168.100.123:8500/v1/kv/upstreams/test upsync_timeout=6m upsync_interval=500ms upsync_type=consul strong_dependency=off;
upsync_dump_path /usr/local/nginx/conf/servers/servers_test.conf;

}

  1. 便于动态扩容缩容

运维可以很方便的在后台增删服务器

  1. 基于upstreams后台提供的服务器列表信息, 结合ads可以实现上线更新时的无缝切换

系统提供了每个upstream对应的服务列表的API, 以及启动, 关闭相关服务的API. ads系统更新上线的时候, 通过调用相关的API, 完成无缝上线.


链接:

https://www.jianshu.com/p/35b03c82f9fd
https://blog.csdn.net/shenshouer/article/details/52925735

https://my.oschina.net/guol/blog/857568

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Docker+Consul+Nginx+keepalived是一种常用的云原生架构方案,它结合了容器化、服务发现、负载均衡和高可用等多种技术手段,可用于构建高可用、弹性、可扩展的应用系统。 该方案的主要组件包括: 1. Docker:用于容器化应用程序和服务,提供了高效、轻量、可移植的应用打包和部署方式。 2. Consul:用于服务发现和配置管理,支持多数据中心、跨平台、高度可扩展的分布式系统。 3. Nginx:用于负载均衡和反向代理,支持高并发、高可用的流量分发。 4. keepalived:用于实现高可用的服务和节点,提供了基于 VRRP 协议的故障转移和自动切换功能。 在该方案中,Docker 容器作为应用程序和服务的运行环境,使用 Consul 进行服务注册和发现,并通过 Nginx 进行流量分发和负载均衡。同时,使用 keepalived 实现高可用的服务和节点,确保系统的稳定性和可用性。 项目描述可以按照以下步骤进行撰写: 1. 项目背景和目的:简要介绍本项目的背景和目的,说明为什么选择 Docker+Consul+Nginx+keepalived 方案。 2. 技术架构:详细介绍该方案的技术架构和组件,包括 Docker、Consul、Nginx 和 keepalived 的作用和使用方式。 3. 系统功能:描述系统的主要功能和特点,包括服务发现、负载均衡、高可用等方面。 4. 实现方式:介绍系统的具体实现方式和实现步骤,包括 Docker 镜像的构建、应用程序的容器化、Consul 的配置和使用、Nginx 的配置和使用、keepalived 的配置和使用等。 5. 测试和验证:对系统进行测试和验证,验证系统的功能和性能是否符合预期,是否满足高可用和弹性的要求。 6. 总结和展望:对本项目进行总结和展望,分析该方案的优缺点和适用范围,展望未来的发展方向和趋势。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值