【0000】PostgreSQL V13.2源码剖析专栏总目录(2024.07.27 更新)


在这里插入图片描述

本专栏将会持续更新,直到将PostgreSQL V13.2内核源码涉及的所有原理与技术剖析完成为止。每一篇文章都是经过若干次的源码阅读 + 调试,且得以验证结论之后才梳理成文章形式;同时,每篇文章都附有大量的逻辑图 + 原理实现图,做到真正的图文并茂。最终该专栏的文章数量约在上千篇左右,这也是文章序号从【0000】开始的缘故。通过本专栏的学习,能够让你快速深入掌握Postgres内核中的每个技术的底层的实现原理。


🏅 1. pg系统架构

【0001】PostgreSQL 数据库系统架构
【0024】PostgreSQL V13 可观察性更新
【0160】PostgreSQL V13.2内核源码组织架构图

🏅 1.1 源码编译安装

【0042】源码编译安装PostgreSQL

🏅 1.2 PG内核客户端认证

【0179】配置PostgreSQL以允许远程连接
【0180】PG内核通过pg_hba.conf完成客户端认证(1)
【0181】PG内核通过pg_hba.conf完成客户端认证(2)
【0182】PG内核客户端认证之将读取的token创建HbaToken(3)
【0183】PG内核客户端认证之将读取的token创建HbaToken(3 - 1)
【0184】PG内核客户端认证之HbaToken列表初始化为TokenizedLine(4)
【0185】PG内核客户端认证之HbaLine(5)
【0187】客户端身份验证配置文件视图之pg_hba_file_rules
【0188】PG内核之pqsignal 信号实现机制(1)
【0194】PG内核之pqsignal 信号实现机制(2) 【0189】UNIX域套接字(UNIX Domain Socket)(1)
【0190】Unix 域套接字实战(2)

🏅 2. 实现原理

【0003】 PostgreSQL所能支持的验证方法
【0004】 关于PostgreSQL数据库版本从9.2.24升级到PostgreSQL11.5的方案
【0005】 详聊PostgreSQL中 GROUP BY(分组)的使用
【0006】 PostgreSQL数据库程序命令列表
【0007】 PostgreSQL配置管理日志(一)
【0022】 LZ压缩算法工作原理
【0023】 使用GDB来调试研究PostgreSQL源码
【0026】 pg_ctl启动PostgreSQL服务,提示启动成功(server started),实际上服务并未起来
【0027】 PostgreSQL进程被意外杀死
【0035】 深挖PostgreSQL中两个(或多个)字段同时order by 时内部的潜在规则
【0036】 pg_ctl启动服务报错:stopped waiting, pg_ctl: could not start server,Examine the log output.
【0038】 PostgreSQL数据表中的列(字段)的最大数量限制
【0043】 专栏目录介绍
【0044】 PostgreSQL源码层如何实现创建数据库(CREATE DATABASE)
【0045】 词法分析器lex工作原理
【0046】 你的Postgres查询是否缺少内存?
【0047】 修改WAL文件大小的2种方式
【0048】 PostgreSQL 13 EXPLAIN包含WAL信息
【0050】 快速查找所有存在继承(inherit)关系的父表和子表
【0069】 查看PostgreSQL数据库启动时间的两种方式
【0071】 全网最详细的MySQL教程(包括增、删、改、查、建表、建库等)
【0073】 20个经典面试题,全部答对月薪30k+
【0074】 mysql api编程(五) 预处理的实现
【0075】 mysql api编程(二)
【0076】 mysql api编程(四) 查询
【0077】 mysql api编程(一)
【0078】《Mysql必知必会》阅读总结
【0079】某知名公司的两道sql面试题
【0082】借助性能调优工具来配置postgresql.conf中的选项参数
【0083】PostgreSQL允许最大后台进程(background worker processes)数量是多少?
【0084】PostgreSQL服务启动注册后台进程(background worker)应用启动器(BackgroundWorkerList)
【0091】你的进程最多能打开多少个文件描述符fd?
【0104】查找PostgreSQL数据库和表的大小
【0118】PostgreSQL 14.4修复了索引损坏
【0119】PostgreSQL FMS(Free Space Map)
【0173】推荐6款最好使用的PostgreSQL GUI工具

