Dubbo分布式

第一章,RPC基础知识

RPC?
RPC是指远程过程调用,是一种进程间通讯方式,是一种技术思想,而不是规范。它允许程序调用另一个地址空间(网络的另一台机器上)的过程或函数,而不用开发人员显示编码这个调用的细节。调用本地方法何调用远程方法一样。
RPC的实现方式可以不同。例如java中的rmi,spring远程调用等。
RPC特点:简单-使用简单,建立分布式应用更容易。高效-调用过程看起来十分清晰,效率高。通用-进程间通讯的方式,有通用的规则。
RPC基本原理
在这里插入图片描述
RPC调用过程
1.调用方法client要使用右侧server的功能(方法),发起对方法的调用
2.client stub是RPC中定义的存根,看作是client的助手。stub把要调用的方法参数进行序列化,方法名称和其它数据包装起来
3.通过网络socket,把方法调用的细节内容发送给右侧的server
4.server端通过socket接受请求的方法名称,参数等数据,传给stub
5.server端接到的数据由server stub处理,调用server的真正方法,处理业务
6.server方法处理完业务,把处理的结果对象交给了助手,助手把Object进行序列化,对象转为二进制数据
7.server助手二进制数据交给网络处理程序
8.通过网络将二进制数据,放松给client
9.client接数据,交给client助手
10.client助手,就收数据通过反序列化为java对象,作为远程方法调用结果
其他:RPC通讯是基于tcp或udp协议,反序列化方式(sml/json/二进制)

第二章,dubbo框架

dubbo概述
Apache Dubbo是一款高性能,轻量级的开源java RPC框架,它提供了三大核心能力,面向接口的远程方法调用,只能容错和负载均衡,以及服务自动注册和发现。Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,服务治理方案。
在这里插入图片描述
服务提供者(Provider):暴露服务的服务提供方,服务提供者在启动时,想注册中心注册自己提供的服务。
服务消费者(Consumer):调用远程服务的服务消费方,服务消费者在启动时,向注册中心订阅自己所需的服务,服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
注册中心(Registy):注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
监控中心(Monitor):服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计 数据到监控中心。

第三章,服务提供者(provider)

1.新建一个空maven工程
2.在pom文件中导入相关依赖

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>4.3.14.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>dubbo</artifactId>
			<version>2.5.3</version>
		</dependency>

3.写好实体类,业务层和实现类
在这里插入图片描述
4.新建spring的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://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <!--声名dubbo的服务名称
        name:dubbo的服务名称,自定义的字符串,可以使用项目的名称,
        服务的名称最好是唯一值,dubbo框架内部用来区分服务的
    -->
    <dubbo:application name="orderserviceprovider"/>

    <!--声名访问dubbo服务的协议
        name:协议名称
        port:端口号
    -->
    <dubbo:protocol name="dubbo" port="20880"/>

    <!--生命服务的接口,暴露服务
        interface:服务接口的权限名称
        ref:接口的实现类对象的id
        registry:是都是用注册中心,第一个项目是直连方式,不使用注册中心,所以赋值为“N/A”
    -->
    <dubbo:service interface="com.rlw.service.OrderService"  ref="orderService" registry="N/A"/>

    <!--生命接口的实现类对象-->
    <bean id="orderService" class="com.rlw.service.impl.OrderServiceImpl"/>
</beans>

5.调试运行

package com;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class OrderProvicerApplication {
    public static void main(String[] args) {
        String config = "orderservice-provider.xml";
        ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
        //容器启动方法
        ((ClassPathXmlApplicationContext) ctx).start();
        //使之一直运行
        System.in.read();
    }
}

第四章,服务消费者(Consumer)

1.新建一个maven项目
2.在pom文件中导入相关依赖,而且多导入一个服务提供者的jar包依赖,为了使用服务提供者中的实体类以及部分方法。

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com,rlw</groupId>
  <artifactId>link-main-web</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>link-main-web</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.14.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>dubbo</artifactId>
      <version>2.5.3</version>
    </dependency>
    <!--提供者的依赖项-->
    <dependency>
      <groupId>com.rlw</groupId>
      <artifactId>link-orderservice-provider</artifactId>
      <version>1.0-SNAPSHOT</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

