美文网首页微服务性能测试
kafka-flink性能测试规划(上)

kafka-flink性能测试规划(上)

作者: 林夕_Yume | 来源:发表于2019-07-30 19:21 被阅读0次

    1.压测方案

    1.1 压测目的

       本次性能测试在正式环境下单台服务器上Kafka处理MQ消息能力进行压力测试。测试包括对Kafka写入MQ消息和消费MQ消息进行压力测试,根据不同量级的消息处理结果,评估Kafka的处理性能是否满足项目需求(该项目期望Kafka能够处理上亿级别的MQ消息)。

    1.2 测试范围及方法

    1.2.1 测试范围概述

       测试使用Kafka自带的测试脚本,通过命令对Kafka发起写入MQ消息和Kafka消费MQ消息的请求。模拟不同数量级的消息队列的消息写入和消费场景,根据Kafka的处理结果,评估Kafka是否满足处理亿级以上的消息的能力。

    1.2.3 测试方法

    • 测试目的:

       验证单台服务器上Kafka写入消息和消费消息的能力,根据测试结果评估当前Kafka集群模式是否满足上亿级别的消息处理能力。

    • 测试方法

       在服务器上使用Kafka自带的测试脚本,模拟1y级别的消息写入以及读取请求,查看Kafka处理不同数量级的消息数时的处理能力,包括每秒生成消息数、吞吐量、消息延迟时间。

       Kafka消息写入创建的topic命名为test_kafka_throughout,Kafka消费读取的topic也是该topic;使用命令发起消费该topic的请求,针对不同的测试指标,本次我们采用固定其他值,动态变化测量值的方式来进行,具体使用脚本为kafka自带的测试脚本,分别为kafka bin目录下的kafka-producer-perf-test.sh和kafka-consumer-perf-test.sh;通过测试来查看Kafka消费不同数量级别的消息时的处理能力。

    • 准备工作

       测试之前,我们需要先用linux命令去测试磁盘的读写速度,具体命令如下:

    1.测试IO读
        hdparm -t --direct /dev/sda3
        IO读用上面的命令测试即可,不过 hdparm 这个工具需要自己安装,而且需要root用户去执行;
    2.测试IO写
        sync;/usr/bin/time -p bash -c "(dd if=/dev/zero of=test.dd  bs=1M count=20000)"
    测试结论:
        1.dd测试出的读速度和hdparm 是存在区别的;
        2.通过 bs 选项 设置不通的读写块大小测试(默认512字节,测试使用1M);
        3.可以看出 dd 的测出的速度与读写块的大小有关系,还可能受到系统中有IO读写的进程的影响;
        4.hdparm的测试原理可能是和dd的测试方法存在差别;
        
    整体上看,IO的实际测试速度是受到很多因素影响的,包括读写的方式(随机还是顺序,hdparm和dd测试是都是采用顺序读写)、缓存机制、测试的取样等等。
    所以不太可能得到一个确定的值(相同的命令行多次测试也不一样,不过差别要小些),以上的方法中读测试还是推荐使用hdparm。
    以上的数据虽然存在偏差,但还是能大体分析出机器的IO性能。只是需要明确,这些测试值是在什么样的环境下获得的。
    3.测试结果
        1.磁盘cache读7471m/s;
        2.disk读163m/s;
        3.IO写125m/s;
        4.IO读206m/s;
    经过测试,我们拿到的磁盘读应该在163m/s-206m/s之间,而写速度是163m/s。后续评测我们以该磁盘测试为基准来核定。
    

    1.3 测试环境

    主 机 数量 资 源 操作系统
    MQ消息服务 1 硬件:32(核)-32(G)-20(T)软件:Kafka集群(Kafka_2.11-1.1.0) CentoOS

    2.kafka参数

       在调试和优化使用Java开发的系统时,第一步绕不开对JVM的调优,Kafka也不例外,而JVM调优的重点则是在内存上。

       其实Kafka服务本身并不需要很大内存,其依赖的是系统提供的PageCache来满足性能上的要求,本次测试时设置30G内存的目的是支持更高的并发,高并发本身就必然会需要更多的内存来支持,同时高并发也意味着SocketBuffer等相关缓存容量会成倍增长。实际使用中,调整内存大小的准则是留给系统尽可能多的空闲内存,Broker本身则是够用就好。

       JVM上的垃圾回收器,官方文档里推荐使用最新的G1来代替CMS作为垃圾回收器。为了稳定性问题,本次我们使用jdk8以上的版本,我们本次使用G1回收器的原因如下:

    • G1是一种适用于服务器端的垃圾回收器,很好的平衡了吞吐量和响应能力;
    • 对于内存的划分方法不同,Eden, Survivor, Old区域不再固定,使用内存会更高效。G1通过对内存进行Region的划分,有效避免了内存碎片问题;
    • G1可以指定GC时可用于暂停线程的时间(不保证严格遵守)。而CMS并不提供可控选项;
    • CMS只有在FullGC之后会重新合并压缩内存,而G1把回收和合并集合在一起;
    • CMS只能使用在Old区,在清理Young时一般是配合使用ParNew,而G1可以统一两类分区的回收算法。

    其使用场景如下:

    • JVM占用内存较大(At least 4G);
    • 应用本身频繁申请、释放内存,进而产生大量内存碎片时;
    • 对于GC时间较为敏感的应用。
         首先,我们设置JVM配置为:
    -Xmx6G -Xms6G -XX:MMetaspaceSize=96m -server -XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:InitiatingHeapOccupancyPercent=35 -XX:G1HeapRegionSize=16m -XX:MinMetaspaceFreeRatio=50 -XX:MaxMetaspaceFreeRatio=80
    
    

       后续在broker的相关参数测试完成后,保持其在最优的参数下,再来针对我们的服务器和kafka的页缓存及jvm堆内存以及策略等进行测试。

    2.1 Producer相关参数

       我们在producer涉及到性能的关键因素可能会存在如下几个:

    • thread:我们测试时的单机线程数;
    • bath-size:我们所处理的数据批次大小;
    • ack:主从同步策略我们在生产消息时特别需要注意,是follower收到后返回还是只是leader收到后返回,这对于我们的吞吐量影响颇大;
    • message-size:单条消息的大小,要在producer和broker中设置一个阈值,且它的大小范围对吞吐量也有影响;
    • compression-codec:压缩方式,目前我们有不压缩,gzip,snappy,lz4四种方式;
    • partition:分区数,主要是和线程复合来测试;
    • replication:副本数;
    • througout:我们所需要的吞吐量,单位时间内处理消息的数量,可能对我们处理消息的延迟有影响;
    • linger.ms:两次发送时间间隔,满足后刷一次数据。

    2.2 Consumer相关参数

    • thread:我们测试时的单机线程数;
    • fetch-size:抓取数据量;
    • partition:分区数,主要是和线程复合来测试;
    • replication:副本数;
    • througout:我们所需要的吞吐量,单位时间内处理消息的数量,可能对我们处理消息的延迟有影响;

    2.3 Broker相关参数

    • num.replica.fetchers:副本抓取的相应参数,如果发生ISR频繁进出的情况或follower无法追上leader的情况则适当增加该值,==但通常不要超过CPU核数+1;==
    • num.io.threads:broker处理磁盘IO的线程数,主要进行磁盘io操作,高峰期可能有些io等待,因此配置需要大些。==建议配置线程数量为cpu核数2倍,最大不超过3倍;==
    • num.network.threads:broker处理消息的最大线程数,和我们生产消费的thread很类似主要处理网络io,读写缓冲区数据,基本没有io等待,==建议配置线程数量为cpu核数加1;==
    • log.flush.interval.messages:每当producer写入多少条消息时,刷数据到磁盘;
    • log.flush.interval.ms:每隔多长时间,刷数据到磁盘;

    3.flink参数

    4.测试过程

    4.1 producer测试

    4.1.1 bath-size

    • 测试脚本
    ./kafka-producer-perf-test.sh  --topic test_kafka_perf1 --num-records 100000000 --record-size 687  --producer-props   bootstrap.servers=10.240.1.134:9092,10.240.1.143:9092,10.240.1.146:9092  batch.size=10000   --throughput 30000
    ./kafka-producer-perf-test.sh  --topic test_kafka_perf1 --num-records 100000000 --record-size 687  --producer-props   bootstrap.servers=10.240.1.134:9092,10.240.1.143:9092,10.240.1.146:9092  batch.size=20000   --throughput 30000
    ./kafka-producer-perf-test.sh  --topic test_kafka_perf1 --num-records 100000000 --record-size 687  --producer-props   bootstrap.servers=10.240.1.134:9092,10.240.1.143:9092,10.240.1.146:9092  batch.size=40000   --throughput 30000
    ./kafka-producer-perf-test.sh  --topic test_kafka_perf1 --num-records 100000000 --record-size 687  --producer-props   bootstrap.servers=10.240.1.134:9092,10.240.1.143:9092,10.240.1.146:9092  batch.size=60000   --throughput 30000
    ./kafka-producer-perf-test.sh  --topic test_kafka_perf1 --num-records 100000000 --record-size 687  --producer-props   bootstrap.servers=10.240.1.134:9092,10.240.1.143:9092,10.240.1.146:9092  batch.size=80000   --throughput 30000
    
    • 测试结果
    batch-size ack message-size compression-codec partition replication throughput MB/S MsgNum/s
    10000 0 687 none 3 3 30000 18.07 27576
    20000 0 687 none 3 3 30000 19.65 29986
    40000 0 687 none 3 3 30000 19.65 29991
    60000 0 687 none 3 3 30000 19.63 29954
    80000 0 687 none 3 3 30000 19.64 29983
    • 测试结论


       测试中通过我们增加batch-size的大小,我们可以发现在消息未压缩的前提下,20000条一批次之后吞吐稳定在30000条/s,而数据量在19.65M/s。

    4.1.2 ack

    • 测试脚本
    ./kafka-producer-perf-test.sh  --topic test_kafka_perf1 --num-records 100000000 --record-size 4096  --producer-props   bootstrap.servers=10.240.1.134:9092,10.240.1.143:9092,10.240.1.146:9092  batch.size=20000 acks=0   --throughput 30000
    ./kafka-producer-perf-test.sh  --topic test_kafka_perf1 --num-records 100000000 --record-size 4096  --producer-props   bootstrap.servers=10.240.1.134:9092,10.240.1.143:9092,10.240.1.146:9092  batch.size=20000 acks=1  --throughput 30000
    ./kafka-producer-perf-test.sh  --topic test_kafka_perf1 --num-records 100000000 --record-size 4096  --producer-props   bootstrap.servers=10.240.1.134:9092,10.240.1.143:9092,10.240.1.146:9092  batch.size=20000 acks=-1  --throughput 30000
    
    • 测试结果
    batch-size ack message-size compression-codec partition replication throughput MB/S MsgNum/s
    20000 0(不响应) 687 none 3 3 30000 19.69 30225
    20000 1(leader响应) 687 none 3 3 30000 19.63 29954
    20000 -1(follower响应) 687 none 3 3 30000 5.08 7760
    • 测试结论

       测试中通过我们使用不同的ack策略,我们可以发现在消息未压缩的前提下,不响应速度最快,其次是leader响应,而follower响应吞吐只有其25%左右,在主从同步策略上要根据数据量还有我们的数据稳定性结合来考量。

    4.1.3 message-size

    • 测试脚本
    ./kafka-producer-perf-test.sh  --topic test_kafka_perf1 --num-records 100000000 --record-size 687  --producer-props   bootstrap.servers=10.240.1.134:9092,10.240.1.143:9092,10.240.1.146:9092  batch.size=20000 acks=-1  --throughput 30000
    ./kafka-producer-perf-test.sh  --topic test_kafka_perf1 --num-records 100000000 --record-size 454  --producer-props   bootstrap.servers=10.240.1.134:9092,10.240.1.143:9092,10.240.1.146:9092  batch.size=20000 acks=-1  --throughput 30000
    
    
    
    • 测试结果
    batch-size ack message-size compression-codec partition replication throughput MB/S MsgNum/s
    20000 1 687 none 3 3 30000 19.63 29954
    20000 1 454 none 3 3 30000 12.98 29976
    • 测试结论

       测试中通过我们使用两种不同的消息大小,发现在消息未压缩的前提下且其他参数一致的情况下,687字节的吞吐量是要优于454字节的,目前我们的两种消息为此大小,测试中发现当消息大小为4k时效果最优,这点可以在后续实践中再去证实。

    4.1.4 compression-codec

    • 测试脚本
    ./kafka-producer-perf-test.sh  --topic test_kafka_perf1 --num-records 100000000 --record-size 687  --producer-props   bootstrap.servers=10.240.1.134:9092,10.240.1.143:9092,10.240.1.146:9092  batch.size=20000 acks=1 compression.type=none  --throughput 30000
    ./kafka-producer-perf-test.sh  --topic test_kafka_perf1 --num-records 100000000 --record-size 687  --producer-props   bootstrap.servers=10.240.1.134:9092,10.240.1.143:9092,10.240.1.146:9092  batch.size=20000 acks=1 compression.type=gzip --throughput 30000
    ./kafka-producer-perf-test.sh  --topic test_kafka_perf1 --num-records 100000000 --record-size 687  --producer-props   bootstrap.servers=10.240.1.134:9092,10.240.1.143:9092,10.240.1.146:9092  batch.size=20000 acks=1  compression.type=snappy --throughput 30000
    ./kafka-producer-perf-test.sh  --topic test_kafka_perf1 --num-records 100000000 --record-size 687  --producer-props   bootstrap.servers=10.240.1.134:9092,10.240.1.143:9092,10.240.1.146:9092  batch.size=20000 acks=1  compression.type=lz4 --throughput 30000
    
    • 测试结果1
    batch-size ack message-size compression-codec partition replication throughput MB/S MsgNum/s
    20000 1 687 none 3 3 30000 19.63 29954
    20000 1 687 gzip 3 3 30000 12.97 29961
    20000 1 687 snappy 3 3 30000 12.97 29945
    20000 1 687 lz4 3 3 30000 12.95 29919

       在batch-size为2w且并发量在3w时,可以看出来不压缩的吞吐量最好,其他的基本相差不大。

    • 测试结果2
    batch-size ack message-size compression-codec partition replication throughput MB/S MsgNum/s
    1000000 1 687 none 3 3 100000 58.6 89455
    1000000 1 687 gzip 3 3 100000 39.8 60762
    1000000 1 687 snappy 3 3 100000 65.45 99907
    1000000 1 687 lz4 3 3 100000 65.47 99928

       我们在后续测试中发现,在batch-size为100w且并发量在10w时,可以看出来snappy和lz4的吞吐量上升幅度明显,而gzip由于压缩的费时其吞吐最差,不压缩的在本测试中的吞吐次之。

    • 测试结果3
    batch-size ack message-size compression-codec partition replication throughput MB/S MsgNum/s
    1000000 1 687 none 3 3 200000 77.69 118585
    1000000 1 687 gzip 3 3 200000 38.28 58422
    1000000 1 687 snappy 3 3 200000 84.08 128326
    1000000 1 687 lz4 3 3 200000 130.89 199772

       我们在后续测试中发现,在batch-size为100w且并发量在20w时,lz4的吞吐量优势明显达到19w/s,snappy次之为12.8w/s,而gzip由于压缩的费时其吞吐最差基本在5.8w/s,不压缩的在本测试中的吞吐也能达到11w/s。

    • 测试结果4
    batch-size ack message-size compression-codec partition replication throughput MB/S MsgNum/s
    1000000 1 687 none 3 3 500000 61.32 93596
    1000000 1 687 gzip 3 3 500000 35.17 53686
    1000000 1 687 snappy 3 3 500000 105.86 161582
    1000000 1 687 lz4 3 3 500000 205.37 313459

       在batch-size为100w且并发量在50w时,lz4的吞吐量优势明显达到31.3w/s,snappy次之为16.1w/s,而gzip由于压缩的费时其吞吐最差基本在5.3w/s,不压缩的在本测试中的吞吐也能达到9.3w/s。

    • 测试结果5
    batch-size ack message-size compression-codec partition replication throughput MB/S MsgNum/s
    1000000 1 687 none 3 3 600000 61.53 93909
    1000000 1 687 gzip 3 3 600000 35.43 54070
    1000000 1 687 snappy 3 3 600000 71.04 108431
    1000000 1 687 lz4 3 3 600000 245.88 375280

       在batch-size为100w且并发量在60w时,lz4的吞吐达到37.5w/s,snappy此时下降到10.8w/s,而gzip由于压缩的费时其吞吐最差基本在5.4w/s,不压缩的在本测试中的吞吐为9.4w/s。

    • 测试结果6
    batch-size ack message-size compression-codec partition replication throughput MB/S MsgNum/s
    1000000 1 687 none 3 3 700000 46.94 71648
    1000000 1 687 gzip 3 3 700000 38.22 58331
    1000000 1 687 snappy 3 3 700000 91.34 139419
    1000000 1 687 lz4 3 3 700000 178.66 272695

       在batch-size为100w且并发量在70w时,lz4的吞吐量下降到达到27.2w/s,snappy次之为13.9w/s,而gzip则继续保持在5.8w/s,不压缩则下降到7.1w/s。

    • 测试结果7

        测试单副本单分区下的各压缩的吞吐量:

    batch-size ack message-size compression-codec partition replication throughput MB/S MsgNum/s
    1000000 1 687 none 1 1 600000 44.01 67179
    1000000 1 687 gzip 1 1 600000 38.95 59454
    1000000 1 687 snappy 1 1 600000 89.44 138245
    1000000 1 687 lz4 1 1 600000 139.19 212449

       我们这次使用1个分区1个副本的主题,测试中通过我们使用不同的压缩格式,在其他参数一致的情况下,在并发和batch-size增大到60w和100w的情况下,lz4达到最好的吞吐21.2w/s,而普通不压缩的方式则维持在6.7w/s。

    • 测试结论

       本次测试对数据的存储块大小未测,但在之前的测试中发现压缩以及解压的情况也是lz4算法最优,==lz4压缩最大时可以达到30w+/s的吞吐,而不压缩为12w/s,snappy最大为16w/s,gzip最大为5.8w/s==;故后续生产消息时建议采用lz4压缩,不仅可以节省磁盘,也可以大幅度增加我们的吞吐。

    4.1.5 partition

    • 测试脚本
    1、创建topic
    /bin/kafka-topics.sh --create --zookeeper 110.240.0.9:2181,10.240.0.10:2181,10.240.0.13:2181/kafka --topic test_kafka_perf11  --partitions 1 --replication-factor 1
    /bin/kafka-topics.sh --create --zookeeper 110.240.0.9:2181,10.240.0.10:2181,10.240.0.13:2181/kafka --topic test_kafka_perf8 --partitions 2 --replication-factor 1
    /bin/kafka-topics.sh --create --zookeeper 110.240.0.9:2181,10.240.0.10:2181,10.240.0.13:2181/kafka --topic test_kafka_perf16 --partitions 3 --replication-factor 1
    /bin/kafka-topics.sh --create --zookeeper 110.240.0.9:2181,10.240.0.10:2181,10.240.0.13:2181/kafka1 --topic test_kafka_perf24 --partitions 4 --replication-factor 1
    /bin/kafka-topics.sh --create --zookeeper 110.240.0.9:2181,10.240.0.10:2181,10.240.0.13:2181/kafka --topic test_kafka_perf32 --partitions 5 --replication-factor 1
    
    2、生产数据
    /bin/kafka-producer-perf-test.sh  --topic test_kafka_perf1 --num-records 100000000 --record-size 10240  --producer-props   bootstrap.servers=10.240.1.134:9092,10.240.1.143:9092,10.240.1.146:9092  batch.size=80000 acks=1  compression.type=lz4 --throughput 29000
    3、初步结论
    分区数越多,单线程消费者吞吐率越小。随着更多的broker线程和磁盘开始扫描不同的分区,吞吐量开始显著增加。但是,一旦使用了所有broker线程和磁盘,添加额外的分区没有任何效果。
    
    • 测试结果
    batch-size ack message-size compression-codec partition replication throughput MB/S MsgNum/s
    1000000 1 687 lz4 1 1 600000 130.9 199792
    1000000 1 687 lz4 2 1 600000 141 216211
    1000000 1 687 lz4 3 1 600000 199.6 304645
    1000000 1 687 lz4 4 1 600000 253.87 387491
    1000000 1 687 lz4 5 1 600000 153 233830
    • 测试结论

       在我们的broker线程小于partiton数时,随着线程增多,吞吐上升,而在两者对等时,达到最优,后续基本稳定,但是由于网络和磁盘的问题可能会有一些起伏。

    4.1.6 replication

    • 测试脚本
    1、创建topic
    
    /bin/kafka-topics.sh--create --zookeeper 110.240.0.9:2181,10.240.0.10:2181,10.240.0.13:2181/kafka --topic test_kafka_rep2 --partitions 1 --replication-factor 1
    /bin/kafka-topics.sh--create --zookeeper 110.240.0.9:2181,10.240.0.10:2181,10.240.0.13:2181/kafka --topic test_kafka_rep3 --partitions 1 --replication-factor 2
    /bin/kafka-topics.sh--create --zookeeper 110.240.0.9:2181,10.240.0.10:2181,10.240.0.13:2181/kafka --topic test_kafka_rep24 --partitions 1 --replication-factor 3
    
    2、生成数据
    /bin/kafka-producer-perf-test.sh  --topic test_kafka_perf1 --num-records 100000000 --record-size 687  --producer-props   bootstrap.servers=10.240.1.134:9092,10.240.1.143:9092,10.240.1.146:9092  batch.size=1000000 acks=1  compression.type=lz4 --throughput 500000
    3、初步结论
    备份数越多,吞吐率越低。
    
    • 测试结果
    batch-size ack message-size compression-codec partition replication throughput MB/S MsgNum/s
    600000 1 4096 lz4 1 1 600000 138.75 211779
    600000 1 4096 lz4 1 2 600000 104.18 159008
    600000 1 4096 lz4 1 3 600000 69.20 105618
    • 测试结论

       Replication是我们对不同partition所做的副本,它的大小会在ISR中显示,为了保证数据的安全性,ISR中掉出的版本应该保持在1,所以此处我们从replica为2开始测试。在ack不同时,其数量的多少会对性能造成线性的影响,数量过少会影响数据的可用性,太多则会白白浪费存储资源,一般建议在2~4为宜,我们设置为3个,既能保障数据的高可用,又避免了浪费过多的存储资源。

    4.1.7 throughout/IO

    • 测试脚本:
    /bin/kafka-producer-perf-test.sh  --topic test_kafka_perf1 --num-records 100000000 --record-size 10240  --producer-props   bootstrap.servers=10.240.1.134:9092,10.240.1.143:9092,10.240.1.146:9092  batch.size=1000000 acks=1  compression.type=lz4 --throughput 10000
    /bin/kafka-producer-perf-test.sh  --topic test_kafka_perf1 --num-records 100000000 --record-size 10240  --producer-props   bootstrap.servers=10.240.1.134:9092,10.240.1.143:9092,10.240.1.146:9092  batch.size=1000000 acks=1  compression.type=lz4 --throughput 30000
    /bin/kafka-producer-perf-test.sh  --topic test_kafka_perf1 --num-records 100000000 --record-size 10240  --producer-props   bootstrap.servers=10.240.1.134:9092,10.240.1.143:9092,10.240.1.146:9092  batch.size=1000000 acks=1  compression.type=lz4 --throughput 50000
    /bin/kafka-producer-perf-test.sh  --topic test_kafka_perf1 --num-records 100000000 --record-size 10240  --producer-props   bootstrap.servers=10.240.1.134:9092,10.240.1.143:9092,10.240.1.146:9092  batch.size=1000000 acks=1  compression.type=lz4 --throughput 70000
    /bin/kafka-producer-perf-test.sh  --topic test_kafka_perf1 --num-records 100000000 --record-size 10240  --producer-props   bootstrap.servers=10.240.1.134:9092,10.240.1.143:9092,10.240.1.146:9092  batch.size=1000000 acks=1  compression.type=lz4 --throughput 100000
    
    • 测试结果
    batch-size ack message-size compression-codec partition replication throughput MB/S MsgNum/s
    1000000 1 687 lz4 1 1 100000 65.46 99907
    1000000 1 687 lz4 1 1 200000 130 199900
    1000000 1 687 lz4 1 1 300000 139.77 213337
    1000000 1 687 lz4 1 1 400000 145.33 221818
    1000000 1 687 lz4 1 1 500000 154.38 235626
    1000000 1 687 lz4 1 1 600000 141 215517
    • 测试结论


       在主题是一个分区和一个副本时,我们看到在并发50w以下时,随着并发数增大,吞吐上升,但是在50w以后时,可以看出并发增大反而吞吐降低了,这是因为IO的限制,在高并发的情况下,产生了阻塞而导致。

    相关文章

      网友评论

        本文标题:kafka-flink性能测试规划(上)

        本文链接:https://www.haomeiwen.com/subject/ngtorctx.html