linux进阶-Mycat代理服务器实现读写分离

Mycat代理服务器实现读写分离

Mycat关键特性

  • 支持SQL92标准
  • 遵守MySQL 原生协议,跨语言,跨平台,跨数据库的通用中间件代理
  • 基于心跳的自动故障切换,支持读写分离,支持MySQL主从,以及galera cluster集群
  • 支持Galera for MySQL集群,Percona Cluster或者MariaDB cluster
  • 基于Nio实现,有效管理线程,高并发问题
  • 支持数据的多片自动路由与聚合,支持sum,count,max等常用的聚合函数,支持跨库分页
  • 支持单库内部任意join,支持跨库2表join,甚至基于caltlet的多表join
  • 支持通过全局表,ER关系的分片策略,实现了高效的多表join查询
  • 支持多租户方案
    -支持分布式事务(弱xa)
    -支持全局序列号,解决分布式下的主键生成问题
    -分片规则丰富,插件化开发,易于扩展
  • 强大的web,命令行监控
  • 支持前端作为mysq通用代理,后端JDBC方式支持Oracle、DB2、SQL Server 、 mongodb 、巨
  • 支持密码加密
  • 支持服务降级
  • 支持IP白名单
  • 支持SQL黑名单、sql注入攻击拦截
  • 支持分表(1.6)
  • 集群基于ZooKeeper管理,在线升级,扩容,智能优化,大数据处理(2.0开发版)

为什么要用MyCat

	这里要先搞清楚Mycat和MySQL的区别(Mycat的核心作用)。我们可以把上层看作是对下层的抽象,
例如操作系统是对各类计算机硬件的抽象。那么我们什么时候需要抽象?假如只有一种硬件的时候,我
们需要开发一个操作系统吗?再比如一个项目只需要一个人完成的时候不需要leader,但是当需要几十
人完成时,就应该有一个管理者,发挥沟通协调等作用,而这个管理者对于他的上层来说就是对项目组
的抽象
	同样的,当我们的应用只需要一台数据库服务器的时候我们并不需要Mycat,而如果你需要分库甚至分
表,这时候应用要面对很多个数据库的时候,这个时候就需要对数据库层做一个抽象,来管理这些数据
库,而最上面的应用只需要面对一个数据库层的抽象或者说数据库中间件就好了,这就是Mycat的核心
作用。所以可以这样理解:数据库是对底层存储文件的抽象,而Mycat是对数据库的抽象

Mycat工作原理

在这里插入图片描述

Mycat的原理中最重要的一个动词是“拦截”,它拦截了用户发送过来的SQL语句,首先对SQL语句做了一
些特定的分析:如分片分析、路由分析、读写分离分析、缓存分析等,然后将此SQL发往后端的真实数
据库,并将返回的结果做适当的处理,最终再返回给用户

Mycat应用场景

  • Mycat适用的场景很丰富,以下是几个典型的应用场景
  • 单纯的读写分离,此时配置最为简单,支持读写分离,主从切换
  • 分表分库,对于超过1000万的表进行分片,最大支持1000亿的单表分片
  • 多租户应用,每个应用一个库,但应用程序只连接Mycat,从而不改造程序本身,实现多租户化
  • 报表系统,借助于Mycat的分表能力,处理大规模报表的统计
  • 替代Hbase,分析大数据
  • 作为海量数据实时查询的一种简单有效方案,比如100亿条频繁查询的记录需要在3秒内查询出来
    结果,除了基于主键的查询,还可能存在范围查询或其他属性查询,此时Mycat可能是最简单有效
    的选择
  • Mycat长期路线图
  • 强化分布式数据库中间件的方面的功能,使之具备丰富的插件、强大的数据库智能优化功能、全面
    的系统监控能力、以及方便的数据运维工具,实现在线数据扩容、迁移等高级功能
  • 进一步挺进大数据计算领域,深度结合Spark Stream和Storm等分布式实时流引擎,能够完成快
    速的巨表关联、排序、分组聚合等 OLAP方向的能力,并集成一些热门常用的实时分析算法,让工
    程师以及DBA们更容易用Mycat实现一些高级数据分析处理功能
  • 不断强化Mycat开源社区的技术水平,吸引更多的IT技术专家,使得Mycat社区成为中国的
    Apache,并将Mycat推到Apache
    基金会,成为国内顶尖开源项目,最终能够让一部分志愿者成为专职的Mycat开发者,荣耀跟实力
    一起提升

