Dubbo入门笔记(尚硅谷)

目录

一、基础知识

1、分布式系统概念

2、发展演变

3、RPC简介

1)基本原理:

2)核心模块:通信效率/序列化与反序列化

3)各种RPC框架:dubbo、gRPC、Thrift、HSF

4、dubbo简介

5、环境搭建 

1)搭建Zookeeper注册中心

2)搭建监控中心

6、dubbo-helloword

1)打开Idea,创建三个meven工程

7、监控中心

1)打开 dubbo-monitor-simple 简易监控中心

2)配置监控中心

三、与spingboot整合

1、创建工程

2、提供者实现

1)导入依赖(pom)

3、消费者实现

1)导入依赖(pom)

四、dubbo配置

1、三种配置策略:

2、取消消费者检查

3、超时设置

4、重试次数

5、多版本

6、本地存根

五、与SpringBoot的三种整合

六、高可用

1、zookeeper宕机与dubbp直连

2、负载均衡

1)Random LoadBalance

2)RoundRobin LoadBalance

3)LeastActive LoadBalance

4)ConsistentHash LoadBalance

3、替换轮询机制

4、修改权重

5、服务降级

1)屏蔽 (直接返回为空)

2)容错 (调用失败后返回为空)

6、集群容错

1)多种容错策略

2)集群模式配置

3)整合hystrix容错配置


一、基础知识

1、分布式系统概念

分布式系统是若干独立计算机的集合,这些计算机对于用户来说就像当个相关系统。

2、发展演变

单一应用架构 >>>> 垂直应用架构 >>>> 分布式服务架构 >>>> 流动计算架构

3、RPC简介

rpc:远程过程调用,是一种进程间通信方法,一种技术思想

1)基本原理:

2)核心模块:通信效率/序列化与反序列化

3)各种RPC框架:dubbo、gRPC、Thrift、HSF

4、dubbo简介

高性能的RPC框架

官网:Apache Dubbo

特性:

5、环境搭建 

1)搭建Zookeeper注册中心

下载安装见Zookeeper入门

启动 zkServer.cml 和 zkCli.sh

2)搭建监控中心

官网 >>> GITHUB >>> dubbo-admin下载 

解压,打开路径下dubbo-admin-master\dubbo-admin-server\src\main\resources的application.properties  修改配置

打包 :mvn clean package -Dmaven.test.skip=true

运行打包号的jar包:java -jar dubbo-admin-0.0.1-SNAPSHOT.jar

浏览器打开:http://localhost:7001/

6、dubbo-helloword

1)打开Idea,创建三个meven工程

gmall-interface:接口工程(存放接口公共信息的工程)

创建javaBean以及各种接口

 user-service-provider:提供者工程 

⚫将服务提供者注册到注册中心(暴露服务)

               ①导入依赖   ②配置服务提供者

⚫让服务消费者去注册中心订阅服务提供者的地址

pom引入接口工程的依赖,引入dubbo依赖,以及zookeeper的依赖

        <dependency>
            <groupId>com.zhijia.gmall</groupId>
            <artifactId>gmall-interface</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <!--引入dubbo-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.6.3</version>
        </dependency>

        <!--引入zookeeper注册中心-->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>2.12.0</version>
        </dependency>

创建 provider.xml 配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd
		http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">


    <!--1、指定当前服务/应用名字-->
    <dubbo:application name="user-service-provider"></dubbo:application>

    <!--2、指定注册中心位置-->
    <dubbo:registry address="zookeeper://127.0.0.1:2181"></dubbo:registry>

    <!--3、指定通信规则(协议,端口)-->
    <dubbo:protocol name="dubbo" port="20880"></dubbo:protocol>

    <!--4、暴露服务-->
    <dubbo:service interface="com.zhijia.gmall.service.UserService" ref="userServiceImpl"
        version="1.0.0"
    ></dubbo:service>

    <bean id="userServiceImp2" class="com.zhijia.gmall.service.impl.UserServiceImpl2"></bean>

    <!--服务实现-->
    <bean id="userServiceImpl" class="com.zhijia.gmall.service.impl.UserServiceImpl"></bean>