🏅 2.1 创建postmaster守护进程

【0105】postmaster服务不能以root身份运行
【0205】哪些信号可kill掉postmaster?内核如何实现?

🏅 2.2 创建postgres后端进程(Backend Process)

【0085】PostgreSQL最多可以支持listen_addresses绑定到多少个IP上(1)?
【0087】PostgreSQL创建监听端口的底层原理(2)
【0088】PostgreSQL创建监听端口的底层原理(3)
【0092】PostgreSQL为客户端的socket请求创建后端进程postgres(5)
【0094】为客户端的socket请求创建postgres之子进程从postmaster主进程分离(6)
【0099】如何在 Postgres 或任何数据库中有效地管理连接
【0123】PostgreSQL注册postmaster进程或后端进程退出(exit-time)时的清理回调
【0124】postgres后端进程实现打印登录客户端的ip与port信息
【0126】Latch中self-pipe trick的应用机制(7)
【0127】Latch的实现机制与原理分析(8-1)
【0128】Latch的实现机制与原理分析(8-2)
【0129】Latch机制是pselect()的一种实现
【0140】postmaster接收并处理client发送的startup packet(9)
【0141】postgres进程process title的设计机制(10)
【0142】设置Backend的argument list(11)
【0153】深入分析postgres接收libpq诸如insert、delete、update、select . . . 等命令的实现原理
【0154】对接收来自libpq客户端的command进行解析处理(2)
【0199】揭晓PG内核使用BackendList去跟踪active进程的实现机制
【0200】psql如何得知postmaster中 backend fork()失败
【0201】PG内核查找 BackendList 中指定PID,并kill()掉
【0202】PG内核通过捕捉SIGHUP信号,完成config file(postgresql.conf、pg_hba.conf、pg_ident.conf)重加载
【0214】postgres后端进程session退出,如何通过日志分析其会话信息
【0020】 一文搞懂PostgreSQL中的扩展(extension)特性
【0244】pg_ctl停止PG服务的底层实现机制
【0245】postmaster通过状态机(state machine)控制startup、shutdown和crash recovery的实现分析
【0251】如何让pg生成core文件,并通过gdb工具定位到pg服务异常崩溃点(精确到函数行)
【0255】揭晓pg内核中MyBackendId的分配机制(后端进程Id,BackendId)(一)
【0256】揭晓pg内核中MyBackendId的分配机制(后端进程Id,BackendId)(二)
【0265】postmaster守护进程入口

🏅 2.2.1 PGPROC

【0267】pg内核初始化 process table(ProcGlobal、PROC_HDR、PGPROC)分析
【0268】深入分析PG内核 shared PGPROC array(ProcArrayStruct、procArray)初始化机制
【0269】揭晓pg内核procArray、MyProc、ProcGlobal三者间的微妙关系
【0270】揭晓postgres内核procArray中添加MyProc的实现机制
【0271】postgres内核共享数组(procArray)移除指定MyProc(PGPROC)
【0287】Postgres内核在pg_internal.init不存在情况下的relcache cache初始化实现
【0288】Postgres内核处理 utility类命令(eg:create、copy、vacuum、destroy等)的实现机制

🏅 2.2.2 relcache

【0273】深入分析 relcache(relation descriptor cache)初始化第一阶段(1)
【0264】深入分析初始化relcache的第二阶段(2)
【0274】从shared init file或local init file加载relation cache(2 - 1)
【0277】深入分析 relcache(relation descriptor cache)初始化第三阶段(3)

🏅 2.2.3 syscache(System catalog cache)

【0275】深入分析PG内核初始化 system catalog cache
【0276】揭晓PG内核 CatCache、CatCacheHeader类型的作用、及对应变量(SysCache、CacheHdr)初始化过程

🏅 2.3 XLOG

【0106】WAL之初始化XLOG访问(1)
【0107】启动XLOG机制(1)
【0109】PostgreSQL配置WAL Archive
【0111】初始化XLogReader
【0112】检查信号恢复文件recovery.conf
【0113】清除旧的relcache缓存文件述
【0117】pg_multixact管理器

