sentinel 使用说明


sentinel 使用说明

        

             

                                 

相关依赖

         

        <!-- sentinel starter -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

        <!-- dubbo限流适配器 -->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-apache-dubbo-adapter</artifactId>
        </dependency>

        <!-- sentinel规则存储 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-sentinel-datasource</artifactId>
        </dependency>

        <!-- sentinel网关限流 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
        </dependency>

             

                

                                 

自动配置类

   

spring-cloud-starter-alibaba-sentinel/spring.factories

              

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.alibaba.cloud.sentinel.SentinelWebAutoConfiguration,\
com.alibaba.cloud.sentinel.SentinelWebFluxAutoConfiguration,\
com.alibaba.cloud.sentinel.endpoint.SentinelEndpointAutoConfiguration,\
com.alibaba.cloud.sentinel.custom.SentinelAutoConfiguration,\
com.alibaba.cloud.sentinel.feign.SentinelFeignAutoConfiguration

org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker=\
com.alibaba.cloud.sentinel.custom.SentinelCircuitBreakerConfiguration

             

SentinelAutoConfiguration

@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnProperty(
    name = {"spring.cloud.sentinel.enabled"},
    matchIfMissing = true
)
@EnableConfigurationProperties({SentinelProperties.class})  //从配置文件中读取数据,装配SentinelProperties类
public class SentinelAutoConfiguration {
    @Value("${project.name:${spring.application.name:}}")
    private String projectName;
    @Autowired
    private SentinelProperties properties;

    public SentinelAutoConfiguration() {
    }

    @PostConstruct
    private void init() {   //初始化属性配置
        if (StringUtils.isEmpty(System.getProperty("csp.sentinel.log.dir")) && StringUtils.hasText(this.properties.getLog().getDir())) {
            System.setProperty("csp.sentinel.log.dir", this.properties.getLog().getDir());
        }

        if (StringUtils.isEmpty(System.getProperty("csp.sentinel.log.use.pid")) && this.properties.getLog().isSwitchPid()) {
            System.setProperty("csp.sentinel.log.use.pid", String.valueOf(this.properties.getLog().isSwitchPid()));
        }

        if (StringUtils.isEmpty(System.getProperty("csp.sentinel.app.name")) && StringUtils.hasText(this.projectName)) {
            System.setProperty("csp.sentinel.app.name", this.projectName);
        }

        if (StringUtils.isEmpty(System.getProperty("csp.sentinel.api.port")) && StringUtils.hasText(this.properties.getTransport().getPort())) {
            System.setProperty("csp.sentinel.api.port", this.properties.getTransport().getPort());
        }

        if (StringUtils.isEmpty(System.getProperty("csp.sentinel.dashboard.server")) && StringUtils.hasText(this.properties.getTransport().getDashboard())) {
            System.setProperty("csp.sentinel.dashboard.server", this.properties.getTransport().getDashboard());
        }

        if (StringUtils.isEmpty(System.getProperty("csp.sentinel.heartbeat.interval.ms")) && StringUtils.hasText(this.properties.getTransport().getHeartbeatIntervalMs())) {
            System.setProperty("csp.sentinel.heartbeat.interval.ms", this.properties.getTransport().getHeartbeatIntervalMs());
        }

        if (StringUtils.isEmpty(System.getProperty("csp.sentinel.heartbeat.client.ip")) && StringUtils.hasText(this.properties.getTransport().getClientIp())) {
            System.setProperty("csp.sentinel.heartbeat.client.ip", this.properties.getTransport().getClientIp());
        }

        if (StringUtils.isEmpty(System.getProperty("csp.sentinel.charset")) && StringUtils.hasText(this.properties.getMetric().getCharset())) {
            System.setProperty("csp.sentinel.charset", this.properties.getMetric().getCharset());
        }

        if (StringUtils.isEmpty(System.getProperty("csp.sentinel.metric.file.single.size")) && StringUtils.hasText(this.properties.getMetric().getFileSingleSize())) {
            System.setProperty("csp.sentinel.metric.file.single.size", this.properties.getMetric().getFileSingleSize());
        }

        if (StringUtils.isEmpty(System.getProperty("csp.sentinel.metric.file.total.count")) && StringUtils.hasText(this.properties.getMetric().getFileTotalCount())) {
            System.setProperty("csp.sentinel.metric.file.total.count", this.properties.getMetric().getFileTotalCount());
        }

        if (StringUtils.isEmpty(System.getProperty("csp.sentinel.flow.cold.factor")) && StringUtils.hasText(this.properties.getFlow().getColdFactor())) {
            System.setProperty("csp.sentinel.flow.cold.factor", this.properties.getFlow().getColdFactor());
        }

        if (StringUtils.hasText(this.properties.getBlockPage())) {
            SentinelConfig.setConfig("csp.sentinel.web.servlet.block.page", this.properties.getBlockPage());
        }

        if (this.properties.isEager()) {
            InitExecutor.doInit();
        }

    }