3.写好实体类,业务层和实现类
在这里插入图片描述
4.书写sprig配置dubbo的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://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <!--声名服务的名称-->
    <dubbo:application name="link-main-web"/>

    <!--声名要使用的远程接口
        id:dubbo创建的接口的实现类对象的名称(动态代理)
        interface:远程的接口全限定名称(服务提供者的接口)
        registry:表示是否使用注册中心,不适用赋值为“N/A”
        url:访问服务提供者的地址,直连方式中,地址是固定的
    -->

    <dubbo:reference id="remoteOrderService"
                     interface="com.rlw.service.OrderService"
                     registry="N/A"
                     url="dubbo://localhost:20880"/>

    <!--声名自定义的业务对象-->
    <bean id="shopService" class="com.rlw.service.impl.ShopServiceImpl">
        <property name="orderService" ref="remoteOrderService"/>
    </bean>
</beans>

5.调式调用服务提供者中的方法,以及查看返回结果

public class App
{
    public static void main( String[] args ) {
        String config = "main-consume.xml";
        ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
        //从容其中获取业务对象
        ShopService shopService = (ShopService)ctx.getBean("shopService");
        Order order = shopService.buyGoods(1, "thinkpad", 2000, 1);
        System.out.println(order);
    }
}

第五章,dubbo服务化最佳实践

分包
建议将服务接口,服务模型,服务异常等均放在公共包中。
粒度
服务接口尽可能最大粒度,每个服务方法应代表一个功能,而不是某个功能的一个步骤,否则将面临分布式事务的问题,Dubbo暂未提供分布式事务支持。
服务接口建议以业务场景为单位划分,并对相近业务成抽象,防止接口数量爆炸(就是多个功能放在一个方法,而不是多个功能多个方法,否则事务回滚不方便)。
不建议使用过于抽象的通用接口,如:Map query(Map),这样的接口没有明确语义,后期维护困难。
版本
每个接口都应该定义版本号,为后续不兼容升级提供问题,如:<dubbo:service interface=“com.xxx.xxxService” version=“1.0”>。建议使用两位版本号,要变更服务版本,先升级一半提供者为新版本,再将消费者全部升为新版本,然后将剩下的一半提供者升为新版本。

创建公共资源项目
在这里插入图片描述
服务提供者,消费者,网站等多个服务中共用,重复使用的类单独定义在一个项目。
1.创建公共的maven java project
项目名称:node-shop-interface
在这里插入图片描述
2.将之打成jar包,方便后续使用
3.创建node-shop-orderservicenode-shop-userservice两个提供者web项目,这里以其中一个为例,另一个是一样的。
在这里插入图片描述
4.引入依赖

<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.3.14.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>dubbo</artifactId>
      <version>2.6.2</version>
    </dependency>
//node-shop-interface,jar包
    <dependency>
    <groupId>com.rlw</groupId>
    <artifactId>node-shop-interface</artifactId>
    <version>1.0.0</version>
    </dependency>

5.书写服务类impl,注意这里引用的是node-shop-interface项目中的通用接口

package com.rlw.service.impl;
import com.rlw.domain.Order;
import com.rlw.service.OrderService;
import java.util.UUID;
public class OrderServiceImpl implements OrderService {
    @Override
    public Order createOrder(Integer userId, String goodName, float price, int amount) {
        Order order = new Order();
        order.setId(UUID.randomUUID().toString().replaceAll("-",""));
        order.setGoodName("ceshi");
        order.setPrice(111);
        order.setAmount(111);
        return order;
    }
}

6.创建spring容器,配置dubbo

<?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"
       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">

    <!--声名服务名称-->
    <dubbo:application name="node-shop-orderservice"/>

    <!--定义服务端口号-->
    <dubbo:protocol name="dubbo" port="20882"/>
    <!--暴露服务-->
    <dubbo:service interface="com.rlw.service.OrderService"
                   registry="N/A" ref="orderService"/>
    <!--声名服务接口的实现类对象-->
    <bean id="orderService" class="com.rlw.service.impl.OrderServiceImpl"/>