🏅 3. 存储管理

🏅 3.1 VFD机制

【0025】 详聊PostgreSQL中VFD(Virtual File Descriptor)实现原理
【0161】 VFD如何打开一个文件?
【0164】 VFD打开32、64、128 …个文件时,VfdCache数组的内部变化情况
【0165】 VfdCache关闭内核文件描述符fd
【0166】 VfdCache关闭数组中所有文件描述符fd
【0167】 再谈谈PG如何管理DIR、FILE和unbuffered fd
【0168】 PG内核通过AllocateDesc返回DIR中下一个directory entry
【0169】 PG内核如何关闭AllocateDesc中的DIR(目录流)

🏅 3.2 内存上下文(Memory Context)

【0097】彻底掌握 MemoryContext 实现原理(1)
【0095】PostgreSQL MemoryContext系统设计(2)
【0100】MemoryContext内存申请(3)
【0096】各全局MemoryContext变量初始化顺序(4)
【0101】获取给定内存片(chunk)所占用的总空间(5)
【0102】计算AllocSet内存消耗统计信息(6)
【0103】重置内存上下文(AllocSetReset)(7)
【0174】删除MemoryContext中分配的所有内存(8 - 1)
【0175】如何利用context_freelists[]来删除MemoryContext中分配的所有内存(8 - 2)
【0176】PG内核如何完成MemoryContext的对外封装,以提供其他模块调用?(9)

🏅 3.3 共享内存(Shared Memory)

【0143】System V共享内存(Shared Memory)
【0144】postmaster创建System V Shared Memory(共享内存)的背后机制(1)
【0145】postmaster创建System V shared memory默认值大小(2)
【0146】判断System V shared memory以前的段是否存在并正在使用?(3)
【0147】当参数shared_memory_type分别为sysv和mmap时,差异为何如此大?
【0195】共享内存管理结构(shmem)之概念篇(1)
【0196】共享内存管理结构(shmem)之创建共享内存分配机制(Shared Memory Allocation)(2 - 1)
【0257】关于pg内核shared cache invalidation messages (概念篇)
【0258】pg内核支持的所有 inval messages 类型
【0266】postmaster创建共享内存(shared memory)、信号量(semaphores)(2 - 2)

3.3.1 动态哈希表(Dynamic Hash Tables)

【0286】Postgres内核 shared buffer pool 初始化实现
【0289】Postgres内核之哈希表(Hash Tables)
【0290】Postgres内核动态哈希表实现机制(1)
【0291】Postgres内核之dynahash table 创建 (2)
【0292】Postgres内核源码之dynahash 插入entry实现
【0293】Postgres内核之创建 dynahash table 解惑
【0294】Postgres内核 dynahash 之 hash_search 实现原理
【0295】Posgres内核 dynahash table 之 hash_search 实现原理(2)
【0296】Posgres内核 dynahash table 之 hash_search 实现原理(3)

🏅 3.4 磁盘管理器

【0171】 揭晓PG中各种缓存技术的实现原理
【0039】 一文搞懂PostgreSQL中的TOAST技术
【0040】 数据库表文件底层结构布局分析
【0041】 一文搞懂PostgreSQL中的template1、template0和postgres系统数据库
【0186】 SQL 的演变:SQL 标准的过去、现在和未来

🏅 3.4.1 磁盘介质管理器SMGR

【0170】 PG内核中的存储管理器(Storage Managers)究竟是什么?(0)
【0222】存储管理器SMGR设计机制,及SMgrRelation、SMgrRelationData的作用(基础篇)
【0223】源码剖析smgr底层设计机制(3)
【0224】源码分析RelFileNode对smgr访问磁盘表文件的重要性(2)
【0225】源码分析postgres磁盘块(disk block)定义
【0226】 smgr设计机制中,segment、block究竟意味着什么述

🏅3.5 进程间通信(IPC)

【0125】详聊Linux下文件锁
【0148】System V Semaphores(信号量)
【0149】System V IPC之消息队列(Message Queue)
【0150】PostgreSQL常用命令总结表
【0152】深入分析multiplex SIGALRM interrupts(1)
【0155】multiplex SIGALRM interrupts应用场景一:阻止恶意客户端连接攻击
【0158】Linux下进程与线程
【0159】Linux下利用getrlimit()、setrlimit()分别获取/设置资源限制
【0177】Linux中POSIX信号量实现机制

