Linux 内存子系统常见参数以及调优

  • 调优的几个模块:
    • 进程管理,CPU;
    • 内存调优,
    • IO调优
    • 文件系统;
    • 网络子系统;
  • 调优思路:性能指标,定位瓶颈,;
  • 系统调优是一种black art;
  • rhel6提供的性能评估的软件:
    • SystemTap:用于观察系统上面每一个系统调用或者应用程序和内核交互时的状态;
    • Oprofile:表示用于进行系统评估的工具;
    • Valgrind:是一个非常强大的内存检测工具,以及对于缓存的使用率的一个工具;
    • Perf:也是一个系统性能评估工具
  • 内存的子系统组件:
    • slab allocator:
    • buddy system:
    • kswapd:
    • pdflush:
    • mmu:
  • 内存子系统的虚拟化
  • 将进程地址成为PA,虚拟主机的地址成为HA,物理地址称为MA,虚拟机对于地址的转换通常需要从PA-->HA-->MA,效率低下,大多数虚拟机都是需要这样进行转换的,支持硬件虚拟化的CPU,可以通过PA直接转换到MA;
  • 现在的支持硬件虚拟化的CPU都支持shadow Page,通过提供虚拟的MMU ,Guest OS在需要转换时,通过硬件MMU芯片,OS自动的同步完成HA-->MA的转换,通过这种机制可以一步完成从PA-->MA的转换;

TLB:TLB(Translation Lookaside Buffer)转换检测缓冲区是一个内存管理单元,用于改进虚拟地址到物理地址转换速度的缓存,TLB是一个小的,虚拟寻址的缓存,其中每一行都保存着一个由单个PTE(Page Table Entry,页表项)组成的块。如果没有TLB,则每次取数据都需要两次访问内存,即查页表获得物理地址和取数据。

  • 提高TLB性能
  • Hugetblfs:大表页文件系统,可以使用多种不同大小的页面,对应的文件系统是HugeFS,
    这里写图片描述
  • 上面的参数表示的含义是大页面的大小为2M,但是总数为0,表示没有启用;
  • 启用大页面的方法:
  • 1.通过更改配置文件
root@westos:~# vim /etc/sysctl.conf 
vm.nr_hugepages=n;
上面的方式等价于:
sysctl -w vm.nr_hugepages=10
  • 2.或者通过向内核传递参数的方式进行
hugepages=n
  • 更改之后进行查看
    这里写图片描述

  • 这些大页面可以被某些应用程序使用;通常来说某些应用程序是可以自动使用大页面的,例如sshm mysqld,如果需要手动的指定某些应用程序使用大页面,可以通过挂载的方式实现;

root@westos:~# mkdir /hugepages
root@westos:~# mount -t hugetlbfs none /hugepages/
root@westos:~# ls /hugepages/
  • 这个地址空间是不允许用户直接使用的;

  • 对于MysqlInnoDB存储引擎存在一个参数InnoDB_Buffer,这个空间主要是用来缓存InnoDB的索引文件,需要的空间特别大,这个建议使用大页面,可以有效的提高性能;

  • 查看系统调用

  • starce用来查看一个进程到底是如何运行的,并且执行了那些系统调用
    这里写图片描述

  • 追踪某个命令执行的系统调用,输出的主要是摘要信息;
    这里写图片描述

  • 通过-i选项查看系统调用信息