Mycat不适合的应用场景

  • 设计使用Mycat时有非分片字段查询,请慎重使用Mycat,可以考虑放弃!
  • 设计使用Mycat时有分页排序,请慎重使用Mycat,可以考虑放弃!
  • 设计使用Mycat时如果要进行表JOIN操作,要确保两个表的关联字段具有相同的数据分布,否则请
    慎重使用Mycat,可以考虑放弃!
  • 设计使用Mycat时如果有分布式事务,得先看是否得保证事务得强一致性,否则请慎重使用
    Mycat,可以考虑放弃!

MyCat的高可用性:

需要注意: 在生产环境中, Mycat节点最好使用双节点, 即双机热备环境, 防止Mycat这一层出现单点故障.
可以使用的高可用集群方式有:

  • Keepalived+Mycat+Mysql
  • Keepalived+LVS+Mycat+Mysql
  • Keepalived+Haproxy+Mycat+Mysql

Mycat安装目录结构

bin

  • mycat命令,启动、重启、停止等

catlet

  • catlet为Mycat的一个扩展功能

conf

  • Mycat 配置信息,重点关注

lib

  • Mycat引用的jar包,Mycat是java开发的

logs

  • 日志文件,包括Mycat启动的日志和运行的日志

version.txt mycat版本说明
logs目录:
wrapper.log

  • mycat启动日志
    mycat.log
  • mycat详细工作日志

Mycat的配置文件都在conf目录里面,这里介绍几个常用的文件:
server.xml

  • Mycat软件本身相关的配置文件,设置账号、参数等
    schema.xml
  • Mycat对应的物理数据库和数据库表的配置,读写分离、高可用、分布式策略定制、
    节点控制
    rule.xml
  • Mycat分片(分库分表)规则配置文件,记录分片规则列表、使用方法等

Mycat 主要配置文件说明