🏅 3.5.1 logger(日志收集器进程)

【0008】 SysLogger日志收集器的工作原理
【0017】 如何评估PostgreSQL中进程可打开最大文件描述符数量

🏅 3.5.2 checkpointer

【0108】checkpoint运行原理(1)
【0247】PG内核checkpoint实现机制分析(2)
【0278】checkpointer 共享内存(CheckpointerShmem)初始化(3)
【0279】深入分析 checkpointer process实现机制

🏅3.5.3 background writer

【0248】Background Writing实现机制分析

🏅3.5.4 walwriter

【0246】深入分析PG内核Write-Ahead Log的实现机制
【0250】深入分析Write-Ahead Log Fault Tolerance(WAL容错)

🏅 3.5.5 autovacuum launcher

【0019】 一文搞懂PostgreSQL中VACUUM 与 VACUUM FULL

🏅 3.5.6 stats collector

【0215】stats collector(统计信息收集器)工作原理之资源初始化(1)
【0216】stats collector(统计信息收集器)资源初始化之获取IPV4套接字地址信息(2)
【0217】stats collector(统计信息收集器)进程启动原理(1)
【0219】一文搞懂global.stat、global.tmp、db_*.stat等统计文件的格式,以及文件组成原理
【0220】stats collector如何得知pgStatSock中的消息类型、消息报文内容以及消息是否完整?
【0234】PgBackendStatus 记录当前postgres进程的活动状态
【0235】修改私有内存(private memory)中的MyBEEntry时,st_changecount值前后变化

🏅3.6 JSON

【0172】cJSON库源码剖析

🏅 3.7 PG系统文件

【0002】 postgresql.conf配置文件详解
【0015】 彻底搞懂postgresql.auto.conf 与 postgresql.conf 之间的差异
【0009】 postmaster.pid文件都存储了什么?
【0010】 从源码级分析pg_control文件的作用
【0011】 PostgreSQL中的辅助进程是如何实现带有前缀“postgres:”的?
【0014】 正在运行中的PostgreSQL服务,如果postmaster.pid文件被删或是内容被修改,会发生什么?
【0016】 从源码级分析postmaster.opts文件
【0260】pg_filenode.map文件分析(内含map文件读取、解析demo)

🏅 3.8 锁

🏅 3.8.1 轻量级锁(Lightweight Lock)

【0191】轻量级锁(LWLock,Lightweight lock)概念篇(1)
【0192】轻量级锁(LWLock,Lightweight lock)之释放锁(LWLockRelease())(2)
【0193】PG内核之释放PGPROC机制
【0198】PGPROC数据结构
【0252】深入分析 Memory Structures 锁

🏅 4. 事务系统

4.1 概念篇

【0021】从源码级来详聊PostgreSQL中事务系统(一)
【0282】Postgres内核 ResourceOwner(资源所有者,Resource Owners)原理分析
【0283】Postgres内核创建一个空的 ResourceOwner

🏅 4.1 事务系统层次划分

【0230】PG内核事务(transaction)系统实现原理之层次划分(上)
【0231】PG内核事务(transaction)系统实现原理之层次划分(下)
【0232】通过PG log分析事务系统(StartTransaction)的运行情况

4.2 实现篇

【0037】查看PostgreSQL当前事务隔离级别
【0072】mysql api编程(三) 事务
【0259】inval.h/inval.c的理解

🏅 4.3 多版本并发控制(MVCC)

【0018】 详聊PostgreSQL的中MVCC(多版本并发控制)底层实现原理
【0116】PostgreSQL/MVCC

🏅5. 查询处理器

🏅 5.1 解析器(Parser)