</beans>

启动主程序

package com.zhijia.gmall;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.io.IOException;

/**
 * 提供者
 * @author zhijia
 * @create 2022-01-29 11:09
 */
public class MainApplication {
    public static void main(String[] args) throws IOException {
        ClassPathXmlApplicationContext ioc=new  ClassPathXmlApplicationContext("provider.xml");
        //启动
        ioc.start();
        //阻塞读取
        System.in.read();
    }
}

提供者启动 

 

order-service-consumer:消费者工程

引入依赖

        <dependency>
            <groupId>com.zhijia.gmall</groupId>
            <artifactId>gmall-interface</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <!--引入dubbo-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.6.3</version>
        </dependency>

        <!--引入zookeeper注册中心-->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>2.12.0</version>
        </dependency>

创建 consumer.xml 配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.zhijia.gmall.service.impl"></context:component-scan>

    <dubbo:application name="order-service-consumer"></dubbo:application>

    <dubbo:registry address="zookeeper://127.0.0.1:2181"></dubbo:registry>

    <!--声明要调用的远程服务接口:生成远程服务代理-->
    <dubbo:reference interface="com.zhijia.gmall.service.UserService" id="userService"
                     version="*" stub="com.zhijia.gmall.service.UserServiceStub">        </dubbo:reference>

</beans>

 OrderServiceImpl 可使用注解远程调用提供者的实现类

package com.zhijia.gmall.service.impl;

import com.zhijia.gmall.bean.UserAddress;
import com.zhijia.gmall.service.OrderService;
import com.zhijia.gmall.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @author zhijia
 * @create 2022-01-28 22:03
 */
@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    UserService userService;


    public List<UserAddress> initOrder(String userId) {
        System.out.println("用户ID: "+userId);

        //1、查询用户的收货地址
        List<UserAddress> addressList=userService.getUserAddressList(userId);
//        System.out.println(addressList);
//        for (UserAddress userAddress : addressList) {
//            System.out.println(userAddress.getUserAddress());
//        }
        return addressList;
    }
}

主方法启动消费者,消费者上线

package com.zhijia.gmall;

import com.zhijia.gmall.service.OrderService;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.io.IOException;

/**
 * 消费者
 * @author zhijia
 * @create 2022-01-29 12:37
 */
public class MainApplication {

    public static void main(String[] args) throws IOException {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("consumer.xml");

        OrderService orderService = applicationContext.getBean(OrderService.class);

        orderService.initOrder("1");

        System.out.println("调用完成");
        System.in.read();
    }
}

运行,成功远程调用实现远程调用 

 

 7、监控中心

1)打开 dubbo-monitor-simple 简易监控中心

mvn package 打包,打开targer,解压 dubbo-monitor-simple-2.0.0-assembly.tar.gz

 可修改 dubbo-monitor-simple-2.0.0\conf 下的 dubbo.properties 配置文件

打开 bin 目录 打开 start.bat 启动监控中心

2)配置监控中心

两种方式(提供者和消费者的配置文件都需配置)

    <!--自动发现监控中心-->
    <dubbo:monitor protocol="registry"></dubbo:monitor>
    <!--直连监控中心-->
    <!--<dubbo:monitor address="127.0.0.1:7070"></dubbo:monitor>-->

重新启动消费者和提供者 浏览器打开 http://localhost:8080/

三、与spingboot整合

1、创建工程

pom加入依赖通用接口

        <dependency>
            <groupId>com.zhijia.gmall</groupId>
            <artifactId>gmall-interface</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

复制原先的各种实现

 

 2、提供者实现

1)导入依赖(pom)

① 导入 dubbo-starter

		<dependency>
			<groupId>com.alibaba.boot</groupId>
			<artifactId>dubbo-spring-boot-starter</artifactId>
			<version>0.2.0</version>
		</dependency>

 ② 配置 application.properties

dubbo.application.name=user-service-provider
dubbo.registry.address=127.0.0.1:2181
dubbo.registry.protocol=zookeeper