    @Bean
    @ConditionalOnMissingBean
    public SentinelResourceAspect sentinelResourceAspect() {
        return new SentinelResourceAspect();
    }

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnClass(
        name = {"org.springframework.web.client.RestTemplate"}
    )
    @ConditionalOnProperty(
        name = {"resttemplate.sentinel.enabled"},
        havingValue = "true",
        matchIfMissing = true
    )
    public SentinelBeanPostProcessor sentinelBeanPostProcessor(ApplicationContext applicationContext) {
        return new SentinelBeanPostProcessor(applicationContext);
    }   //处理@SentinelRestTemplate

    @Bean
    @ConditionalOnMissingBean
    public SentinelDataSourceHandler sentinelDataSourceHandler(DefaultListableBeanFactory beanFactory, SentinelProperties sentinelProperties, Environment env) {
        return new SentinelDataSourceHandler(beanFactory, sentinelProperties, env);
    }   //sentinel规则数据源处理

    @ConditionalOnClass({ObjectMapper.class})
    @Configuration(
        proxyBeanMethods = false
    )
    protected static class SentinelConverterConfiguration {
        protected SentinelConverterConfiguration() {
        }

        @ConditionalOnClass({XmlMapper.class})
        @Configuration(
            proxyBeanMethods = false
        )
        protected static class SentinelXmlConfiguration {  //解析xml格式规则
            private XmlMapper xmlMapper = new XmlMapper();

            public SentinelXmlConfiguration() {
                this.xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            }

            @Bean({"sentinel-xml-flow-converter"})
            public XmlConverter xmlFlowConverter() {
                return new XmlConverter(this.xmlMapper, FlowRule.class);
            }   //解析限流规则

            @Bean({"sentinel-xml-degrade-converter"})
            public XmlConverter xmlDegradeConverter() {
                return new XmlConverter(this.xmlMapper, DegradeRule.class);
            }   //解析熔断降级规则

            @Bean({"sentinel-xml-system-converter"})
            public XmlConverter xmlSystemConverter() {
                return new XmlConverter(this.xmlMapper, SystemRule.class);
            }   //解析系统限流规则

            @Bean({"sentinel-xml-authority-converter"})
            public XmlConverter xmlAuthorityConverter() {
                return new XmlConverter(this.xmlMapper, AuthorityRule.class);
            }   //解析黑白名单规则

            @Bean({"sentinel-xml-param-flow-converter"})
            public XmlConverter xmlParamFlowConverter() {
                return new XmlConverter(this.xmlMapper, ParamFlowRule.class);
            }   //解析热点限流规则
        }

        @Configuration(
            proxyBeanMethods = false
        )
        protected static class SentinelJsonConfiguration {    //解析json格式规则
            private ObjectMapper objectMapper = new ObjectMapper();

            public SentinelJsonConfiguration() {
                this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            }