【0236】聊一聊PG内核中的命令标签(Command Tags、CommandTag、tag_behavior)
【0238】flex/yacc之PG内核parser
【0239】从编译原理角度理解 #include “xxx“ 或 #include<xxx> 的实现机制
【0240】源码分析PG内核中的关键字列表(SQL keywords)
【0241】Parser解析分析统计信息(PARSE ANALYSIS STATISTICS)
【0253】深入分析Query Execution(一)
【0254】深入分析Query Execution(二)
【0261】pg内核 raw parsetree 深入分析(一)
【0262】PG内核查询树(Query Tree)、Query结构随手记
【0263】深入分析pg内核 Parse tree(解析树)到Query tree(查询树)的转换实现
【0284】Postgres内核分析 raw parse tree(原始解析树)实现机制 (2)

🏅 5.2 分析器(Analyzer/Analyser)

【0297】Postgres内核之 INSERT INTO 原始解析树 转 Query 树 (1)
【0298】Postgres内核之 INSERT INTO 原始解析树 转 Query 树 (2)
【0300】Postgres内核之 INSERT INTO 原始解析树 转 Query 树 (2 - 1)
【0299】Postgres内核之 INSERT INTO 原始解析树 转 Query 树 (3)

🏅 5.3 重写器(Rewriter)

🏅 5.4 计划器(Planner)

🏅 5.5 执行器(Executor)

🏅 6. libpq库函数

【0012】 如何使用libpq库函数集合
【0013】 如何编译libpq.so动态库文件
【0093】 PostgreSQL数据库集群相关文件和目录介绍
【0098】 libpq是什么?如何使用?
【0114】 libpq连接句柄PGconn介绍

🏅 6.1 建立libpq与postgres连接

【0115】libpq连接PostgreSQL数据库(0)
【0120】建立与postgres后端的连接(1)
【0121】建立与postgres后端的连接(2)
【0122】检查PostgreSQL状态,是否允许指定类型的连接
【0131】建立与postgres后端的连接(2 - 1)
【0132】将options的values移植到PGconn结构中(2 - 2)
【0133】PGconn中为每个尝试连接的host分配内存空间(3)
【0134】启动建立一个与postmaster通信的连接(4)
【0135】阻塞并完成一个postmaster连接(【内含PGconn状态转换图】 5)
【0136】startup packet应用机制及构建过程(6)
【0137】向postmaster发送 startup packet 数据包(7)
【0138】发送任何在outBuffer中等待的数据(8)
【0139】postmaster收到startup packet启动数据包,并向libpq发送一个ACK(9)
【0151】gdb调试libpq与postgres之间通信的技巧
【0206】postmaster向客户端发送认证消息(Client authentication) (10 - 1)
【0207】Backend向客户端发送Client authentication的底层实现(10 - 2)
【0208】Backend向客户端发送Client authentication的底层实现(10 - 3)
【0209】frontend如何接收来自Backend进程的认证请求报文(authentication request packet)(11)
【0210】frontend接收到Backend进程的认证请求报文后,如何作出回应 (12)
【0211】tcpdump抓包分析pg_hba.conf以password作为认证证方式下frontend与Backend之间身份验证过程(13)
【0212】tcpdump抓包分析pg_hba.conf以password作为认证证方式下frontend与Backend之间身份验证过程(13 - 2)
【0229】libpq库实现压测PG服务器max_connections的最大连接数

🏅 7. 约束

【0051】 详聊PostgreSQL约束(Constraints)

🏅 8. 现场问题