dubbo.protocol.name=dubbo
dubbo.protocol.port=20880

dubbo.monitor.protocol=registry

③ UserServiceImpl 使用dubbo 的 @Service 注解暴露服务

package com.zhijia.gmall.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.zhijia.gmall.bean.UserAddress;
import com.zhijia.gmall.service.UserService;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

@Service //暴露服务
@Component
public class UserServiceImpl implements UserService {

	public List<UserAddress> getUserAddressList(String userId) {
		System.out.println("UserServiceImpl.....old...");
		// TODO Auto-generated method stub
		UserAddress address1 = new UserAddress(1, "北京市昌平区宏福科技园综合楼3层", "1", "李老师", "010-56253825", "Y");
		UserAddress address2 = new UserAddress(2, "深圳市宝安区西部硅谷大厦B座3层(深圳分校)", "1", "王老师", "010-56253825", "N");
		/*try {
			Thread.sleep(4000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}*/
		return Arrays.asList(address1,address2);
	}

}

④ 主方法中使用@EnableDubbo 注解 开启基于注解的dubbo功能

package com.zhijia.gmall;

import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * 1、导入依赖
 * 		1)、导入dubbo-starter
 * 		2)、导入dubbo的其他依赖
 */
@EnableDubbo //开启基于注解的dubbo功能
@SpringBootApplication
public class BootUserServiceProviderApplication {

	public static void main(String[] args) {
		SpringApplication.run(BootUserServiceProviderApplication.class, args);
	}

}

3、消费者实现

1)导入依赖(pom)

① 导入 dubbo-starter

		<dependency>
			<groupId>com.alibaba.boot</groupId>
			<artifactId>dubbo-spring-boot-starter</artifactId>
			<version>0.2.0</version>
		</dependency>

 ② 配置 consumer.properties 并修改服务端口,因为启动后Tomcal也是8080端口,防止冲突

server.port=8081

dubbo.application.name=boot-order-service-consumer
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.monitor.protocol=registry

③OrderServiceImpl 使用@Reference 远程引用服务

package com.zhijia.gmall.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.zhijia.gmall.bean.UserAddress;
import com.zhijia.gmall.service.OrderService;
import com.zhijia.gmall.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @author zhijia
 * @create 2022-01-28 22:03
 */
@Service
public class OrderServiceImpl implements OrderService {

    //@Autowired
    @Reference
    UserService userService;

    public List<UserAddress> initOrder(String userId) {

        System.out.println("用户ID: "+userId);

        //1、查询用户的收货地址
        List<UserAddress> addressList=userService.getUserAddressList(userId);
//        System.out.println(addressList);
        return addressList;
    }
}

④ 主方法中使用@EnableDubbo 注解 开启基于注解的dubbo功能 

package com.zhijia.gmall;

import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@EnableDubbo
@SpringBootApplication
public class BootOrderServiceConsumerApplication {

	public static void main(String[] args) {
		SpringApplication.run(BootOrderServiceConsumerApplication.class, args);
	}

}

⑥ 新建controller层 将数据返回到页面(OrderController)

package com.zhijia.gmall.controller;

import com.zhijia.gmall.bean.UserAddress;
import com.zhijia.gmall.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;

/**
 * @author zhijia
 * @create 2022-01-29 16:57
 */
@Controller
public class OrderController {

    @Autowired
    OrderService orderService;

    @ResponseBody//json
    @RequestMapping("/initOrder")
    public List<UserAddress> initOrder(@RequestParam("uid")String userId){
        return orderService.initOrder(userId);
    }
}

四、dubbo配置

1、三种配置策略:

API配置、XML配置、Properties配置 优先级逐步降低

2、取消消费者检查

启动消费者,如果提供者没有启动,消费者会报错,此时可用启动 取消检查

启动取消检查,如果启动消费者没有实例对象,将不检查

配置消费者统一规则 

    <!--check:不检查服务  timoout:超时时间   retries:重试次数-->
    <dubbo:consumer check="false" timeout="2000" retries="3"></dubbo:consumer>

 3、超时设置

