- 博客(189)
- 收藏
- 关注
原创 Kafka 多线程开发消费实例
Kafka 多线程开发消费实例Kafka Java Consumer 设计原理谈到 Java Consumer API,最重要的当属它的入口类 KafkaConsumer 了。我们说 KafkaConsumer 是单线程的设计,严格来说这是不准确的。因为,从 Kafka 0.10.1.0 版本开始,KafkaConsumer 就变为了双线程的设计,即用户主线程和心跳线程。所谓用户主线程,就是你启动 Consumer 应用程序 main 方法的那个线程,而新引入的心跳线程(Heartbeat Threa
2020-12-19 11:32:18
764
2
原创 Kafka CommitFailedException 异常怎么处理?
Kafka CommitFailedException 异常怎么处理?CommitFailedException,顾名思义就是 Consumer 客户端在提交位移时出现了错误或异常,而且还是那种不可恢复的严重异常。如果异常是可恢复的瞬时错误,提交位移的 API 自己就能规避它们了,因为很多提交位移的 API 方法是支持自动错误重试的,比如commitSync()。每次和 CommitFailedException 一起出现的,还有一段非常著名的注释。为什么说它很“著名”呢?第一,我想不出在近 50 万行
2020-12-18 16:23:49
2120
1
原创 Kafka中位移提交那些事儿
Kafka中位移提交那些事儿Consumer 端有个位移的概念,它和消息在分区中的位移不是一回事,虽然它们的英文都是 Offset。今天我们要聊的位移时 Consumer 的消费位移,它记录了 Consumer 要消费的下一条消息的位移,而不是目前最新消费消息的位移。我来举个例子说明一下,假设一个分区中有 10 条消息,位移分别是 0 到 9 。某个 Consumer 应用已经消费了 5 条消息,这就说明该 Consumer 消费了位移为 0 到 4 的 5 条消息,此时 Consumer 的位移是 5
2020-12-18 14:27:51
237
1
原创 Kafka 消费者组重平衡能避免吗?
Kafka 消费者组重平衡能避免吗?Rebalance 就是让一个 Consumer Group 下所有的 Consumer 实例就如何消费订阅主题的所有分区达成共识的过程。在 Rebalance 过程中,所有的 Consumer 实例共同参与,在协调者组件的帮助下,完成订阅主题分区的分配。但是,在这个过程中,所有实例都不能消费任何消息,因此对 Consumer 的 TPS 影响很大。Coordinator 协调者所谓协调者,在 Kafka 中对应的术语是 Coordinator,它专门为 Con
2020-12-17 19:20:50
784
4
原创 Kafka 中的消费者位移 __consumer_offsets
Kafka 中的消费者位移 __consumer_offsets__consumer_offsets 在 Kafka 源码中有个更为正式的名字,叫位移主题,即 Offsets Topic。老版本 Consumer 的位移管理是依托于 Apache ZooKeeper 的,它会自动或手动地将位移数据提交到 ZooKeeper 中保存。当 Consumer 重启后,它能自动从 ZooKeeper 中读取位移数据,从而在上次消费截止的地方继续消费。这种设计使得 Kafka Broker 不需要保存位移数据,减
2020-12-17 11:29:27
9254
1
原创 Kafka 的消费者组和重平衡(Rebalance)
Kafka 的消费者组消费者组消费者组,即 Consumer Group,应该算是 Kafka 比较有亮点的设计了。用一句话概括就是 Consumer Group 是 Kafka 提供的可扩展且具有容错性的消费者机制。既然是一个组,那么组内必然可以有多个消费者或消费者实例(Consumer Instance),它们共享一个公共的 ID,这个 ID 被称为 Group ID。组内的所有消费者协调在一起来消费订阅主题(Subscribed Topics)的所有分区(Partition)。当然,每个分区只能
2020-12-16 20:16:01
1094
原创 Kafka 消息交付可靠性保障
文章目录Kafka 消息交付可靠性保障至少一次最多一次精确一次幂等性 Producer事务型 Producer小结Kafka 消息交付可靠性保障所谓的消息交付可靠性保障,是指 Kafka 对 Producer 和 Consumer 要处理的消息提供什么样的承诺。常见的承诺有以下三种:至少一次(at least once):消息不会丢失,但有可能被重复发送最多一次(at most once):消息可能会丢失,但绝不会被重复发送精确一次(exactly once):消息不会丢失,也不会被重
2020-12-16 16:49:57
752
原创 Kafka 无消息丢失配置
Kafka 无消息丢失配置Kafka 到底在什么情况下才能保证消息不丢失呢?Kafka 只对“已提交”的消息(commited message)做有限度的持久化保证已提交的消息什么是已提交的消息?当 Kafka 的若干个 Broker 成功地接收到一条消息并写入日志文件后,它们会告诉生产者程序这条消息已成功提交。此时,这条消息在 Kafka 看来就正式变为“已提交”消息了。那为什么是若干个 Broker 呢?这取决于你对“已提交”的定义。你可以选择只要有一个 Broker 成功保存该消息就
2020-12-16 14:24:01
245
原创 Kafka 生产者压缩算法
Kafka 生产者压缩算法说起压缩(compression),我相信你一定不会感到陌生。它秉承了用时间去换空间的经典 trade-off 思想,具体来说就是用 CPU 时间去换磁盘空间或网络 I/O 传输量,希望以较小的 CPU 开销带来更少的磁盘占用或更少的网络 I/O 传输。在 Kafka 中,压缩也是用来做这件事的。今天我就来跟你分享一下 Kafka 中压缩的那些事儿。怎么压缩Kafka 是如何压缩消息的呢?要弄清楚这个问题,就要从 Kafka 的消息格式说起了。目前 Kafka 共有两大类消息
2020-12-16 10:36:14
3020
原创 Kafka 基本概念
Kafka 基本概念Kafka 是一个分布式的消息引擎系统,它的主要功能是提供一套完备的消息发布与订阅解决方案。Topic在 Kafka 中,发布订阅的对象是主题(Topic),你可以为每个业务、每个应用甚至每类数据都创建专属的主题。是承载消息的逻辑容器,在实际使用中多用来区分具体的业务。Producer向主题发布消息的客户端应用程序称为生产者(Producer),生产者程序通常持续不断地向一个或者多个主题发送消息Consumer订阅主题消息的客户端应用程序被称为消费者(Consu
2020-12-15 16:34:30
245
1
原创 JVM 内存模型
JVM 内存模型JVM 内存结构每个线程都只能访问自己的线程栈。每个线程都不能访问(看不见)其他线程的局部变量。所有原生类型的局部变量都存储在线程栈中,因此对其他线程时不可见的。线程可以将一个原生变量值的副本传给另一个线程,但不能共享原生局部变量本身。堆内存中包含了 Java 代码中创建的所有对象,不管是哪个线程创建的。其中也涵盖了包装类型(例如 Byte,Integer,Long 等)不管是创建一个对象并将其赋值给局部变量,还是赋值给另一个对象的成员变量,创建的对象都会保存到堆内存中。
2020-12-11 15:26:54
158
原创 JVM 类加载器
JVM 类加载器类的生命周期一个类从被加载到虚拟机内存开始,到卸载出内存为止,这个生命周期经历了七个阶段:加载、验证、准备、解析、初始化、使用、卸载。加载(Loading):找 Class 文件通过一个类的全限定名来获取定义此类的二进制字节流。将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。在内存中生成一个代表这个类的 java.lang.Class 对象,作为方法区这个类的各种数据的访问入口验证(Verification):验证格式、依赖验证的目的是确保Cl
2020-12-10 19:46:13
154
1
原创 主流服务注册中心对比
主流服务注册中心对比ZookeeperZookeeper 是一个分布式服务框架,是 Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中一些经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。简单来说,zookeeper 本质就是 存储 + 监听通知。zookeeper 用来做服务注册中心,主要是因为它具有节点变更通知功能,只要客户端监听相关服务器节点,服务器节点的所有变更,都能及时地通知到监听的客户端,这样作为调用方只需要使用 zo
2020-12-04 11:30:12
1624
原创 Java常用命令——jps/jstat/jinfo/jmap/jstack
文章目录Java常用命令——jps/jstat/jinfo/jmap/jstackjps:输出Java进程`jps``jps -v` 输出 jvm 启动参数`jps -l` 输出主类名或 jar 包jstat:查看虚拟机运行状态`jstat -class [pid]` 类加载/卸载的总数量/总空间、类加载耗费时间`jstat -gc [pid]` 堆内存各区域用量,垃圾收集时间`jstat -gcutil [pid]` 与-gc差不多,主要关注已使用空间的百分比jinfo:java配置信息`jinfo [p
2020-12-01 20:17:13
871
1
原创 Zookeeper 的 Leader 选举
文章目录Zookeeper 的 Leader 选举服务器启动时的 Leader 选举服务器运行时的 Leader 选举Zookeeper 的 Leader 选举Zookeeper Leader 选举概述Leader 选举是 zookeeper 最重要的技术之一,也是保证分布式数据一致性的关键所在当 zookeeper 集群中的一台服务器出现以下两种情况时,需要进入 Leader 选举。服务器初始化启动。服务器运行期间无法和 Leader 保持连接。服务器启动时的 Leader 选举若
2020-11-24 20:17:28
250
原创 Zookeeper 服务器启动过程
文章目录Zookeeper 服务器启动过程zookeeper服务端整体架构图单机版服务器启动过程预启动初始化集群服务器启动过程预启动初始化Leader 选举Leader 和 Follower 启动期交互过程Leader 和 Follower 启动Zookeeper 服务器启动过程zookeeper服务端整体架构图zookeeper 服务器的启动,大致可以分为以下五个步骤:配置文件解析初始化数据管理器初始化网络I/O管理器数据恢复对外服务单机版服务器启动过程上图的过程可以分为预启动
2020-11-24 19:25:02
1765
原创 Zookeeper 服务器角色
文章目录Zookeeper 服务器角色LeaderFollowerObserverZookeeper 服务器角色LeaderLeader 服务器是 zookeeper 集群工作的核心,其主要工作有以下两个:事务请求的唯一调度和处理者,保证集群事务处理的顺序性;集群内部各服务器的调度者Leader 处理请求的过程:zookeeper使用责任链模式来处理客户端的请求,Leader 服务器的请求处理链如下:可以看到,从 prepRequestProcessor 到 FinalRequestP
2020-11-23 15:34:13
399
原创 Zookeeper 深入进阶 —— ZAB 协议
文章目录Zookeeper 深入进阶 —— ZAB 协议概念ZAB 核心ZAB 协议介绍崩溃恢复模式消息广播模式消息广播过程崩溃恢复过程基本特性:数据同步运行时状态分析ZAB 与 Paxos 的联系和区别联系:区别:Zookeeper 深入进阶 —— ZAB 协议概念在深入了解 zookeeper 之前,很多同学可能会认为 zookeeper 就是 paxos 算法的一个实现。但事实上,zookeeper 并没有完全采用 paxos 算法,而是使用了一种称为 Zookeeper Atomic Broa
2020-11-23 10:21:39
284
原创 Zookeeper 应用场景
文章目录Zookeeper 应用场景数据发布/订阅命名服务集群管理Master 选举分布式锁排他锁共享锁分布式队列FIFO 先进先出Barrier :分布式屏障Zookeeper 应用场景zookeeper 是一个典型的发布/订阅模式的分布式数据管理与协调框架,我们可以使用它来进行分布式数据的发布与订阅。另一方面,通过对 zookeeper 中丰富的数据节点类型进行交叉使用,配合 Watcher 事件通知机制,可以非常方便地构建一系列分布式应用中都会涉及的核心功能,如 数据发布/订阅、命名服务、集群管理
2020-11-18 20:29:08
344
原创 Zookeeper 基本使用
文章目录Zookeeper 基本使用Zookeeper 系统模型Zookeeper 数据模型 ZNodeZNode 的类型事务IDZNode 的状态信息Watcher —— 数据变更通知ACL —— 保障数据的安全权限模式:Scheme授权对象 ID:权限:Zookeeper 基本使用Zookeeper 系统模型Zookeeper 数据模型 ZNode在 Zookeeper 中,数据信息被保存在一个个数据节点上,这些节点被称为 ZNode。ZNode 是 Zookeeper 中最小的数据单位,在ZN
2020-11-17 20:24:04
498
原创 分布式服务治理 Zookeeper 简介
Zookeeper 简介分布式系统定义及面临的问题Zookeeper 最为主要的使用场景,是作为分布式系统的分布式协同服务。我们将分布式系统定义为:分布式系统是同事跨越多个物理主机,独立运行的多个软件所组成的系统。类比一下,分布式系统就是一群人干活,人多力量大,每个服务器的算力是有限的,但是通过分布式系统,由n个服务器组成起来的集群,算力可以试无限扩张的。优点显而易见,人多干活快,并且互为备份,但是缺点也很明显。我们可以想象一下,以一个小研发团队开发软件为例,假设我们有一个5人的项目组,要开始一个系
2020-11-17 15:48:00
413
原创 分布式事务:2PC与3PC
分布式事务数据库事务的基本特性我们知道事务有4个非常重要的特性,即我们常说的 ACID:Atomicity(原子性):是说事务是一个不可分割的整体,所有操作要么全部成功,要么全部失败;Consistency(一致性):是说事务执行前后,数据从一个状态到另一个状态必须是一致的,比如A向B转账(A、B的总金额就是一个一致性状态),不能出现A扣钱了,B却没收到钱的情况;Isolation(隔离性):多个并发事务之间互相隔离,不能互相干扰。这里的并发事务指的是两个事务操作了同一份数据的情况。而对于并发事务
2020-11-07 11:19:51
391
1
原创 Tomcat 服务器核心配置解析
Tomcat 服务器核心配置解析Tomcat服务器核心配置文件路径 Tomcat目录下的\conf\server.xml注意:Tomcat 作为服务器的配置,主要是 server.xml 文件的配置server.xml 中包含了 Servlet 容器的相关配置,即 Catalina 的配置主要标签结构如下:<!-- Server 根元素,创建⼀个Server实例,⼦标签有 Listener、GlobalNamingResources、Service --><Ser
2020-10-23 15:27:04
276
原创 使用Nginx限制白名单及通过不同域名转发请求
worker_processes 1; events { worker_connections 65535;}http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; gzip on; upstream 项目名 { server 127.0.0.1:809
2020-10-14 10:51:27
834
原创 栈
栈如何理解栈?关于“栈”,我有一个非常贴切的例子,就是一摞叠在一起的盘子。我们平时放盘子的时候,都是从下往上一个一个放;取的时候,我们也是从上往下一个一个地依次取,不能从中间任意抽出。后进者先出,先进者后出,这就是典型的“栈”结构。从栈的操作特性来看,栈是一种操作受限的线性表,只允许在一端插入和删除数据。我第一次接触这种数据结构的时候,就对它存在的意义产生了很大的疑惑。因为我觉得,相比数组和链表,栈带给我的只有限制,并没有任何优势。那我直接使用数组或者链表不就好了吗?为什么还要用这个“操作受限”的
2020-09-30 15:02:21
224
原创 链表
链表相比数据,链表是一种稍微复杂一点的数据结构。我们先从底层的存储结构上来看一看:数组需要一块连续的内存空间来存储,对内存的要求比较高。如果我们申请 100MB 大小的数组,当内存中没有连续的、足够大的存储空间时,即便内存的剩余总可用空间大于 100MB ,仍然会申请失败。而链表恰恰相反,它并不需要一块连续的内存空间,它通过“指针”将一组零散的内存块串联起来使用,所以如果我们申请的是 100MB 大小的链表,根本不会有问题。最常见的三种链表结构有:单向链表双向链表循环链表链表通过指针将
2020-09-28 17:00:28
259
原创 数组
数组数组(Array)是一种线性表数据结构。它用一组连续的内存空间,来存储一组具有相同类型的数据。线性表(Linear List):线性表就是数据排成一条线一样的结构。每个线性表上的数据最多只有前和后两个方向。其实除了数组,链表、队列、栈等也是线性表结构。与它相对立的概念是非线性表,比如二叉树、堆、图等。之所以叫非线性,是因为在非线性表中,数据之间并不是简单的前后关系。连续的内存空间和相同类型的数据:正是因为这两个限制,它才有了一个堪称杀手锏的特性,“随机访问” 。但有利就有弊,这两个限制也
2020-09-27 21:01:47
178
原创 Java 集合之 ArrayList
先从 ArrayList 的构造函数说起ArrayList 有三种方式来初始化,构造方法源码如下:public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{ /** * 默认初始容量大小 */ private static final int
2020-09-17 17:51:17
520
原创 理论七:为何说要多用组合少用继承?如何决定该用组合还是继承?
王争《设计模式之美》学习笔记文章目录理论七:为何说要多用组合少用继承?如何决定该用组合还是继承?为什么不推荐使用继承?组合相比继承有哪些优势?如何判断该用组合还是继承?重点回顾为什么不推荐使用继承?组合相比继承有哪些优势?如何判断该用组合还是继承?理论七:为何说要多用组合少用继承?如何决定该用组合还是继承?在面向对象编程中,有一条非常经典的设计原则,那就是:组合优于继承,多用组合少用继承。为什么不推荐使用继承?组合相比继承有哪些优势?如何判断该用组合还是继承?今天,我们就围绕着这三个问题,来详细讲解一
2020-09-15 11:20:05
641
原创 理论六:为什么基于接口而非实现编程?有必要为每个类都定义接口吗?
王争《设计模式之美》学习笔记文章目录理论六:为什么基于接口而非实现编程?有必要为每个类都定义接口吗?如何解读原则中的“接口”二字?如何将这条原则应用到实战中?是否需要为每个类定义接口?重点回顾理论六:为什么基于接口而非实现编程?有必要为每个类都定义接口吗?今天,我们继续讲一个跟“接口”相关的知识点:基于接口而非实现编程。这个原则非常重要,是一种非常有效的提高代码质量的手段,在平时的开发中特别经常被用到。为了让你理解透彻,并真正掌握这条原则如何应用,今天,我会结合一个有关图片存储的实战案例来讲解。除此
2020-09-14 20:23:13
289
原创 理论五:接口vs抽象类的区别?如何用普通的类模拟抽象类和接口?
王争《设计模式之美》学习笔记文章目录理论五:接口vs抽象类的区别?如何用普通的类模拟抽象类和接口?什么是抽象类和接口?区别在哪里?首先,我们来看一下,在 Java 这种编程语言中,我们是如何定义抽象类的。刚刚我们讲了如何定义抽象类,现在我们再来看一下,在 Java 这种编程语言中,我们如何定义接口。抽象类和接口的区别抽象类和接口能解决什么编程问题?首先,我们来看一下,我们为什么需要抽象类?它能够解决什么编程问题?其次,我们再来看一下,我们为什么需要接口?它能够解决什么编程问题?如何模拟抽象类和接口两个语法
2020-09-11 16:35:09
183
原创 理论四:哪些代码设计看似是面向对象,实际是面向过程的?
王争《设计模式之美》学习笔记文章目录理论四:哪些代码设计看似是面向对象,实际是面向过程的?哪些代码设计看似是面向对象,实际是面向过程的?1. 滥用 getter、setter 方法2. 滥用全局变量和全局方法3. 定义数据和方法分离的类在面向对象编程中,为什么容易写出面向过程风格的代码?面向过程编程及面向过程编程语言就真的无用武之地了吗?重点回顾1. 滥用 getter、setter 方法2. Constants 类、Utils 类的设计问题3. 基于贫血模型的开发模式理论四:哪些代码设计看似是面向对象
2020-09-09 16:18:38
764
原创 ES7.6 许可证过期 ElasticsearchSecurityException: current license is non-compliant for [security]
ES7的X-pack许可证是提供免费一个月的试用,但是到期之后,就会隔一段时间报这个错误elasticsearch_1 | {"type": "server", "timestamp": "2020-09-09T04:14:51,347Z", "level": "ERROR", "component": "o.e.x.s.a.f.SecurityActionFilter", "cluster.name": "docker-cluster", "node.name": "elasticsearch", "
2020-09-09 15:11:59
7612
1
原创 理论三:面向对象相比面向过程有哪些优势?面向过程真的过时了吗?
王争《设计模式之美》学习笔记文章目录理论三:面向对象相比面向过程有哪些优势?面向过程真的过时了吗?什么是面向过程编程与面向过程编程语言?面向对象编程相比面向过程编程有哪些优势?1.OOP 更加能够应对大规模复杂程序的开发2.OOP 风格的代码更易复用、易扩展、易维护3.OOP 语言更加人性化、更加高级、更加智能重点回顾1. 什么是面向过程编程?什么是面向过程编程语言?2. 面向对象编程相比面向过程编程有哪些优势?理论三:面向对象相比面向过程有哪些优势?面向过程真的过时了吗?实际上,除了面向对象之外,被
2020-09-05 15:59:28
2257
原创 理论二:封装、抽象、继承、多态分别可以解决哪些编程问题?
王争《设计模式之美》学习笔记文章目录理论二:封装、抽象、继承、多态分别可以解决哪些编程问题?封装(Encapsulation)抽象(Abstraction)继承(Inheritance)多态重点回顾关于封装特性关于抽象特性关于继承特性关于多态特性理论二:封装、抽象、继承、多态分别可以解决哪些编程问题?封装(Encapsulation)首先,我们来看封装特性。封装也叫作信息隐藏或者数据访问保护。类通过暴露有限的访问 接口,授权外部仅能通过类提供的方式(或者叫函数)来访问内部信息或者数据。这句话怎 么理
2020-09-04 18:07:10
667
原创 理论一:当谈论面向对象的时候,我们到底在谈论什么?
王争《设计模式之美》学习笔记文章目录理论一:当谈论面向对象的时候,我们到底在谈论什么?什么是面向对象编程和面向对象编程语言?如何判定某编程语言是否是面向对象编程语言?什么是面向对象分析和面向对象设计?什么是 UML?我们是否需要 UML?重点回顾理论一:当谈论面向对象的时候,我们到底在谈论什么?考虑到各个水平层次的同学,并且保证专栏内容的系统性、全面性,我会循序渐进地讲解跟设计模式相关的所有内容。所以,专栏正文的第一个模块,我会讲一些设计原则、设计思想,比如,面向对象设计思想、经典设计原则以及重构相关
2020-09-04 17:12:18
278
原创 面向对象、设计原则、设计模式、编程规范、重构,这五者有何关系?
面向对象现在,主流的编程范式或者是编程风格有三种,它们分别是面向过程、面向对象和函数式编 程。面向对象这种编程风格又是这其中最主流的。现在比较流行的编程语言大部分都是面向 对象编程语言。大部分项目也都是基于面向对象编程风格开发的。面向对象编程因为其具有 丰富的特性(封装、抽象、继承、多态),可以实现很多复杂的设计思路,是很多设计原 则、设计模式编码实现的基础。对于这部分内容,你需要掌握下面这 7 个大的知识点:面向对象的四大特性:封装、抽象、继承、多态面向对象编程与面向过程编程的区别和联系
2020-09-04 16:53:45
500
原创 升级SpringBoot版本导致NoSuchMethodError: redis/clients/jedis/ScanResult.getStringCursor()
今天在对SpringBoot项目升级的时候,把2.1.8.RELEASE 升级到了 2.3.2.RELEASE ,运行后发现,在获取在线用户的时候,报了一个错误,日志如下:Caused by: java.lang.NoSuchMethodError: redis/clients/jedis/ScanResult.getStringCursor()Ljava/lang/String; (loaded from file:/E:/m2/repository/redis/clients/jedis/3.3.0
2020-08-17 15:07:08
2555
3
原创 Spring Batch入门
文章目录Spring Batch 入门Spring Batch 概述Spring Batch 主要有以下功能:SpringBatch如何实现批处理的官方文档Spring Batch 入门Spring Batch 概述Spring Batch 是一个轻量级的、完善的批处理框架,旨在帮助企业建立健壮的批处理应用。Spring Batch 是Spring的一个子项目,使用Java语言并基于Spring框架为基础开发,使得已经使用Spring框架的开发者或者企业更容易访问和利用服务。Spring Ba
2020-07-31 15:38:11
450
原创 MyBatis-Plus 实体类实现动态表名
项目中使用了 MyBatis-Plus 简化开发,在项目中,对数据库表的操作,可以通过在数据表实体类中添加@TableName("table_name") 来指定该实体所对应的表,如下:@TableName("user")@Datapublic class User implements Serializable { private static final long serialVersionUID = 4462743168115185463L; }在业务中有这么个需求,在Us
2020-07-31 14:38:00
14708
11
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