</beans>

7.配置web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:orderservice-provider.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
</web-app>

8.创建消费者web项目node-show-web
在这里插入图片描述
9.引入maven依赖

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.rlw</groupId>
  <artifactId>node-show-web</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>node-show-web Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.3.14.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>dubbo</artifactId>
      <version>2.6.2</version>
    </dependency>

    <dependency>
      <groupId>com.rlw</groupId>
      <artifactId>node-shop-interface</artifactId>
      <version>1.0.0</version>
    </dependency>

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>

    <!--标签库-->
    <dependency>
      <groupId>taglibs</groupId>
      <artifactId>standard</artifactId>
      <version>1.1.2</version>
    </dependency>

  </dependencies>

  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

10书写controller,service,servieImpl,
在serviceImpl调用提供者的服务orderService.buyOrder();或者其他服务者的方法;
11.springmvc配置写好

<?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:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--声名组件扫描器-->
    <context:component-scan base-package="com.rlw.controller"/>
    <!--视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/view/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    <!--注解驱动-->
    <mvc:annotation-driven />
</beans>

12.dubbo消费者的配置,要去找暴露的服务者

<?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"
       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">

    <!--生命服务名称-->
    <dubbo:application name="node-show-web"/>
    <!--声名要使用的远程接口-->
    <dubbo:reference
            interface="com.rlw.service.UserInfoService"
            id="userService"
            registry="N/A"
            url="dubbo://localhost:20881"
            check="false"/>
    <dubbo:reference
            interface="com.rlw.service.OrderService"
            id="orderService"
            registry="N/A"
            url="dubbo://localhost:20882"
            check="false"/>

    <!--生命自定义的service-->
    <bean id="shopService" class="com.rlw.service.impl.ShopServiceImpl">
        <property name="orderService" ref="orderService"/>
        <property name="userInfoService" ref="userService"/>
    </bean>
</beans>

13.测试消费者调用服务者是否成功
在这里插入图片描述
成功调用到了服务者中set的id和名字

第六章,注册中心-Zookerper

注册中心描述
对于服务的提供方,他需要发布服务,而且由于系统应用的复杂性,服务的数量,类型也不断膨胀,对于服务消费方,她最关心如何获取到他所需要的服务,而对复杂的应用系统,需要管理大量的服务调用。
而且,对于服务提供方和服务消费方来说,他们还有可能兼具这两种角色,急需要提供服务,有需要消费服务。通过将服务统一管理起来,可以有效地优化内部应用对服务发布/使用的流程和管理。服务注册中心可以通过特定协议来完成服务对外的统一。Dubbo提供的注册中心有如下几种类型可供选择:

Multicast注册中心:组播方式
Redis注册中心:使用Redis作为注册中心
Simple注册中心:就是一个Dubbo服务。作为注册中心。提供查找服务的功能
Zookeeper注册中心:使用Zookeeper作为注册中心
推荐Zookeeper

注册中心工作方式
在这里插入图片描述

windows安装zookeeper
官网下载,解压,bin目录和config目录为主,bin目录下zkServer.cmd启动zookeeper
在这里插入图片描述

Linux中安装zooleeper
zookeeper上传到home目录下,解压到/usr/local目录下,向windows一样修改配置文件名称为zoo.cfg,其中修改配置与windows一样,别忘了zookeeper需要在jdk的基础之上运行,zkServer.sh启动zookeeper
成功运行
在这里插入图片描述

第七章,使用zookeeper,改造上节dubbo直连方式的项目

两个服务者:举其中一个为例
在这里插入图片描述
1.添加zookeeper的maven依赖:

<!--zookeeper依赖-->
    <dependency>
      <groupId>org.apache.curator</groupId>
      <artifactId>curator-framework</artifactId>
      <version>4.1.0</version>
    </dependency>

2.改变之前的容器中dubbo的配置文件
(1)之前的直连方式改为zookeeper