            @Bean({"sentinel-json-flow-converter"})
            public JsonConverter jsonFlowConverter() {
                return new JsonConverter(this.objectMapper, FlowRule.class);
            }   //解析限流规则

            @Bean({"sentinel-json-degrade-converter"})
            public JsonConverter jsonDegradeConverter() {
                return new JsonConverter(this.objectMapper, DegradeRule.class);
            }   //解析熔断降级规则

            @Bean({"sentinel-json-system-converter"})
            public JsonConverter jsonSystemConverter() {
                return new JsonConverter(this.objectMapper, SystemRule.class);
            }   //解析系统限流规则

            @Bean({"sentinel-json-authority-converter"})
            public JsonConverter jsonAuthorityConverter() {
                return new JsonConverter(this.objectMapper, AuthorityRule.class);
            }   //解析黑白名单规则

            @Bean({"sentinel-json-param-flow-converter"})
            public JsonConverter jsonParamFlowConverter() {
                return new JsonConverter(this.objectMapper, ParamFlowRule.class);
            }   //解析热点限流规则
        }
    }
}

               

SentinelProperties

@ConfigurationProperties(
    prefix = "spring.cloud.sentinel"
)
@Validated
public class SentinelProperties {
    private boolean eager = false;
    private boolean enabled = true;
    private String blockPage;
    private Map<String, DataSourcePropertiesConfiguration> datasource;
    private SentinelProperties.Transport transport;
    private SentinelProperties.Metric metric;
    private SentinelProperties.Servlet servlet;
    private SentinelProperties.Filter filter;
    private SentinelProperties.Flow flow;
    private SentinelProperties.Log log;
    private Boolean httpMethodSpecify;
    private Boolean webContextUnify;
 
*********
Transport
 
    public static class Transport {
        private String port = "8719";
        private String dashboard = "";
        private String heartbeatIntervalMs;
        private String clientIp;
 
*********
Metric
 
    public static class Metric {
        private String fileSingleSize;
        private String fileTotalCount;
        private String charset = "UTF-8";
 
*********
Servlet
 
    public static class Servlet {
        private String blockPage;
 
*********
Filter
 
    public static class Filter {
        private int order = -2147483648;
        private List<String> urlPatterns = Arrays.asList("/**");
        private boolean enabled = true;
  
*********
Flow
 
    public static class Flow {
        private String coldFactor = "3";
  
*********
Log
 
    public static class Log {
        private String dir;
        private boolean switchPid = false;

           

DataSourcePropertiesConfiguration

public class DataSourcePropertiesConfiguration {
    private FileDataSourceProperties file;     //本地文件存储
    private NacosDataSourceProperties nacos;   //nacos存储
    private ZookeeperDataSourceProperties zk;  //zookeeper存储
    private ApolloDataSourceProperties apollo; //apollo存储
    private RedisDataSourceProperties redis;   //redis存储
    private ConsulDataSourceProperties consul; //consul存储

          

NacosDataSourceProperties

public class NacosDataSourceProperties extends AbstractDataSourceProperties {
    private String serverAddr;
    private String username;
    private String password;
    @NotEmpty
    private String groupId = "DEFAULT_GROUP";
    @NotEmpty
    private String dataId;
    private String endpoint;
    private String namespace;
    private String accessKey;
    private String secretKey;
 
    public NacosDataSourceProperties() {
        super(NacosDataSourceFactoryBean.class.getName());
    }

         

AbstractDataSourceProperties

public class AbstractDataSourceProperties {
    @NotEmpty
    private String dataType = "json";   //数据默认用json格式存储
    @NotNull
    private RuleType ruleType;          //规则类型
    private String converterClass;
    @JsonIgnore
    private final String factoryBeanName;
    @JsonIgnore
    private Environment env;
 
