大数据面试
Ai之家-开箱测评
这个作者很懒,什么都没留下…
展开
-
一文带你读懂Java语言和JVM的发展历程
大家好,我是笔者无为,今天给大家分享一下Java和JVM的发展历程,如果你觉得我写的不错的话,请在文末给我点个大大的赞,谢谢~本文约2000字,阅读大约需要8分钟文章目录如何理解Java是跨平台的语言如何理解JVM是跨语言的平台Java的发展历程常见的JVMJVM的生命周期?重点说下HotSpot?如何理解Java是跨平台的语言“write once, run anywhere.” 一次写入,导出运行!当Java源代码成功编译成字节码后,如果想在不同的平台上面运行,则无须再次编译这个优势.原创 2021-11-11 20:09:14 · 1878 阅读 · 0 评论 -
8周吃透JVM之年薪百万的Java架构师每天都会思考什么?
思考如何让我的系统变得更快,如何避免系统出现瓶颈。生产中经常会遇到的问题运行着的线上系统突然卡死,系统无法访问,甚至直接OOM!想解决线上JVM GC问题,但却无从下手。新项目上线,对各种JVM参数设置一脸茫然,然后就GG了。每次面试之前都要背一遍JVM的一些原理概念性的东西,然而面试官却经常问把你在实际项目中如何调优JVM参数的,如何解决GC、OOM等问题,导致你一脸懵逼架构师的任务,就是解决这些问题...原创 2021-10-25 14:35:06 · 186 阅读 · 0 评论 -
字节二面,居然给我出的是这道算法题(8)【推荐收藏】
题目是:定义一个二叉树结构,并实现一个接受根结点作为参数,将二叉树中每个节点的左右子节点交换位置的二叉树翻转方法。我给出了以下答案:/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode() {} * TreeNode(int val) { this.val原创 2021-07-25 20:40:42 · 271 阅读 · 2 评论 -
字节二面,居然给我出的是这道算法题(7)【推荐收藏】
题目是:了解算法的空间复杂度和时间复杂度么?时间复杂度:时间复杂度是用来描述算法运行时间和算法处理问题规 模之间关系的一种衡量标准。1.1、忽略公式中的常数项1.2、忽略公式中的低次幂项,仅保留公式中的最高次幂 项1.3、忽略公式中的最高次幂项的常数系数1.4、如果一个公式中所有项均为常数项,那么这个算法的时间复杂 度为o(1) 常见时间复杂度大小关系:o(n*n) > o(nlogn) > o(1)空间复杂度:空间复杂度是用来衡量一个算法在运行 过程中,在除了保存原始数据空间外还需原创 2021-07-25 20:39:45 · 249 阅读 · 1 评论 -
字节二面,出的是这道算法题(6)【推荐收藏】
题目是:请简述反转链表的两种方式及优缺点。这个题目我给出了两个解决方案。一种是循环、一种是递归。递归的优点会不停地压栈弹栈,比较耗时间。代码如下:循环方式 public static Node iterate(Node head){ Node prev = null , next ; Node curr = head ; while(curr != null){ next = curr.next ;//原创 2021-07-25 20:38:11 · 183 阅读 · 1 评论 -
字节二面,出的是这道算法题(5)【推荐收藏】
题目:如何判断一个整数是“2”的整数次幂?我想了想,给出了以下答案:public static boolean isPowerOf2(int num){ return (num & num - 1) == 0;}/*时间复杂度:O(1)*/原创 2021-07-25 20:35:58 · 224 阅读 · 0 评论 -
字节二面,出的是这道算法题(4)【推荐收藏】
题目:给你一个非负整数 num,请你返回将它变成 0 所需要的步数。 如果当前数字是偶数,你需要把它除以 2;否则,减去 1。示例 1:输入:num = 14输出:6解释:步骤 1) 14 是偶数,除以 2 得到 7。步骤 2)7 是奇数,减 1 得到 6。步骤 3)6 是偶数,除以 2 得到 3。步骤 4)3 是奇数,减 1 得到 2。步骤 5)2 是偶数,除以 2 得到 1。步骤 6)1 是奇数,减 1 得到 0。示例 2:输入:num = 8输出:4解释:步骤 1)8 是原创 2021-07-25 20:35:10 · 181 阅读 · 0 评论 -
字节二面,出的是这道算法题(3)【推荐收藏】
题目是:三数之和:给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c,使得 a + b + c = 0?请你找出所有满足条件且不重复的三元组。注意:答案中不可以包含重复的三元组。示例:给定数组 nums = [-1, 0, 1, 2, -1, -4],满足要求的三元组集合为:[[-1, 0, 1],[-1, -1, 2]]求解过程如下:首先我们先把数组排个序(原因一会儿说),排完序长这样:因为我们要同时找三个数,所以采取固定一个数,同时用双指针来查找原创 2021-07-25 20:34:06 · 321 阅读 · 1 评论 -
字节二面,给我出的是这道算法题(2)【推荐收藏】
题目:给你一个非负整数 num ,请你返回将它变成 0 所需要的步数。 如果当前数字是偶数,你需要把它除以 2 ;否则,减去 1 。示例 1:输入:num = 14输出:6解释:步骤 1) 14 是偶数,除以 2 得到 7 。步骤 2) 7 是奇数,减 1 得到 6 。步骤 3) 6 是偶数,除以 2 得到 3 。步骤 4) 3 是奇数,减 1 得到 2 。步骤 5) 2 是偶数,除以 2 得到 1 。步骤 6) 1 是奇数,减 1 得到 0 。示例 2:输入:num = 8输出:原创 2021-07-25 20:29:24 · 213 阅读 · 1 评论 -
字节二面,面试官给我出的是这道算法题
题目:给定一个仅包含大小写字母和空格 ’ ’ 的字符串s,返回其最后一个单词的长度。如果字符串从左向右滚动显示,那么最后一个单词就是最后出现的单词。示例:输入: “Hello World”输出: 5说明: 一个单词是指仅由字母组成、不包含任何空格字符的 最大子字符串。我苦思冥想,给出了以下答案://JAVAclass Solution { public int lengthOfLastWord(String s) { if(s == null |原创 2021-07-23 15:30:26 · 340 阅读 · 2 评论 -
大数据高频面试题之Hive的数据存储格式
类型texfile:默认的存储格式:普通的文本文件,数据不压缩,磁盘的开销比较大,分析开销大。sequencefile:提供的一种二进制存储格式,可以切割,天生压缩。rcfile:提供的是一种行列混合存储方式,该方式会把相近的行和列数据放在一块儿,存储比较耗时,查询效率高,也天生压缩。orc:是rcfile的一种优化存储。parquet:自定义输入输出格式。具体描述1)texfile普通文本文件(通常默认的就是这个格式)创建表create table if not exists one (原创 2021-04-15 19:11:49 · 340 阅读 · 0 评论 -
大数据高频面试题之Hive表数据的加载与导出
Hive表数据加载1)直接向分区表中插入数据insert into table score3 partition(month =‘201807’) values (‘001’,‘002’,‘100’);2)通过查询插入数据先通过load加载创建一个表(linux) load data local inpath ‘/export/servers/hivedatas/score.csv’ overwrite into table score partition(month=‘201806’);(HD原创 2021-04-15 19:06:24 · 251 阅读 · 0 评论 -
大数据高频面试题之Hive常用函数总结
Hive内部支持大量的函数,可以通过 SHOW FUNCTIONS 查看Hive的内置函数。灵活地运用Hive提供的函数能够极大地节省数据分析成本。Hive函数主要包含数学函数,集合函数,类型转换函数,日期函数,条件函数,字符串函数,聚合函数和表生成函数等。1)数学函数数学函数是Hive内部提供的专门用于数学运算的函数,如round()函数和sqrt()函数等。round()函数主要用来对给定的数字进行四舍五入取近似值,如下所示:hive (default)> SELECT ROUND(5.5)原创 2021-04-14 17:57:28 · 332 阅读 · 0 评论 -
大数据高频面试题之Hive的分区及其优势
什么是hive分区 : 就是一种对表进行粗略划分的机制,可以实现加快查询速度的组织形式.在使用分区时, 在表目录下会有相应的子目录,当查询时添加了分区谓词,那么该查询会直接定位到相应的子目录中进行查询,避免全表查询,提成查询效率.注意事项:1 . hive的分区使用的表外字段,分区字段是一个伪列但是可以查询过滤。2 . 分区字段不建议使用中文3 . 不太建议使用动态分区。因为动态分区将会使用mapreduce来查询数据,如果分区数量过多将导致namenode和yarn的资源瓶颈。所以建议动态分区前原创 2021-04-13 14:44:08 · 436 阅读 · 0 评论 -
大数据高频面试题之Hive的严格模式
Hive提供了一个严格模式,可以防止用户执行那些可能意想不到的不好的影响的查询。通过设置属性hive.mapred.mode值为默认是非严格模式nonstrict 。开启严格模式需要修改hive.mapred.mode值为strict,开启严格模式可以禁止3种类型的查询。对于分区表,除非where语句中含有分区字段过滤条件来限制范围,否则不允许执行。换句话说,就是用户不允许扫描所有分区。进行这个限制的原因是,通常分区表都拥有非常大的数据集,而且数据增加迅速。没有进行分区限制的查询可能会消耗令人不可接受的原创 2021-04-13 14:40:14 · 224 阅读 · 0 评论 -
大数据高频面试题之如何合理设置Reduce的数量
1.调整reduce个数方法一(1)每个Reduce处理的数据量默认是256MBhive.exec.reducers.bytes.per.reducer=256000000(2)每个任务最大的reduce数,默认为1009hive.exec.reducers.max=1009(3)计算reducer数的公式N=min(参数2,总输入数据量/参数1)2.调整reduce个数方法二在hadoop的mapred-default.xml文件中修改设置每个job的Reduce个数set mapre原创 2021-04-13 14:37:18 · 435 阅读 · 0 评论 -
大数据高频面试题之Hive的小文件合并
(1)在map执行前合并小文件,减少map数:CombineHiveInputFormat具有对小文件进行合并的功能(系统默认的格式)。HiveInputFormat没有对小文件合并功能。set hive.input.format= org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;(2)在Map-Reduce的任务结束时合并小文件的设置:在map-only任务结束时合并小文件,默认trueSET hive.merge.mapfiles = tr原创 2021-04-13 14:34:09 · 280 阅读 · 0 评论 -
大数据高频面试题之Hive怎么解决数据倾斜
场景: MR中,shuffle阶段的一个key值对应了很多值,那么就会将这么多值分到一个分区中hive中,两个表做join maptask中一个任务处理的时间明显大于其他task的时间 就是出现了数据倾斜的问题开启数据倾斜时负载均衡set hive.groupby.skewindata=true;思想:就是先随机分发并处理,再按照 key group by 来分发处理。操作:当选项设定为 true,生成的查询计划会有两个 MRJob。第一个 MRJob 中,Map 的输出结果集合会随机分布到 Re原创 2021-04-13 14:29:48 · 291 阅读 · 0 评论 -
大数据高频面试题之Hive的自定义函数
1)Hive 自带了一些函数,比如:max/min等,但是数量有限,自己可以通过自定义UDF来方便的扩展。2)当Hive提供的内置函数无法满足你的业务处理需要时,此时就可以考虑使用用户自定义函数(UDF:user-defined function)。3)根据用户自定义函数类别分为以下三种:UDF:User-Defined-Function,用户自定义函数,数据是一进一出,功能类似于大多数数学函数或者字符串处理函数;UDAF:User-Defined Aggregation Function,用户自定原创 2021-04-13 14:25:25 · 229 阅读 · 0 评论 -
大数据高频面试题之HiveSQL的转化过程
Hive是如何将SQL转化为MapReduce任务的,整个编译过程分为六个阶段:1.Antlr定义SQL的语法规则,完成SQL词法,语法解析,将SQL转化为抽象语法树AST Tree;2.遍历AST Tree,抽象出查询的基本组成单元QueryBlock;3.遍历QueryBlock,翻译为执行操作树OperatorTree;4.逻辑层优化器进行OperatorTree变换,合并不必要的ReduceSinkOperator,减少shuffle数据量;5.遍历OperatorTree,翻译为MapR原创 2021-04-08 10:14:44 · 322 阅读 · 0 评论 -
大数据高频面试题之Hive的内部表和外部表
创建表时:创建内部表时,会将数据移动到数据仓库指向的路径;若创建外部表,仅记录数据所在的路径, 不对数据的位置做任何改变。删除表时:在删除表的时候,内部表的元数据和数据会被一起删除, 而外部表只删除元数据,不删除数据。这样外部表相对来说更加安全些,数据组织也更加灵活,方便共享源数据。1.未被external修饰的是内部表【managed table】,被external修饰的为外部表【external table】2.内部表数据由Hive自身管理,外部表数据由HDFS管理。3.内部表数据存储在hiv原创 2021-04-08 10:13:56 · 289 阅读 · 0 评论 -
大数据高频面试题之Hive的优缺点
1)操作接口采用类SQL语法,提供快速开发的能力(简单、容易上手)。2)避免了去写MapReduce,减少开发人员的学习成本。3)Hive的执行延迟比较高,因此Hive常用于数据分析,对实时性要求不高的场合。4)Hive优势在于处理大数据,对于处理小数据没有优势,因为Hive的执行延迟比较高。5)Hive支持用户自定义函数,用户可以根据自己的需求来实现自己的函数。缺点1.Hive的HQL表达能力有限(1)迭代式算法无法表达(2)数据挖掘方面不擅长,由于MapReduce数据处理流程的限制,效原创 2021-04-08 10:12:57 · 382 阅读 · 0 评论 -
Hive的架构组成详解
如图中所示,Hive通过给用户提供的一系列交互接口,接收到用户的指令(SQL),使用自己的Driver,结合元数据(MetaStore),将这些指令翻译成MapReduce,提交到Hadoop中执行,最后,将执行返回的结果输出到用户交互接口。一、概要用户接口:ClientCLI(command-line interface)、JDBC/ODBC(jdbc访问hive)、WEBUI(浏览器访问hive)元数据:Metastore元数据包括:表名、表所属的数据库(默认是default)、表的.原创 2021-04-02 23:40:30 · 774 阅读 · 0 评论 -
Hive是什么?
Hive是什么?一、概述Hive是基于Hadoop的一个数据仓库工具,用来进行数据提取、转化、加载,这是一种可以存储、查询和分析存储在Hadoop中的大规模数据的机制。hive数据仓库工具能将结构化的数据文件映射为一张数据库表,并提供SQL查询功能,能将SQL语句转变成MapReduce任务来执行。Hive的优点是学习成本低,可以通过类似SQL语句实现快速MapReduce统计,使MapReduce变得更加简单,而不必开发专门的MapReduce应用程序。而且,hive十分适合数据仓库的统计分析。二原创 2021-04-02 23:36:52 · 1551 阅读 · 0 评论 -
Hadoop生态圈中各个服务角色
Hadoop生态圈中各个服务角色zookeeper角色:ZooKeeper服务是指包含一个或多个节点的集群提供服务框架用于集群管理。对于集群,Zookeeper服务提供的功能包括维护配置信息、命名、提供HyperBase的分布式同步,推荐在 ZooKeeper集群中至少有3个节点。JDK角色:JDK是 Java 语言的软件开发工具包, JDK是整个Java开发的核心,它包含了Java的运行环境,Java工具和Java基础的类库。Apache-Flume角色:Flume是Cloudera提供原创 2021-04-02 23:35:14 · 280 阅读 · 0 评论 -
Hadoop为什么会有Yarn?
Hadoop为什么会有Yarn?Hadoop2.x较Hadoop1.x来说,变化非常大,主要主要体现在Hadoop2.x引入了“Yarn”这个核心部件。hadoop1.x有两大部件,HDFS和MadpReduce,其中HDFS(Hadoop Distributed Files System)用于分布式存储文件,由一个NameNode和多个DateNode组成,便于集群中各机器从上面读取和写入文件(数据),MadpReduce由一个JobTracker和多个TaskTracker组成,两个核心任务,Map原创 2021-04-02 23:31:34 · 544 阅读 · 0 评论 -
yarn架构组件
YARN 总体上是 master/slave 结构,在整个资源管理框架中,ResourceManager 为 master,NodeManager 是 slave。YARN的基本组成结构,YARN 主要由 ResourceManager、NodeManager、ApplicationMaster 和 Container 等几个组件构成。ResourceManager是Master上一个独立运行的进程,负责集群统一的资源管理、调度、分配等等;NodeManager是Slave上一个独立运行的进程,负责上原创 2021-03-10 16:32:13 · 394 阅读 · 0 评论 -
简单的介绍一下YARN
Apache Yarn(Yet Another Resource Negotiator的缩写)是hadoop集群资源管理器系统,Yarn从hadoop 2引入,最初是为了改善MapReduce的实现,但是它具有通用性,同样执行其他分布式计算模式。在MapReduce1中,具有如下局限性:1、扩展性差:jobtracker兼顾资源管理和作业控制跟踪功能跟踪任务,启动失败或迟缓的任务,记录任务的执行状态,维护计数器),压力大,成为系统的瓶颈2、可靠性差:采用了master/slave结构,master容原创 2021-03-09 21:10:02 · 279 阅读 · 0 评论 -
Mapreduce的combiner
每一个map都可能会产生大量的本地输出,Combiner的作用就是对map端的输出先做一次合并,以减少在map和reduce节点之间的数据传输量,以提高网络IO性能,是MapReduce的一种优化手段之一。combiner是MR程序中Mapper和Reducer之外的一种组件combiner组件的父类就是Reducercombiner和reducer的区别在于运行的位置:Combiner是在每一个maptask所在的节点运行Reducer是接收全局所有Mapper的输出结果;combiner的意原创 2021-03-09 20:56:45 · 245 阅读 · 0 评论 -
MapReduce的序列化
1.概述序列化(Serialization)是指把结构化对象转化为字节流。反序列化(Deserialization)是序列化的逆过程。把字节流转为结构化对象。当要在进程间传递对象或持久化对象的时候,就需要序列化对象成字节流,反之当要将接收到或从磁盘读取的字节流转换为对象,就要进行反序列化。Java的序列化(Serializable)是一个重量级序列化框架,一个对象被序列化后,会附带很多额外的信息(各种校验信息,header,继承体系…),不便于在网络中高效传输;所以,hadoop自己开发了一套序列化原创 2021-03-08 11:46:50 · 232 阅读 · 0 评论 -
MapReduce中排序发生在哪几个阶段?
一个MapReduce作业由Map阶段和Reduce阶段两部分组成,这两阶段会对数据排序,从这个意义上说,MapReduce框架本质就是一个Distributed Sort。在Map阶段,Map Task会在本地磁盘输出一个按照key排序(采用的是快速排序)的文件(中间可能产生多个文件,但最终会合并成一个),在Reduce阶段,每个ReduceTask会对收到的数据排序,这样数据便按照key分成了若干组,之后以组为单位交给reduce方法处理。很多人的误解在Map阶段,如果不使用Combiner便不会排原创 2021-03-08 11:44:47 · 1322 阅读 · 0 评论 -
mapreduce为什么分两部分
是为了实现分布式计算,提高计算效率。很多情况下都是需要对整个数据集进行计算操作,单单的分成每个单独的小部分虽然能提高计算效率,但是导致无法完成实际需求,是没有任何意义的,所以添加一个reduce阶段,负责将分成多个部分计算的结果汇总进行处理,使得更加能满足一般需求...原创 2021-03-07 18:17:01 · 364 阅读 · 0 评论 -
MapReduce的优化
一、概述优化前我们需要知道hadoop适合干什么活,适合什么场景,在工作中,我们要知道业务是怎样的,能才结合平台资源达到最有优化。除了这些我们当然还要知道mapreduce的执行过程,比如从文件的读取,map处理,shuffle过程,reduce处理,文件的输出或者存储。在工作中,往往平台的参数都是固定的,不可能为了某一个作业去修改整个平台的参数,所以在作业的执行过程中,需要对作业进行单独的设定,这样既不会对其他作业产生影响,也能很好的提高作业的性能,提高优化的灵活性。现在回顾下hadoop的优势(适用原创 2021-03-07 18:14:17 · 207 阅读 · 0 评论 -
如何使用MapReduce实现两表的join
map join:map side join 是针对一下场景进行的优化。两个待连接的表中,有一个表非常大,而另一个非常小,以至于小表可以直接存放到内存中。这样,我们可以将小表复制多份,让每一个map task内存中存在一份(比如放在hash table中),然后只扫描大表:对于大表中的每一条记录key/value,在hash table中查找是否具有相同key的记录,入股有,则连接后输出即可。场景:MapJoin 适用于有一份数据较小的连接情况。做法:直接将较小的数据加载到内存中,按照连接的关键字建立原创 2021-03-05 15:25:14 · 991 阅读 · 0 评论 -
MapReduce的shuffle过程
mapper()方法做业务逻辑处理,然后将数据传到分区方法中,给数据标记好分区,将数据发送到环形缓冲区环形缓冲区默认100M,达到80%的阈值进行溢写操作溢写之前会进行排序,排序的规则是字典序排序,排序的手段呢是快排溢写会产生很多溢写文件,溢写文件默认达到10个会进行“墨汁”合并,合并时采用的算法是归并排序也可以进行combiner局部聚合的操作,前提是局部聚合的结果不会对最终的结果有影响等到所有的maptask运行完毕,会启动一定数量的reducetask,并告知reducetask读取数据的范原创 2021-03-05 10:28:01 · 218 阅读 · 1 评论 -
MapReduce编程模型简述(mr任务流程)
1.在客户端执行submit()方法之前,会先去获取一下待读取文件的信息2.将job提交给yarn,这时候会带着三个信息过去(job.split(文件的切片信息),jar.job.xml)3.yarn会根据文件的切片信息去计算将要启动的maptask的数量,然后去启动maptask4.maptask会调用InPutFormat()方法去HDFS上面读取文件,InPutFormat()方法会再去调用RecordRead()方法,将数据以行首字母的偏移量为key,一行数据为value传给mapper(..原创 2021-03-04 14:34:30 · 427 阅读 · 1 评论 -
简单描述MapReduce(mr是什么?)
概念Hadoop MapReduce 是一个分布式计算框架,用于编写批处理应用程序。编写好的程序可以提交到 Hadoop 集群上用于并行处理大规模的数据集。MapReduce作业通常将输入数据集拆分为独立的块,这些任务由map任务以完全并行的方式进行处理。框架对map的输出进行排序,然后将其输入到reduce任务。通常,作业的输入和输出都存储在文件系统中。该框架负责安排任务,监视任务并重新执行失败的任务。MapReduce可以分成Map和Reduce两部分理解。1.Map:映射过程,把一组数据按原创 2021-03-04 14:31:18 · 636 阅读 · 1 评论 -
HDFS压缩方式
文件压缩主要有两个好处,一是减少了存储文件所占空间,另一个就是为数据传输提速。在hadoop大数据的背景下,这两点尤为重要,那么我现在就先来了解下hadoop中的文件压缩。1 gzip压缩优点:压缩率比较高,而且压缩/解压速度也比较快;hadoop本身支持,在应用中处理gzip格式的文件就和直接处理文本一样;有hadoop native库;大部分linux系统都自带gzip命令,使用方便。缺点:不支持split。应用场景:当每个文件压缩之后在130M以内的(1个块大小内),都可以考虑用gzip压缩格原创 2021-03-03 14:41:41 · 925 阅读 · 1 评论 -
HDFS集群优化
操作系统级别优化1.优化文件系统(推荐使用EXT4和XFS文件系统,相比较而言,更推荐后者,因为XFS已经帮我们做了大量的优化。)2.预读缓冲 预读技术可以有效的减少磁盘寻道次数和应用的I/O等待时间,增加Linux文件系统预读缓冲区的大小(默认为256 sectors,128KB),可以明显提高顺序文件的读性能,建议调整到1024或2048 sectors。预读缓冲区的设置可以通过blockdev命令来完成。3.放弃RAID和LVM磁盘管理方式,选用JBOD复制代码不使用RAID 应避原创 2021-03-02 21:16:15 · 357 阅读 · 0 评论 -
大数据面试之HDFS小文件问题及解决方案
小文件是指文件size小于HDFS上block大小的文件。这样的文件会给hadoop的扩展性和性能带来严重问题。首先,在HDFS中,任何block,文件或者目录在内存中均以对象的形式存储,每个对象约占150byte,如果有1000 0000个小文件,每个文件占用一个block,则namenode大约需要2G空间。如果存储1亿个文件,则namenode需要20G空间。这样namenode内存容量严重制约了集群的扩展。 其次,访问大量小文件速度远远小于访问几个大文件。HDFS最初是为流式访问大文件开发的,如原创 2021-03-01 22:40:18 · 478 阅读 · 0 评论
分享