server.xml
存放Mycat软件本身相关的配置文件,比如:连接Mycat的用户,密码,数据库名称等
server.xml文件中配置的参数解释说明:
参数 说明
user 用户配置节点
name 客户端登录MyCAT的用户名,也就是客户端用来连接Mycat的用户名。
password 客户端登录MyCAT的密码
schemas 数据库名,这里会和schema.xml中的配置关联,多个用逗号分开,例如:db1,db2
privileges 配置用户针对表的增删改查的权限
readOnly mycat逻辑库所具有的权限。true为只读,false为读写都有,默认为false
注意:
server.xml文件里登录mycat的用户名和密码可以任意定义,这个账号和密码是为客户机登录
mycat时使用的账号信息
逻辑库名(如上面的TESTDBt,也就是登录mycat后显示的库名,切换这个库之后,显示的就是代
理的真实mysql数据库的表)要在schema.xml里面也定义,否则会导致mycat服务启动失败!
这里只定义了一个标签,所以把多余的都注释了。如果定义多个标签,即设置多个连接mycat的用
户名和密码,那么就需要在schema.xml文件中定义多个对应的库!
schema.xml
是最主要的配置项,此文件关联mysql读写分离策略,读写分离、分库分表策略、分片节点都是在此文
件中配置的.MyCat作为中间件,它只是一个代理,本身并不进行数据存储,需要连接后端的MySQL物
理服务器,此文件就是用来连接MySQL服务器的
schema.xml文件中配置的参数解释说明:
#配置环境变量
vim /etc/profile.d/mycat.sh
PATH=/app/mycat/bin:$PATH
source /etc/profile.d/mycat.sh
#启动
mycat start
#查看日志,确定成功
cat /app/mycat/logs/wrapper.log
...省略...
INFO | jvm 1 | 2019/11/01 21:41:02 | MyCAT Server startup successfully. see
logs in logs/mycat.log
#连接mycat:
mysql -uroot -p123456 -h 127.0.0.1 -P8066
参数 说明
schema 数据库设置,此数据库为逻辑数据库,name与server.xml中schema对应
dataNode 分片信息,也就是分库相关配置
dataHost 物理数据库,真正存储数据的数据库
配置说明
name属性唯一标识dataHost标签,供上层的标签使用。
maxCon属性指定每个读写实例连接池的最大连接。也就是说,标签内嵌套的writeHost、readHost标
签都会使用这个属性的值来实例化出连接池的最大连接数
minCon属性指定每个读写实例连接池的最小连接,初始化连接池的大小
每个节点的属性逐一说明
schema:
属性 说明
name 逻辑数据库名,与server.xml中的schema对应
checkSQLschema 数据库前缀相关设置,这里为false
sqlMaxLimit select 时默认的limit,避免查询全表
table
属性 说明
name 表名,物理数据库中表名
dataNode 表存储到哪些节点,多个节点用逗号分隔。节点为下文dataNode设置的name
primaryKey 主键字段名,自动生成主键时需要设置
autoIncrement 是否自增
rule 分片规则名,具体规则下文rule详细介绍
dataNode
属性 说明
name 节点名,与table中dataNode对应
datahost 物理数据库名,与datahost中name对应
database 物理数据库中数据库名
dataHost
属性 说明
name 物理数据库名,与dataNode中dataHost对应
balance 均衡负载的方式
writeType 写入方式
dbType 数据库类型
heartbeat 心跳检测语句,注意语句结尾的分号要加
schema.xml文件中有三点需要注意:balance="1",writeType="0" ,switchType="1"
schema.xml中的balance的取值决定了负载均衡对非事务内的读操作的处理。balance 属性负载均衡类
型,目前的取值有 4 种:
balance="0": 不开启读写分离机制,所有读操作都发送到当前可用的writeHost 上,即读请求仅发送
到writeHost上
balance="1": 读请求随机分发到当前writeHost对应的readHost和standby的writeHost上。即全部
的readHost与stand by writeHost 参与 select 语句的负载均衡,简单的说,当双主双从模式(M1 ->S1
, M2->S2,并且 M1 与 M2 互为主备),正常情况下, M2,S1, S2 都参与 select 语句的负载均衡
balance="2": 读请求随机分发到当前dataHost内所有的writeHost和readHost上。即所有读操作都
随机的在writeHost、 readhost 上分发
balance="3": 读请求随机分发到当前writeHost对应的readHost上。即所有读请求随机的分发到
wiriterHost 对应的 readhost 执行, writerHost 不负担读压力,注意 balance=3 只在 1.4 及其以后版本
有,1.3 没有
writeHost和readHost 标签
这两个标签都指定后端数据库的相关配置给mycat,用于实例化后端连接池。
唯一不同的是:writeHost指定写实例、readHost指定读实例,组着这些读写实例来满足系统的要求。
在一个dataHost内可以定义多个writeHost和readHost。但是,如果writeHost指定的后端数据库宕
机,那么这个writeHost绑定的所有readHost都将不可用。
另一方面,由于这个writeHost宕机系统会自动的检测到,并切换到备用的writeHost上去
注意:
Mycat主从分离只是在读的时候做了处理,写入数据的时候,只会写入到writehost,需要通过mycat的
主从复制将数据复制到readhost

实验开始

实验准备

192.168.26.18   #充当mycat
192.168.26.17   #充当master
192.168.26.27   #充当slave-1
192.168.26.37   #充当slave-2

//关闭防火墙
systemctl disable firewalld
//关闭selinux
setenforce 0   #临时关闭

sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config   #改配置文件
//时间同步
yum install -y ntpdate   #安装服务
systemctl start ntpdate   #开启服务
ntpdate 域名/IP   #同步时间

Mycat相关配置

//下载安装JDK
[root@mycat mycat]# yum -y install java
[root@mycat mycat]# java -version
openjdk version "1.8.0_232"
OpenJDK Runtime Environment (build 1.8.0_232-b09)
OpenJDK 64-Bit Server VM (build 25.232-b09, mixed mode)
--------------------------------------------------------
//下载安装mycat
[root@test-cp mycat]# mkdir/data/app/;cd /data/app;wget http://dl.mycat.io/1.6-RELEASE/Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz;tar -xf /data/app/Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz

[root@test-cp mycat]# ls /data/app/mycat
bin  catlet  conf  lib  logs  version.txt
-------------------------------------------------------
//定义PATH变量
[root@mycat data]# echo "PATH=/data/app/mycat/bin:$PATH" > /etc/profile.d/mycat.sh 
-------------------------------------------------------

Master相关配置

yum -y install mariadb-server   #安装服务
systemctl start mariadb.service   #启动服务
---------------------------------------
vim /etc/my.cnf.d/server.cnf