    public AbstractDataSourceProperties(String factoryBeanName) {
        this.factoryBeanName = factoryBeanName;
    }

          

RuleType:限流、熔断降级、热点限流、系统限流、黑白名单、网关限流、网关api限流

public enum RuleType {
    FLOW("flow", FlowRule.class),
    DEGRADE("degrade", DegradeRule.class),
    PARAM_FLOW("param-flow", ParamFlowRule.class),
    SYSTEM("system", SystemRule.class),
    AUTHORITY("authority", AuthorityRule.class),
    GW_FLOW("gw-flow", "com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule"),
    GW_API_GROUP("gw-api-group", "com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition");
 
    private final String name;
    private Class clazz;
    private String clazzName;
 
    private RuleType(String name, Class clazz) {
        this.name = name;
        this.clazz = clazz;
    }
 
    private RuleType(String name, String clazzName) {
        this.name = name;
        this.clazzName = clazzName;
    }
 

            

             

                                 

相关注解

   

@SentinelResource

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface SentinelResource {
    String value() default "";        //资源名称,必填

    EntryType entryType() default EntryType.OUT;
    int resourceType() default 0;

    String blockHandler() default "";  //处理blockException的方法,参数及返回类型需相同,
                                       //方法参数最后也可添加BlockException(可不添加)
    Class<?>[] blockHandlerClass() default {};  //处理blockException的类,对应的函数必需为static函数

    String fallback() default "";        //处理所有异常,指定异常时的服务降级方法,
                                           同时配置fallback、defaultFallback,fallback生效
    String defaultFallback() default ""; //处理所有异常,异常时默认的服务降级处理方法
    Class<?>[] fallbackClass() default {};  //处理所有异常,异常时服务降级处理类

    Class<? extends Throwable>[] exceptionsToTrace() default {Throwable.class};  //需要追踪处理的异常类
    Class<? extends Throwable>[] exceptionsToIgnore() default {};  //忽略处理的异常类,不会统计异常,不会用fallback处理,直接抛出异常
}

             

EntryType

public enum EntryType {
    IN("IN"),
    OUT("OUT");

    private final String name;

    private EntryType(String s) {
        this.name = s;
    }

    public boolean equalsName(String otherName) {
        return this.name.equals(otherName);
    }

    public String toString() {
        return this.name;
    }
}

             

@SentinelResource使用示例

public class TestService {

    // 原函数
    @SentinelResource(value = "hello", blockHandler = "exceptionHandler", fallback = "helloFallback")
    public String hello(long s) {
        return String.format("Hello at %d", s);
    }
    
    // Fallback 函数,函数签名与原函数一致或加一个 Throwable 类型的参数.
    public String helloFallback(long s) {
        return String.format("Halooooo %d", s);
    }

    // Block 异常处理函数,参数最后多一个 BlockException,其余与原函数一致.
    public String exceptionHandler(long s, BlockException ex) {
        // Do some log here.
        ex.printStackTrace();
        return "Oops, error occurred at " + s;
    }

    // 这里单独演示 blockHandlerClass 的配置.
    // 对应的 `handleException` 函数需要位于 `ExceptionUtil` 类中,并且必须为 public static 函数.
    @SentinelResource(value = "test", blockHandler = "handleException", blockHandlerClass = {ExceptionUtil.class})
    public void test() {
        System.out.println("Test");
    }
}

              

             

                                 

限流降级规则

   

RuleConstant:限流降级规则常量

public final class RuleConstant {
    public static final int FLOW_GRADE_THREAD = 0;
    public static final int FLOW_GRADE_QPS = 1;
    public static final int DEGRADE_GRADE_RT = 0;
    public static final int DEGRADE_GRADE_EXCEPTION_RATIO = 1;
    public static final int DEGRADE_GRADE_EXCEPTION_COUNT = 2;
    public static final int DEGRADE_DEFAULT_SLOW_REQUEST_AMOUNT = 5;
    public static final int DEGRADE_DEFAULT_MIN_REQUEST_AMOUNT = 5;
    public static final int AUTHORITY_WHITE = 0;
    public static final int AUTHORITY_BLACK = 1;
    public static final int STRATEGY_DIRECT = 0;
    public static final int STRATEGY_RELATE = 1;
    public static final int STRATEGY_CHAIN = 2;
    public static final int CONTROL_BEHAVIOR_DEFAULT = 0;
    public static final int CONTROL_BEHAVIOR_WARM_UP = 1;
    public static final int CONTROL_BEHAVIOR_RATE_LIMITER = 2;
    public static final int CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER = 3;
    public static final String LIMIT_APP_DEFAULT = "default";
    public static final String LIMIT_APP_OTHER = "other";
    public static final int DEFAULT_SAMPLE_COUNT = 2;
    public static final int DEFAULT_WINDOW_INTERVAL_MS = 1000;