解决因为网络原因,服务提供方执行方法占用很长时间,导致大量线程阻塞,引起的性能下降。

设置某个线程在规定时间内没有完成,立即终止不让线程大量阻塞。系统默认设置超时时间为1秒

精确优先 and 消费者优先

 4、重试次数

调用失败额外重试次数(不包含第一次调用)

多次重试,若有多个相同提供者,将重试调用的提供者,在重试其他提供者

幂等(设置重试次数)【查询、删除、修改】、非幂等()不能设置重试次数【新增】

设置为 0 代表不重试

    <!--check:不检查服务  timoout:超时时间   retries:重试次数-->
    <dubbo:consumer check="false" timeout="2000" retries="3"></dubbo:consumer>

5、多版本

灰度发布、版本更替 

    <!--4、暴露服务-->
    <dubbo:service interface="com.zhijia.gmall.service.UserService" ref="userServiceImpl"
        version="1.0.0"
    ></dubbo:service>
    <!--多版本-->
    <dubbo:service interface="com.zhijia.gmall.service.UserService" ref="userServiceImpl2"
        version="2.0.0"
    ></dubbo:service>
    <bean id="userServiceImp2" class="com.zhijia.gmall.service.impl.UserServiceImpl2"></bean>

    <!--服务实现-->
    <bean id="userServiceImpl" class="com.zhijia.gmall.service.impl.UserServiceImpl"></bean>

 随机调用版本

    <!--声明要调用的远程服务接口:生成远程服务代理-->
    <dubbo:reference interface="com.zhijia.gmall.service.UserService" id="userService"
                     version="*"></dubbo:reference>

6、本地存根

远程调用之前做一些参数验证、判断或缓存,就可用用本地存根

在接口工程配置本地存根实现代码

package com.zhijia.gmall.service;

import com.zhijia.gmall.bean.UserAddress;
import org.springframework.util.StringUtils;

import java.util.List;

/**
 * 本地存根
 * @author zhijia
 * @create 2022-01-31 10:10
 */
public class UserServiceStub implements UserService {

    private final UserService userService;

    public UserServiceStub(UserService userService) {
        this.userService = userService;
    }

    public List<UserAddress> getUserAddressList(String userId) {
        System.out.println("本地存根被调用");
        if(!StringUtils.isEmpty(userId)){
            return userService.getUserAddressList(userId);
        }
        return null;
    }
}

使用本地存根(消费者)

    <!--声明要调用的远程服务接口:生成远程服务代理-->
    <dubbo:reference interface="com.zhijia.gmall.service.UserService" id="userService"
                     version="*" stub="com.zhijia.gmall.service.UserServiceStub"></dubbo:reference>

五、与SpringBoot的三种整合

SpringBoot与dubbo整合的三种方式::

① 导入dubbo-starter,在application.properties配置属性,使用Dubbo的@Service【暴露服务】@Reference【引用】

② 保留dubbo xml配置文件,导入dubbo-starter,使用@ImportResource

添加provider.xml配置,使用@ImportResource 替换@EnableDubbo

package com.zhijia.gmall;

import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;

/**
 * 1、导入依赖
 * 		1)、导入dubbo-starter
 * 		2)、导入dubbo的其他依赖
 * SpringBoot与dubbo整合的三种方式::
 * 1)、导入dubbo-starter,在application.properties配置属性,使用@Service【暴露服务】@Reference【引用】
 * 2)、保留dubbo xml配置文件,导入dubbo-starter,使用@ImportResource
 * 3)、注解API的方式:将每一个组件手动创建到容器中,让dubbo来扫描其他的组件,@EnableDubbo(scanBasePackges="包地址") @Service暴露
 */
//@EnableDubbo //开启基于注解的dubbo功能
@ImportResource(locations = "classpath:provider.xml")
@SpringBootApplication
public class BootUserServiceProviderApplication {

	public static void main(String[] args) {
		SpringApplication.run(BootUserServiceProviderApplication.class, args);
	}

}