//编辑配置文件添加一下数据
[mysqld]
server_id=17   #全网唯一ID
log_bin   #开启二进制日志
skip_name_resolve = on   #此项一定要加,禁止将IP地址解析成域名
---------------------------------------
systemctl restart mariadb.service   #重启服务
--------------------------------------
//安全加固,设置root密码
[root@次联slave ~]# mysql_secure_installation

//登录mysql
[root@次联slave ~]#mysql -u用户名 -p密码

//创建有复制权限的用户账户给slave使用
MariaDB [(none)]> GRANT REPLICATION SLAVE ON *.* TO repliuser@'192.168.26.%' IDENTIFIED BY 'centos';
Query OK, 0 rows affected (0.00 sec)

//可用于刷新用户权限
MariaDB [(none)]> FLUSH PRIVILEGES; 
Query OK, 0 rows affected (0.00 sec)
---------------------------------------
MariaDB [(none)]> SHOW MASTER STATUS;   #查看主节点状态
+--------------------+----------+--------------+------------------+
| File               | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+--------------------+----------+--------------+------------------+
| mariadb-bin.000001 |      476 |              |                  |
+--------------------+----------+--------------+------------------+
1 row in set (0.00 sec)

Slave-1相关配置

yum -y install mariadb-server   #安装服务
systemctl start mariadb.service   #启动服务
---------------------------------------
vim /etc/my.cnf.d/server.cnf

//编辑配置文件添加一下数据
[mysqld]
server_id=27   #全网唯一ID
---------------------------------------
systemctl restart mariadb.service   #重启服务
---------------------------------------
MariaDB [(none)]> CHANGE MASTER TO
    ->   MASTER_HOST='192.168.26.17',
    ->   MASTER_USER='repliuser',
    ->   MASTER_PASSWORD='centos',
    ->   MASTER_PORT=3306,
    ->   MASTER_LOG_FILE='mariadb-bin.000001',
    ->   MASTER_LOG_POS=476,
    ->   MASTER_CONNECT_RETRY=10;
Query OK, 0 rows affected (0.01 sec)

MariaDB [(none)]> START SLAVE;   #开启从节点
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> SHOW SLAVE STATUS\G   #查看从节点状态
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.26.17
                  Master_User: repliuser
                  Master_Port: 3306
                Connect_Retry: 10
              Master_Log_File: mariadb-bin.000001
          Read_Master_Log_Pos: 476
               Relay_Log_File: mariadb-relay-bin.000002
                Relay_Log_Pos: 531
        Relay_Master_Log_File: mariadb-bin.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 476
              Relay_Log_Space: 827
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 17
1 row in set (0.00 sec)

Slave-2相关配置

yum -y install mariadb-server   #安装服务
systemctl start mariadb.service   #启动服务
---------------------------------------
vim /etc/my.cnf.d/server.cnf

//编辑配置文件添加一下数据
[mysqld]
server_id=37   #全网唯一ID
---------------------------------------
systemctl restart mariadb.service   #重启服务
---------------------------------------
MariaDB [(none)]> CHANGE MASTER TO
    ->   MASTER_HOST='192.168.26.17',
    ->   MASTER_USER='repliuser',
    ->   MASTER_PASSWORD='centos',
    ->   MASTER_PORT=3306,
    ->   MASTER_LOG_FILE='mariadb-bin.000001',
    ->   MASTER_LOG_POS=476,
    ->   MASTER_CONNECT_RETRY=10;
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> START SLAVE;   #开启从节点
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> SHOW SLAVE STATUS\G   #查看从节点状态
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.26.17
                  Master_User: repliuser
                  Master_Port: 3306
                Connect_Retry: 10
              Master_Log_File: mariadb-bin.000001
          Read_Master_Log_Pos: 476
               Relay_Log_File: mariadb-relay-bin.000002
                Relay_Log_Pos: 531
        Relay_Master_Log_File: mariadb-bin.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 476
              Relay_Log_Space: 827
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 17
1 row in set (0.00 sec)

用默认密码123456来尝试连接mycat

[root@mycat data]# mysql -uroot -p123456 -h 127.0.0.1 -P8066
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.6.29-mycat-1.6-RELEASE-20161028204710 MyCat Server (OpenCloundDB)

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

在mycat 服务器上修改server.conf 文件配置Mycat的连接信息

vim /data/app/mycat/conf/server.xml

在这里插入图片描述


图解