    private RuleConstant() {
    }
}

           

AbstractRule

public abstract class AbstractRule implements Rule {
    private String resource;    //限制的资源名称
    private String limitApp;    //规则针对的调用来源:some_origin、default(不区分来源,默认)、other

    public AbstractRule() {
    }

            

FlowRule:限流规则

public class FlowRule extends AbstractRule {
    private int grade = 1;                  //限流阈值类型:0(并发线程数限流)、1(QPS限流)
    private double count;                   //限流阀值
    private int strategy = 0;               //调用关系限流策略:直接(默认)、链路、关联
    private String refResource;             //关联资源名称
    private int controlBehavior = 0;        //流控效果:直接拒绝(默认)、WarmUp、匀速+排队等待
    private int warmUpPeriodSec = 10;       //流控效果为warm up时,冷启动时长,默认10s
    private int maxQueueingTimeMs = 500;    //流控效果为匀速+排队等待时,最长排队时间
    private boolean clusterMode;            //是否是集群模式
    private ClusterFlowConfig clusterConfig;      //集群限流配置
    private TrafficShapingController controller;  //自定义流控效果

    public FlowRule() {
        this.setLimitApp("default");
    }

    public FlowRule(String resourceName) {
        this.setResource(resourceName);
        this.setLimitApp("default");
    }

       

ClusterFlowConfig:集群流控策略

public class ClusterFlowConfig {
    private Long flowId;               //集群流控id,需保证全局唯一
    private int thresholdType = 0;     //阀值模式:0(单机均摊)、1(全局模式)
    private boolean fallbackToLocalWhenFail = true;  //在 client 连接失败或通信失败时,是否退化到本地的限流模式
    private int strategy = 0;            //限流策略:直接(资源本深,默认)、链路、关联
    private int sampleCount = 10;        //窗口数量
    private int windowIntervalMs = 1000; //窗口统计时长,默认1s

    public ClusterFlowConfig() {
    }

            

              

DegradeRule:降级策略

public class DegradeRule extends AbstractRule {
    private int grade = 0;            //熔断策略:慢调用比例(默认)、异常比例、异常数策略
    private double count;             //熔断阀值(慢调用为最长响应时间)
    private int timeWindow;           //熔断时间窗口
    private int minRequestAmount = 5; //最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断
    private double slowRatioThreshold = 1.0D;  //慢调用比例阈值
    private int statIntervalMs = 1000;         //统计时长(单位为ms)

    public DegradeRule() {
    }

    public DegradeRule(String resourceName) {
        this.setResource(resourceName);
    }

               

ParamFlowRule:热点限流规则

public class ParamFlowRule extends AbstractRule {
    private int grade = 1;                //限流模式,默认为QPS限流
    private Integer paramIdx;             //热点参数的索引
    private double count;                 //限流阀值
    private int controlBehavior = 0;      //流控策略:快速失败(默认)、匀速排队模式
    private int maxQueueingTimeMs = 0;    //最大排队等待时长(仅在匀速排队模式生效), 默认0ms
    private int burstCount = 0;           //应对突发流量额外允许的数量,默认为0
    private long durationInSec = 1L;      //统计窗口时间长度(单位为秒),默认1s
    private List<ParamFlowItem> paramFlowItemList = new ArrayList();  
                                          //参数例外项,针对指定的参数值单独设置限流阈值,
                                          //不受count阈值限制,仅支持基本类型和字符串类型
    private Map<Object, Integer> hotItems = new HashMap();  //额外参数
    private boolean clusterMode = false;                    //是否是集群模式
    private ParamFlowClusterConfig clusterConfig;           //集群流控配置