【0028】 记录一次PostgreSQL的问题排查
【0029】 PostgreSQL报错 RETURNING id err ERROR: bad magic number in sequence “xxx_info_id_seq“: 0
【0030】 PostgreSQL报错:row number 0 is out of range 0…-1
【0031】PostgreSQL报错提示:ERROR: invalid byte sequence for encoding UTF8: 0xaa
【0032】 PostgreSQL终端查询结果集横竖展示字段
【0033】 PostgreSQL报错: psql: could not connect to server: No such file or directory
【0034】 PostgreSQL报错信息:The server must be started by the user that owns the data directory.
【0049】报错:fe_sendauth: invalid authentication request from server: AUTH_REQ_SASL_CONT without
【0052】 PostgreSQL报错提示:“Could not extend file” or “No space left on device”
【0053】 PostgreSQL报错提示:“Invalid input syntax”
【0054】 PostgreSQL报错:Could not connect to server: no such file or directory
【0055】 PostgreSQL报错信息:“Error 1053” or “The service did not respond to the start or con
【0056】 PostgreSQL报错提示:“Error 42501” or “Permission Denied”
【0057】 PostgreSQL报错提示:“Error: syntax error at or near ‘grant’”
【0058】 PostgreSQL报错提示:psql: FATAL: no pg_hba.conf entry for host “192.xx.0.22“, user “webu
【0059】PostgreSQL报错提示:psql: could not connect to server: Connection refused Is the server
【0060】 PostgreSQL报错提示:psql: FATAL: Peer authentication failed for user “postgres“
【0061】 PostgreSQL报错提示:psql: could not connect to server: No such file or directory
【0062】 PostgreSQL报错提示打印:ERROR: column does not exist
【0063】 PostgreSQL报错提示:Error: psql: FATAL: database “root“ does not exist
【0064】 PostgreSQL报错提示:Is the PostgreSQL Server Running Locally and Accepting?
【0065】 PostgreSQL日志报错提示:OOM Killer
【0066】 PostgreSQL报错提示Out of Memory Issue
【0067】 PostgreSQL报错Replication Standby Issue
【0068】 PostgreSQL报错Out of Disk Space Error
【0070】 initdb报错: could not change directory to “xxxxx“: Permission denied
【0080】 解决报错:ERROR:failed to add old item to the right sibling while splitting block 14 of
【0081】PostgreSQL报错:DETAIL: The database subdirectory “pg_tblspc/0/PG_x.x_20160x131/0“ is missing报错问题
【0086】解决ERROR: MultiXactId 1076887568 has not been created yet – apparent wraparound
【0089】PostgreSQ中信号量常见问题汇总
【0090】查找并停止PostgreSQL中长时间运行的查询
【0162】解决报错:startup process (PID 229811) was terminated by signal 6: Aborted
【0163】解决报错:startup process (PID 54511) was terminated by signal 11: Segmentation fault
【0178】DBeaver、pgAdmin III报错提示:FATAL: password authentication failed for user “postgres”
【0237】pg_ctl: could not access directory “/home/xxx/xxx/data“: Permission denied
【0242】psql报错:could not send startup packet: xxxx
【0243】解决PG waiting for server to shut down … failed问题

  • 12
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
安装 PostgreSQL 在 Ubuntu 22.04 上的步骤如下: 1. 打开终端并运行命令 `sudo apt update` 更新软件包列表。 2. 运行命令 `sudo apt install postgresql postgresql-contrib` 安装 PostgreSQL 和相关的扩展包。 3. 为了允许远程访问 PostgreSQL 服务器,打开配置文件 `postgresql.conf`。可以使用 `sudo vim /etc/postgresql/14/main/postgresql.conf` 命令来编辑该文件。 4. 在 `postgresql.conf` 文件的 `CONNECTIONS AND AUTHENTICATION` 部分,添加 `listen_addresses = '*'`,以允许来自任何 IP 地址的连接。 5. 重新启动 PostgreSQL 服务使修改生效,可以使用命令 `sudo service postgresql restart`。 6. 确认修改的效果,可以使用命令 `ss -nlt | grep 5432` 检查 PostgreSQL 是否在监听 5432 端口。 7. 编辑 `pg_hba.conf` 文件,配置服务器接受远程连接。可以使用命令 `sudo vi /etc/postgresql/14/main/pg_hba.conf` 来编辑该文件。在文件中添加一行,例如 `host all all 0.0.0.0/0 md5` 表示接受来自任何 IP 地址的连接。 8. 重启 PostgreSQL 服务使修改生效。 9. 如果服务器有防火墙,需要打开 5432 端口以允许远程访问。 10. 如果需要开启日志,可以编辑 `postgresql.conf` 文件并修改以下配置项: - 将 `logging_collector` 设置为 `on`,开启日志收集器。 - 设置 `log_directory` 为你希望保存日志文件的目录。 - 设置 `log_filename` 为日志文件的命名格式。 - 设置 `log_file_mode` 为日志文件的权限。 11. 重启 PostgreSQL 服务使修改生效。 请注意,上述步骤中的命令可能需要使用 `sudo` 获得管理员权限。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

内核之道

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值