<?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"
       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">

    <!--声名服务名称-->
    <dubbo:application name="node-shop-orderservice"/>

    <!--定义服务端口号-->
    <dubbo:protocol name="dubbo" port="20882"/>

    <!--zookeeper的注册中心-->
    <dubbo:registry address="zookeeper://localhost:2181"/>

    <!--暴露服务-->
    <dubbo:service interface="com.rlw.service.OrderService"
                   ref="orderService"/>

    <!--声名服务接口的实现类对象-->
    <bean id="orderService" class="com.rlw.service.impl.OrderServiceImpl"/>
</beans>

(2)并且有相应的小改动
在这里插入图片描述
在这里插入图片描述
一个消费者

<?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"
       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">
    <!--生命服务名称-->
    <dubbo:application name="node-show-web"/>
    <!--声名要使用的远程接口-->
    <dubbo:reference
            interface="com.rlw.service.UserInfoService"
            id="userService"
            check="false"/>
    <dubbo:reference
            interface="com.rlw.service.OrderService"
            id="orderService"
            check="false"/>
    <!--声名zookeeper-->
    <dubbo:registry address="zookeeper://localhost:2181"/>
    <!--生命自定义的service-->
    <bean id="shopService" class="com.rlw.service.impl.ShopServiceImpl">
        <property name="orderService" ref="orderService"/>
        <property name="userInfoService" ref="userService"/>
    </bean>
</beans>

在这里插入图片描述
在这里插入图片描述
启动zookeeper:
在这里插入图片描述
一个问题,在启动zookeeper之后,访问服务者后,关掉zookeeper服务后还可以访问到服务者嘛?
答案是可以的,zookeeper在消费者访问服务者的同时就已经将服务者的路径地址缓存起来,之后也是可以访问服务者的,就算zookeeper宕机了也不影响程序的运行,zookeeper接收所有的服务者以供消费者使用。

第八章,dubbo的配置

配置原则
在服务提供者配置访问参数,因为服务提供者更了解服务的各种参数。
关闭检查
dubbo缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,组织Spring初始化完成,一边上线,能及早发现问题,默认check=true。通过check=“false”关闭检查,比如在测试阶段,有些服务不关系,或者出现了循环依赖,必须有一方先起动。
例一:关闭某个服务的启动检查

<dubbo:reference
            interface="com.rlw.service.OrderService"
            id="orderService"
            check="false"/>

例二:关闭注册中心启动时检查

<dubbo:registry check="false"/>

默认启动服务时检查注册中心存在并已运行,注册中心不会报错。
重试次数
消费者访问提供者,如果访问失败,则切换重试访问其他服务器,但重试会带来更长延迟。访问时间变长,用户体验较差,多次重新访问服务器有可能访问成功。可通过retries=“2”来设置重试次数。

<dubbo:service retries="2"/>
//或者
<dubbbo:reference retries="2"/>

超时时间
由于网络或服务端不可靠,会导致调用出现一种不确定的中间状态(超时),为了避免超时导致客户端资源挂起耗尽,必须设置超时时间。
timeout:调用远程服务超时时间(毫秒)

消费端设置

<dubbo:reference interface="com.rlw.xxx" timeout="2000"/>

服务端设置

<dubbo:server interface="com.rlw.xxx" timeout="2000"/>

版本号
消费者指定使用哪个版本
在这里插入图片描述
服务者定义版本
在这里插入图片描述

第九章,监控中心

什么是监控中心
dubbo的使用,其实只需要有注册中心,消费者,提供者这三个就可以使用了,但是并不能看到有哪些消费者和提供者,为了更好的调试,发现问题,解决问题,因此引入了dubbo-admin。通过dubbo-admin可以对消费者和提供者进行管理,可以在dubbo应用部署做动态的调整,服务的管理。
dubbo-admin:
图形化服务管理页面:安装时需要指定注册中心地址,既可以从注册中心中获取到所有的提供者/消费者进行配置管理
dubbo-monitor-simple:
简单的监控中心

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值