    public ParamFlowRule() {
    }

    public ParamFlowRule(String resourceName) {
        this.setResource(resourceName);
    }

           

SystemRule:系统流控规则

public class SystemRule extends AbstractRule {
    private double highestSystemLoad = -1.0D;   //系统最高负载
    private double highestCpuUsage = -1.0D;     //系统cpu最高使用率
    private double qps = -1.0D;                 //入口资源的QPS
    private long avgRt = -1L;                   //入口流量的平均响应时间
    private long maxThread = -1L;               //入口流量的最大并发数

    public SystemRule() {
    }

             

AuthorityRule:访问控制规则(黑白名单规则)

public class AuthorityRule extends AbstractRule {
    private int strategy = 0;   //限制模式:白名单模式(默认)、黑名单模式

         

                          

SentinelgateWayConstants:网关限流常量

public final class SentinelGatewayConstants {
    public static final int APP_TYPE_GATEWAY = 1;
    public static final int RESOURCE_MODE_ROUTE_ID = 0;
    public static final int RESOURCE_MODE_CUSTOM_API_NAME = 1;
    public static final int PARAM_PARSE_STRATEGY_CLIENT_IP = 0;
    public static final int PARAM_PARSE_STRATEGY_HOST = 1;
    public static final int PARAM_PARSE_STRATEGY_HEADER = 2;
    public static final int PARAM_PARSE_STRATEGY_URL_PARAM = 3;
    public static final int PARAM_PARSE_STRATEGY_COOKIE = 4;
    public static final int URL_MATCH_STRATEGY_EXACT = 0;
    public static final int URL_MATCH_STRATEGY_PREFIX = 1;
    public static final int URL_MATCH_STRATEGY_REGEX = 2;
    public static final int PARAM_MATCH_STRATEGY_EXACT = 0;
    public static final int PARAM_MATCH_STRATEGY_PREFIX = 1;
    public static final int PARAM_MATCH_STRATEGY_REGEX = 2;
    public static final int PARAM_MATCH_STRATEGY_CONTAINS = 3;
    public static final String GATEWAY_CONTEXT_DEFAULT = "sentinel_gateway_context_default";
    public static final String GATEWAY_CONTEXT_PREFIX = "sentinel_gateway_context$$";
    public static final String GATEWAY_CONTEXT_ROUTE_PREFIX = "sentinel_gateway_context$$route$$";
    public static final String GATEWAY_NOT_MATCH_PARAM = "$NM";
    public static final String GATEWAY_DEFAULT_PARAM = "$D";

    private SentinelGatewayConstants() {
    }
}

              

GateWayFlowRule:网关限流规则

public class GatewayFlowRule {
    private String resource;          //限流资源
    private int resourceMode = 0;     //资源模式:RESOURCE_MODE_ROUTE_ID(0,默认)、RESOURCE_MODE_CUSTOM_API_NAME(1)
    private int grade = 1;            //限流阈值类型:并发线程模式(0)、QPS模式(1,默认)
    private double count;             //限流阀值
    private long intervalSec = 1L;    //统计时间窗口,默认1s
    private int controlBehavior = 0;  //流控效果:快速失败、匀速排队
    private int burst;                //应对突发请求时额外允许的请求数目
    private int maxQueueingTimeoutMs = 500;   //匀速排队模式下的最长排队时间,单位毫秒
    private GatewayParamFlowItem paramItem;   //参数限流配置,若不提供,则代表不针对参数进行限流

    public GatewayFlowRule() {
    }

    public GatewayFlowRule(String resource) {
        this.resource = resource;
    }

              

                 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值