<user name="bokebi">   #连接mycat的用户名
        <property name="password">centos</property>   #连接mycat的用户密码
        <property name="schemas">TESTDB</property>   #数据库名要和schema.xml相对应

修改schema.xml实现读写分离策略

vim /data/app/mycat/conf/schema.xml 

在这里插入图片描述

//master的上查看库文件
MariaDB [(none)]> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| hellodb            |
| mysql              |
| performance_schema |
+--------------------+
4 rows in set (0.01 sec)

//master上创建与mycat服务器对应的数据库
MariaDB [(none)]> CREATE DATABASE mycat;
Query OK, 1 row affected (0.00 sec)

MariaDB [(none)]> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| hellodb            |
| mycat              |
| mysql              |
| performance_schema |
+--------------------+
5 rows in set (0.00 sec)

//master创建允许登录mycat服务器的账户
//与/data/app/mycat/conf/server.xml配置文件中账户和密码所匹配
MariaDB [(none)]> GRANT ALL ON *.* TO 'bokebi'@'192.168.26.18' IDENTIFIED BY 'centos' WITH GRANT OPTION;
Query OK, 0 rows affected (0.00 sec)

//刷新用户权限
MariaDB [(none)]> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)

测试实验结果

//使用在master上创建的授权用户在mycat登录
[root@mycat ~]# mysql -ubokebi -pcentos -h127.0.0.1 -P8066 -DTESTDB
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.6.29-mycat-1.6-RELEASE-20161028204710 MyCat Server (OpenCloundDB)

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

//在mycat服务器上唯一的库TESTDB中创建t1表
MySQL [TESTDB]> CREATE TABLE t1(id int);
Query OK, 0 rows affected (0.002 sec)

MySQL [TESTDB]> SHOW TABLES;   #查看得
+-----------------+
| Tables_in_mycat |
+-----------------+
| t1              |
+-----------------+
1 row in set (0.002 sec)

-------------------------------------------
//master服务器
[root@master ~]# mysql -uroot -pcentos   #master进入数据库
------------------------------------------
MariaDB [(none)]> USE mycat;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [mycat]> SHOW TABLES;   #查看得
+-----------------+
| Tables_in_mycat |
+-----------------+
| t1              |
+-----------------+
1 row in set (0.00 sec)
--------------------------------------------
//slave-1服务器
[root@slave-1 ~]# mysql -uroot -pcentos   #slave-1进入数据库
--------------------------------------------
MariaDB [(none)]> USE mycat;
Database changed
MariaDB [mycat]> SHOW TABLES;   #查看得
+-----------------+ 
| Tables_in_mycat |
+-----------------+
| t1              |
+-----------------+
1 row in set (0.00 sec)
--------------------------------------------
//slave-2服务器
[root@slave-2 ~]# mysql -uroot -pcentos   #slave-2进入数据库
-------------------------------------------
MariaDB [(none))]> USE mycat;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [mycat]> SHOW TABLES;   #查看得
+-----------------+
| Tables_in_mycat |
+-----------------+
| t1              |
+-----------------+
1 row in set (0.00 sec)
-------------------------------------------

通过通用日志确认实现读写分离

在mysql中查看通用日志

  • show variables like ‘general_log’; #查看日志是否开启
  • set global general_log=on; #开启日志功能
  • show variables like ‘general_log_file’; #看看日志文件保存位置
  • set global general_log_file=‘tmp/general.log’; #设置日志文件保存位置
[root@centos8 ~]#vim /etc/my.cnf.d/server.cnf

//在master,slave-1,slave-2中的配置文件中修改配置文件添加以下数据
[mysqld]
general_log=ON   #开启通用日志
general_log_file=/var/lib/mysql/general.log   #自定义通用日志路径
--------------------------------------------
[root@centos8 ~]#systemctl restart mariadb   #重启服务
------------------------------------------- 
[root@centos8 ~]#tail -f /var/lib/mysql/general.log   #追踪通过日志
-------------------------------------------

Mycat服务器中查询t1表内容

在这里插入图片描述


Slave-1通用日志文件内容显示

在这里插入图片描述


Slave-2通用日志文件内容显示

在这里插入图片描述


Mycat服务器中在t1表表中插入数据2

在这里插入图片描述


Master通用日志文件内容显示

在这里插入图片描述


Slave-1通用日志文件内容显示

在这里插入图片描述


Slave-2通用日志文件内容显

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值