root@westos:~# strace -i   cat /etc/fstab 
[00007f4b1b1d3607] execve("/bin/cat", ["cat", "/etc/fstab"], [/* 19 vars */]) = 0
[00007fa5502f1879] brk(NULL)            = 0x55e661629000
[00007fa5502f25a7] access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
[00007fa5502f269a] mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa5504f9000
[00007fa5502f25a7] access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
[00007fa5502f2547] open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
[00007fa5502f24d2] fstat(3, {st_mode=S_IFREG|0644, st_size=121277, ...}) = 0
[00007fa5502f269a] mmap(NULL, 121277, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fa5504db000
[00007fa5502f2647] close(3)             = 0
[00007fa5502f25a7] access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
[00007fa5502f2547] open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
[00007fa5502f2567] read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320\3\2\0\0\0\0\0"..., 832) = 832
[00007fa5502f24d2] fstat(3, {st_mode=S_IFREG|0755, st_size=1689360, ...}) = 0
[00007fa5502f269a] mmap(NULL, 3795360, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fa54ff3a000
[00007fa5502f2737] mprotect(0x7fa5500cf000, 2097152, PROT_NONE) = 0
[00007fa5502f269a] mmap(0x7fa5502cf000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x195000) = 0x7fa5502cf000
[00007fa5502f269a] mmap(0x7fa5502d5000, 14752, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fa5502d5000
[00007fa5502f2647] close(3)             = 0
[00007fa5502f269a] mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa5504d9000
[00007fa5502d9bb8] arch_prctl(ARCH_SET_FS, 0x7fa5504d9700) = 0
[00007fa5502f2737] mprotect(0x7fa5502cf000, 16384, PROT_READ) = 0
[00007fa5502f2737] mprotect(0x55e65fc41000, 4096, PROT_READ) = 0
[00007fa5502f2737] mprotect(0x7fa5504fc000, 4096, PROT_READ) = 0
[00007fa5502f2717] munmap(0x7fa5504db000, 121277) = 0
[00007fa55001ac69] brk(NULL)            = 0x55e661629000
[00007fa55001ac69] brk(0x55e66164a000)  = 0x55e66164a000
[00007fa54ff64e9f] open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
[00007fa550015062] fstat(3, {st_mode=S_IFREG|0644, st_size=3468304, ...}) = 0
[00007fa55001e3ca] mmap(NULL, 3468304, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fa54fbeb000
[00007fa54ff64f51] close(3)             = 0
[00007fa550015062] fstat(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(136, 0), ...}) = 0
[00007fa550015470] open("/etc/fstab", O_RDONLY) = 3
[00007fa550015062] fstat(3, {st_mode=S_IFREG|0644, st_size=196, ...}) = 0
[00007fa55001976d] fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
[00007fa55001e3ca] mmap(NULL, 139264, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa5504b7000
[00007fa550015690] read(3, "# /dev/sdd1\nUUID=4cc08fc5-b4e5-4"..., 131072) = 196
[00007fa5500156f0] write(1, "# /dev/sdd1\nUUID=4cc08fc5-b4e5-4"..., 196# /dev/sdd1
UUID=4cc08fc5-b4e5-40f3-8545-9746f8ba0b0e	/         	ext4      	rw,relatime,data=ordered	0 1

/swapfile none swap defaults 0 0

cpuset          /cpusets         cpuset defaults  0   0
) = 196
[00007fa550015690] read(3, "", 131072)  = 0
[00007fa55001e467] munmap(0x7fa5504b7000, 139264) = 0
[00007fa550015cb0] close(3)             = 0
[00007fa54ffaba1b] close(1)             = 0
[00007fa54ffaba1b] close(2)             = 0
[00007fa54fff25d8] exit_group(0)        = ?
[????????????????] +++ exited with 0 +++
  • strace COMMAND:查看命令的系统调用;
  • strace -p PID:查看已经启动的进程的syscall;
  • -c:只输出概括信息;
  • -o FILE:将追踪结果保存至文件中,用来参考;
  • 使用这个命令是用于追踪LNMP或者其他服务将大量的时间用在哪些方面;通常还可以用于锁竞争,用于定位IO故障;
  • 内存的使用策略
  • 1.尽量降低小内存对象的开销,可以使用slab cache
    这里写图片描述
  • slab cache通常是事先在内存中划分出来的片段,通常这些是链式结构,并且每个kmem_cache分为三个段slab_full slab_partial slabs_empty;
  • 查看slab的信息
root@westos:~#  cat /proc/slabinfo 
slabinfo - version: 2.1
# name            <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
xfs_dqtrx              0      0    528    7    1 : tunables   54   27    8 : slabdata      0      0      0
xfs_rui_item           0      0    672    6    1 : tunables   54   27    8 : slabdata      0      0      0
xfs_rud_item           0      0    152   26    1 : tunables  120   60    8 : slabdata      0      0      0
xfs_ili                0      0    168   24    1 : tunables  120   60    8 : slabdata      0      0      0
xfs_inode             15     20    960    4    1 : tunables   54   27    8 : slabdata      5      5      0
xfs_buf_item           0      0    248   16    1 : tunables  120   60    8 : slabdata      0      0      0
xfs_da_state           0      0    480    8    1 : tunables   54   27    8 : slabdata      0      0      0
bio-4                 32     36    320   12    1 : tunables   54   27    8 : slabdata      3      3      0
kvm_async_pf           0      0    136   30    1 : tunables  120   60    8 : slabdata      0      0      0
kvm_vcpu               0      0  19264    1    8 : tunables    8    4    0 : slabdata      0      0      0
kvm_mmu_page_header      0      0    168   24    1 : tunables  120   60    8 : slabdata      0      0      0
pte_list_desc          0      0     32  124    1 : tunables  120   60    8 : slabdata      0      0      0
fuse_request           0      0    400   10    1 : tunables   54   27    8 : slabdata      0      0      0
fuse_inode             1      9    832    9    2 : tunables   54   27    8 : slabdata      1      1      0
ext4_groupinfo_4k    459    476    144   28    1 : tunables  120   60    8 : slabdata     17     17      0
ext4_inode_cache   23316  23358   1080    3    1 : tunables   24   12    8 : slabdata   7786   7786      0
ext4_allocation_context      8     32    128   32    1 : tunables  120   60    8 : slabdata      1      1      0
ext4_extent_status   4503   9999     40   99    1 : tunables  120   60    8 : slabdata    101    101      0
  • 对于上面显示的内容是存在tunables,表示这个 slab是可以进行调整的
  • 对于内存对象来说都是不一样的,所以分配的slab的大小也不应该是一样的,所以每一种对象可能需要准备多个slab空间;
  • 所以使用slab应该是提前申请,对于某个对象被删除slab并不会被删除,而是会被清空,留给以后使用;
  • 2.降低或者延迟慢速子系统的时间:
  • 文件系统元数据filesystem medata:通过提供 buffer 或者cache,将文件元数据直接缓存在buffer;;
  • DIsk IO:通过提供page cache;
  • Interprocess communication通过提供shared memory;
  • Network IO:通过提供buffer, cache, arp cache,connection tracking;
  • slab_cache的参数:
  • 查看
    这里写图片描述
  • slabtop
    这里写图片描述
  • 通常来说dentry,和ext4_innodb的使用量是比较大的,这个使用百分比在deepin上面显示的好像不正常,手动来算两个
    这里写图片描述
  • 这个值建议对于某些服务根据上面的情况来调整变大
    这里写图片描述;
  • 通过echo命令来调整上面的参数:
root@westos:~# echo "cache_name limit batchcount shared" > /proc/slabinfo 
  • limit:表示可以被每个CPU缓存的最大object数目
  • batchcount:全局缓存对象中最多允许多少个在某个CPU缓存为空时,进行传送的个数;
  • shared:在对称多处理器架构中,允许多少个缓存对象;
root@westos:~#  echo 'ext4_inode_cache 54 27 8' > /proc/slabinfo
  • 再次查看这个值就已经改变
    这里写图片描述

  • 关于vm_min_free_kbytes:

    • 这个参数是用于定义最少需要空闲出来多少内存,用于确保内存不会被使用完,而导致系统崩溃;这个参数在硬盘设备比较差,并且CPU性能也比较差时,需要考虑使用,通常是调小这个参数;
    • 这个参数可以用于减少请求分页的响应时间;
    • 这段memory对于其他的应用程序不可用
      这里写图片描述
  • vm.overcommit_memory:

  • 用于防止内存的过量使用,可以在swap的程度上面允许内存的一部分过量使用;

  • 0:表示heuristic overcommit:表示启发式过量,用于自动决定内存过量使用的时机,以及大小;

  • 1:表示always overcommit,表示一直允许过量使用,在数据库服务器上面,尽可能的不要使用swap,也就是不要使用这个选项,但是在hadoop对于内存的量要求大,但是速度要求不强;

  • 2:表示使用一部分的物理内存加上一部分的swap内存,这个大于的百分比是可以自行进行定义的overcommit_ratio百分比;并且建议不要超过50%;这个范围在确定的时候,不应该超过物理内存和swap分区的大小,通常计算方法是swap+RAM*raito;

  • 为了防止物理内存不能够充分被使用,需要使用:

    • 1.swapRAM一样大,并且swapiness=0;
    • 2.或者设定overcommit_memory=2,并且设定,overcommit_ratio=100;,并且还需要设定swappiness=0;
      这里写图片描述;
  • 内核中的OOMK Out Of Memory Kill杀手,当应用程序使用的内存占据了内核空间的内存的时候,内核就会优先杀死那些占用内存空间最多的进程,无论是否重要;

  • 当然上面这个杀死进行的方式是可以进行定义的,内核维护了对于所有进程的一个评分,用于确定那个进程优先被杀死;
    这里写图片描述

  • 1这个进程肯定是不能够优先被杀死的
    这里写图片描述

  • 换一个进程来查看
    这里写图片描述

  • 好像默认的都是一样的
    这里写图片描述

  • 调整网络IO

  • 默认情况下,arp的解析结果缓存在/proc/net/arp文件中 ,默认情况下这个文件里面可以缓存512个条目,硬限制是1024个条目;一旦超出软限制,内核子系统Garbage collection会自动移除一些过期的条目
    这里写图片描述

  • 可以通过命令ip neighbor list显示已经缓存的条目
    这里写图片描述

  • 如果需要清空某个设备上面的缓存条目

root@westos:~# ip neigh flush dev enp0s25
  • net.ipv4.neigh.default.gc_thresh1=128:当里面的缓存条目少于128时,garbage collection不会进行任何操作;

  • net.ipv4.neigh.default.gc_thresh2=512:表示软限制,可以允许超过,当选项net.ipv4.neigh.default.gc_interval启用时,清除超过硬限制清理时间的条目,超过软限制的做多不允许超过5秒钟;

  • net.ipv4.neigh.default.gc_thresh1=1024:表示硬限制,这个值是不允许超过的;

  • net.ipv4.neigh.default.gc_interval,表示每隔多长时间来检查一次,并且进行清理;

  • PAGE CACHE

  • 页缓存的主要目的使用来降低磁盘缓存的,也就是尽量将文件放在内存中进行读,主要是用来加速读操作的;

  • page cache降低IO请求:

    • Directory Read :目录读取;
    • Reading and Write regular file: 读写[表示对于文件内容的修改]普通文件;
    • 可以加快读和写块设备;
    • 通常还是可以使用内存映射的mmap;
  • vm.lowmem_reserve_ratio

  • 表示内存中为page Cache预留多大的空间;

  • vfs_cache_pressure

  • 用于控制内核控制内存设备中那些被用于缓存目录以及inode对象的的趋势,一般来说为了加快访问,这些内容是不应该回收的;

  • 100表示在dentries innodespagecache swapcache更加公平的在两者之家选择回收策略,如果减少这个值,表示更加倾向于保留dentryinnode cache;

  • 0:表示不会依赖于内存的使用情况来回收dentry以及innode,这样容易导致内存溢出;

  • 1-->99:倾向于不回收dentry以及innode;

  • >100:表示更加倾向于回收dentry以及innode;
    这里写图片描述

  • page-cluster

  • 表示页面组,专业说法是页簇;表示在将数据需要存放在交换页面上面的时候,每一次拿出多少个页面放在交换内存上面去;如果这个值为n,那么表示的含义是每次交换出2^n个,一般来收只有在系统频繁使用交换分区的时候,需要调大这个值,并且不应该大于4

  • 这个参数需要在虚拟化时,需要调大这个值;
    这里写图片描述

  • zone_reclaim_mode

  • 表示在内存回收的模型,表示在进行内存回收时,更加倾向于回收哪一段的内存;

  • 1:表示打开内存回收的功能,具体的回收策略交给内核进行限定;

  • 2:表示回收写操作产生的脏页;

  • 4:表示回收swap页面;
    这里写图片描述

  • anonymous page

  • 表示匿名页,这里面通常包含:

  • 1.程序自身产生的数据,数组和堆里面的数据;

  • 2.通常匿名内存区域也称为匿名页;

  • 3.程序私有内存页面映射的脏页面;

  • 4.进程间通信的共享内存页面;

  • Anonymous page的计算方法:anonymous pages = RSS[实际内存集合] - Shared[共享内存集合];

  • 通常来说匿名页面是不能够被交换出去的;
    这里写图片描述
    这里写图片描述

  • 对于进程间通信的调优

  • 查看当前的IPC的限定
    这里写图片描述

  • min seg size:表示每一个段最小使用的字节数;

  • 通常来说使用较多的通信机制是shared memory以及Messages;

  • ipcrm:如果某个进程使用进程间通信陷入睡眠,无法被唤醒,使用这个命令可以移除一个消息队列;

  • shared memory的调优:

  • kernel.shmmni:表示在全系统内部允许使用多少个共享内存段;,数据库服务器上面经常需要调整这个参数,这个值通常需要被调大;
    这里写图片描述

  • kernel.shmall:表示的是全系统范围内,一次可以最大为共享内存使用的最大页面数;
    这里写图片描述

  • this should be at least kernel.mmax/PAGE_SIZE;

  • kernel.shamax:共享内存段可以被创建的最大大小
    这里写图片描述

  • 关于msgmnb:

  • kernel.msgmnb:表示单个消息队列的最大字节数;
    这里写图片描述

  • kernel.msgmni:系统级别,表示消息队列个数的的上限;
    这里写图片描述

  • kernel.msgmax: 表示消息队列中,单个消息的上限,单位是字节;

  • 一般来说这些值是需要调大的,对于上面的内存空间是不能够被交换出去的;

  • 内存空间的清写

  • 内存空间的清写是交给pdflush这个线程来完成的,这个线程是按照需求进行启动的,当出现需要进行磁盘刷写的时候,这个线程是会自动启动的,这个线程一般最少是两个;
    这里写图片描述

  • 一般来说内核会自动优化,一块磁盘设备是一个线程;这块进行修改,出现了权限不够的错误,所以不建议手动进行修改;
    这里写图片描述

  • 建议进行修改的是pdflush的工作属性

  • vm.dirty_background_ratio脏页占据内存的比例达到多少,需要启动pdflush线程;这个值是个百分比;
    这里写图片描述

  • vm.dirty_ratio:表示的是单个进程的脏页占据内存达到的百分比,应该启动pdflush线程进行刷写;
    这里写图片描述

  • vm.dirty_bytes:表示使用的脏页的字节数来进行控制;
    这里写图片描述

  • 0表示没有进行定义,使用vm.dirty_ratio来进行控制

  • vm.dirty.expire.centisecs:单位是百分之一秒,表示如果上面的时间没有得到满足,那么每隔多长时间进行一次清写操作,底下这个表示的是30秒,其中0表示禁止;
    这里写图片描述

  • vm.dirty.Writeback.centisecs:表示用于定义系统中某些脏页存在的最长时间,一旦到达这个时间,就会启动线程刷写脏页;

  • FLUSHall dirty buffers and pages

  • 这个通常来说是通过调用sync command来执行的,syn主要实现的是将dirty page同步到磁盘上面;

  • echo s > /proc/sysrq-trigger

  • Reclaim clean pages

  • echo 3 > /proc/sys/vm/drop_cache:

    • 1:表示free pagecache;
    • 2表示free dentries and inodes;
    • 3表示free pagecache dentries and inodes;
  • Out Of memory Kill

  • 通常在 所有的memory以及swap都被使用的时候;

  • ZONE_NORMAL里面没有可以使用的page;

  • 没有足够的内存用于页表mapping;

  • 通常来说杀死进程是按照oom_score这个分数为标准的,数值越高,越优先被杀死;

  • 当这个值为0时,表示内存耗尽时,就可以启动OOMK
    这里写图片描述

  • 这个oom_score是系统自动计算得到的,并且需要主动的参照于oom_adj,通常范围是-17-->15,可用的表示范围是-16--->15,如果设置为-17,表示无论任何情况,这个进程都是不会被kill掉的;可以用于保护某些进程;

  • 通常来说oom_score=2^oom_adj的值;

  • 通常来说子进程是继承父进程的oom_score的值的,如果需要关闭这个选项,

sysctl -w vm.panic_on_oom=1
  • 评估内存子系统
  • valgrind:通常是一个包含各个子组件的,内存状态监测工具,建议安装上这个软件包
    这里写图片描述
  • 内存泄漏就是,内存再被分配出去,无法进行回收,也无法重新分配进行使用
    这里写图片描述
  • SWAP页面
  • swap-out表示从内存上面写入,交换分区中;
  • swap-in:表示从交换分区中写入内存中;
  • 满足swap的要求:
    • 1.首先是inactive pages;
    • 2.其次是anonymous pages;
  • swap cache:从swap加载进来的,但是没有进行任何修改的数据, 通常使用来避免多进程同时访问同一个内存页框的情况;
  • 提供swap性能:
    * 尽可能降低swap的访问次数;
    * 可以通过多个磁盘设备提供多个swap分区,可以提供负载均衡的效果;
    * 降低服务时间;
    * 使用SSD盘;
    * 可以讲swap分区划分在最外道的分区,用于加快交换分区的访问速度;
  • 调整swap的使用:
    这里写图片描述
  • 通常来说使用交换内存是因为% of memory mapped into page table + vm.swappiness >= 100,时就会使用swap分区,如果更加倾向于使用交换出anonymous pages可以通过提高vm.swappiness;在内存足够使用,的情况下,应该尽可能的降低这个值;
  • 使用交换分区的情况:
    • batch compute server:通常是4*RAM;
    • Database server:<= 1GB;
    • Application server:通常是>=0.5 * RAM;
  • 通过提供多个设备,并且提供同样的优先级
root@westos:~# mkswap -L SWAP_LABEL /path/to/some/device
vim /etc/fstab
/dev/sda1		swap 		swap 		pri=5	0	0
/dev/sdb1		swap		swap		pri=5	0	0
LABEL=testswap	swap		swap		pri=5	0	0
/swap/swapfile1	swap		swap		pri=5	0	0

//挂载使用
swapon 	-a
  • 如果需要查看交换分区,
    这里写图片描述

  • 关于网络的几个变量:

  • tcp_max_tw_buckets:表示的含义是用于保存所有处于TIME_WAIT的会话的个数,这个值建议调大,而不是调小;
    这里写图片描述

  • tcp_fin_timeout:表示的含义是tcp_fin的超时时间;

  • tcp_mem:表示的含义是tcp socketstcp_wmem发送和接受tcp_rmem缓冲的大小;,关于这两个值的最大值,在文件core/rmem_max core/wmem_max core/mem_default;

  • 可能使用的命令 sar dstat vmstat mpstat iostat top free iotop uptime cat /proc/meminfo ss netstat lsof blktrace blkparse btt time perf ;

  • 对文件系统进行压力测试的工具:dd iozone io-stress fio;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值