③ 注解API的方式:将每一个组件手动创建到容器中,让dubbo来扫描其他的组件,@EnableDubbo(scanBasePackges="包地址") @Service暴露

 使用注解配置,手写配置类

 MyDubboConfig 配置类

package com.zhijia.gmall.config;

import com.alibaba.dubbo.config.*;
import com.zhijia.gmall.service.UserService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;

/**
 * 注解API的方式
 * @author zhijia
 * @create 2022-01-31 10:59
 */
@Configuration
public class MyDubboConfig {

    //当前服务名
    @Bean
    public ApplicationConfig applicationConfig(){
        ApplicationConfig applicationConfig = new ApplicationConfig();
        applicationConfig.setName("boot-user-service-provider");
        return applicationConfig;
    }

    //注册中心
    @Bean
    public RegistryConfig registryConfig(){
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setProtocol("zookeeper");
        registryConfig.setAddress("127.0.0.1.2181");
        return registryConfig;
    }

    //通信规则
    @Bean
    public ProtocolConfig protocolConfig(){
        ProtocolConfig protocolConfig = new ProtocolConfig();
        protocolConfig.setName("dubbo");
        protocolConfig.setPort(20882);
        return protocolConfig;
    }

    //暴露服务
    @Bean
    public ServiceConfig<UserService> userServiceConfig(UserService userService){
        ServiceConfig<UserService> serviceConfig = new ServiceConfig<UserService>();
        serviceConfig.setInterface(UserService.class);
        serviceConfig.setRef(userService);
        serviceConfig.setVersion("1.0.0");

        MethodConfig methodConfig = new MethodConfig();
        methodConfig.setName("getUserAddressList");
        methodConfig.setTimeout(1000);

        ArrayList<MethodConfig> methods = new ArrayList<MethodConfig>();
        serviceConfig.setMethods(methods);

        return serviceConfig;
    }
}

使用 @EnableDubbo 并规定扫描包路径

 六、高可用

1、zookeeper宕机与dubbp直连

注册中心全部宕机后,服务提供者和服务消费者仍能通过本地缓存通信

消费者绕过注册中心直连

 2、负载均衡

四种负载均衡策略

1)Random LoadBalance

随机,按权重设置随机概率。(基于权重的负载均衡机制)(默认)

2)RoundRobin LoadBalance

轮循,按公约后的权重设置轮循比率。(基于权重的轮询负载均衡机制)

3)LeastActive LoadBalance

最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。(最少活跃数的负载均衡机制)

4)ConsistentHash LoadBalance

一致性 Hash,相同参数的请求总是发到同一提供者。(一致性 Hash负载均衡机制)

3、替换轮询机制

 

4、修改权重

5、服务降级

通过服务降级功能临时屏蔽某个出错的非关键服务,并定义降级后的返回策略

1)屏蔽 (直接返回为空)

2)容错 (调用失败后返回为空)

6、集群容错

1)多种容错策略

Failover Cluster (默认)

失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 retries="2" 来设置重试次数(不含第一次)。

Failfast Cluster

快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。

Failsafe Cluster

失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。

Failback Cluster

失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。

Forking Cluster

并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks="2" 来设置最大并行数。

Broadcast Cluster

广播调用所有提供者,逐个调用,任意一台报错则报错 [2]。通常用于通知所有提供者更新缓存或日志等本地资源信息。

2)集群模式配置

按照以下示例在服务提供方和消费方配置集群模式

<dubbo:service cluster="failsafe" />

<dubbo:reference cluster="failsafe" />

3)整合hystrix容错配置

① 配置spring-cloud-starter-netflix-hystrix (消费者和提供者)

		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
			<version>1.4.4.RELEASE</version>
		</dependency>

② 然后在Application类上增加@EnableHystrix来启用hystrix starter(消费者和提供者)

 ③ 在Dubbo的Provider上增加@HystrixCommand配置,这样子调用就会经过Hystrix代理。

(提供者)

 ④ 对于Consumer端,则可以增加一层method调用,并在method上配置@HystrixCommand。当调用出错时,会走到fallbackMethod = "reliable"的调用里

(消费者)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值