Tomcat 性能调优

Tomcat 容器内的优化

一、 tomcat的3种运行模式

1、 bio

默认的模式,性能非常低下,没有经过任何优化处理和支持. 一个线程处理一个请求。缺点:并发量高时,线程数较多,浪费资源。
Tomcat7或以下,在Linux系统中默认使用这种方式。

2、 nio

nio(new I/O),是Java SE 1.4及后续版本提供的一种新的I/O操作方式(即java.nio包及其子包)。Java nio是一个基于缓冲区、并能提供非阻塞I/O操作的Java API,因此nio也被看成是non-blocking I/O的缩写。它拥有比传统I/O操作(bio)更好的并发运行性能。

利用Java的异步IO处理,可以通过少量的线程处理大量的请求。
配置方式:

打开 tomcat 安装目录 \conf\server.xml文件,定位到这一行:

<Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />

将其修改为

<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
               connectionTimeout="20000"
               redirectPort="8443" />

3、apr

安装起来最困难,但是从操作系统级别来解决异步的IO问题,大幅度的提高性能.
即Apache Portable Runtime,从操作系统层面解决io阻塞问题。
Tomcat7或Tomcat8在Win7或以上的系统中启动默认使用这种方式。
Linux如果安装了apr和native,Tomcat直接启动就支持apr。
具体安装办法 参见这个地址:https://my.oschina.net/lsw90/blog/181161

4、 在那里看我们的tomcat以何种工作模式启动的?

Tomcat启动的时候,可以通过log看到Connector使用的是哪一种运行模式:
Starting ProtocolHandler ["http-bio-8080"]
Starting ProtocolHandler ["http-nio-8080"]
Starting ProtocolHandler ["http-apr-8080"]

二、 执行器(线程池)

默认的tomcat没有启用线程池

在tomcat中每一个用户请求都是一个线程,所以可以使用线程池提高性能。这里前台其实有一个调度线程,然后调度线程会放入线程池内,然后到到一定的时候线程池的任务变成工作线程

1、开启并使用

打开 tomcat 安装目录 \conf\server.xml文件,找到下面这段注释并打开:

<!--
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
    maxThreads="150" minSpareThreads="4"/>
-->

然后找到下面的这个配置,注释掉上面的 Connector ,打开下面被注释掉的 Connector

<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />
<!-- A "Connector" using the shared thread pool-->
<!--
<Connector executor="tomcatThreadPool"
           port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />
-->

2、参数说明

Attribute Description
threadPriority (优先级) (int)线程的线程优先级执行程序,默认是5(NORM_PRIORITY常数)
daemon(守护进程) (boolean)是否应该守护程序线程,线程默认是true
namePrefix(名称前缀) (String) The name prefix for each thread created by the executor. The thread name for an individual thread will be namePrefix+threadNumber
maxThreads(最大线程数) (int) The max number of active threads in this pool, default is 200
minSpareThreads(最小活跃线程数) (int) The minimum number of threads always kept alive, default is 25
maxIdleTime(空闲线程等待时间) (int) 一个空闲的线程shutsdown之前的毫秒数,除非活动线程的数量不等于minSpareThreads。默认值为60000(1分钟)
maxQueueSize(最大的等待队里数,超过则请求拒绝) (int) Integer.MAX_VALUE可运行的最大数量可以排队等待执行的任务之前,我们拒绝他们。默认值是Integer.MAX_VALUE
prestartminSpareThreads (是否在启动时就生成minSpareThreads个线程) (boolean) minSpareThreads是否应该开始在开始执行程序,默认是false
threadRenewalDelay(重建线程的时间间隔) (long) If a ThreadLocalLeakPreventionListener is configured, it will notify this executor about stopped contexts. After a context is stopped, threads in the pool are renewed. To avoid renewing all threads at the same time, this option sets a delay between renewal of any 2 threads. The value is in ms, default value is 1000 ms. If value is negative, threads are not renewed.

二、 连接器(Connector)优化

1、介绍

Connector是连接器,负责接收客户的请求,以及向客户端回送响应的消息。所以 Connector 的优化是重要部分。默认情况下Tomcat支持200线程访问,超过这个数量的连接将被等待甚至超时放弃,所以我们需要提高这方面的处理能力。

打开 tomcat 安装目录 \conf\server.xml文件,找到Connector的配置部分:

<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />

其中 port 代表服务接口;protocol 代表协议类型;connectionTimeout 代表连接超时时间,单位为毫秒;redirectPort 代表安全通信(https)转发端口,一般配置成443。

可以看到除了这几个基本配置外并无特殊功能,所以我们需要对 Connector 进行扩展。

其中Connector 支持参数属性可以参考Tomcat官方网站(https://tomcat.apache.org/tomcat-8.0-doc/config/http.html)非常多,所以本文就只介绍些常用的。

2、通用属性

Attribute Description
allowTrace 如果需要服务器能够处理用户的HAED/TRACE请求,这个值应该设置为true,默认值是false
asyncTimeout 默认超不时候以毫秒为单位的异步恳求。若是没有指定,该属性被设置为10000(10秒)
enableLookups 若是你想request.getRemoteHost()的调用 履行,以便返回的长途客户端的实际主机名的DNS查询,则设置为true。设置为false时跳过DNS查找,并返回字符串情势的IP地址(从而提高性能)。默认景象下,禁用DNS查找。
maxHeaderCount 容器允许的请求头字段的最大数目。请求中包含比指定的限制更多的头字段将被拒绝。值小于0表示没有限制。如果没有指定,默认设置为100。
maxParameterCount 将被容器自动解析的最大数量的参数和值对(GET加上POST)。参数值对超出此限制将被忽略。值小于0表示没有限制。如果没有指定,默认为10000。请注意, FailedRequestFilter 过滤器可以用来拒绝达到了极限值的请求。
maxPostSize 将被容器以FORM URL参数形式处理的最大长度(以字节为单位)的POST。通过设置此属性的值小于或等于0可以禁用该限制。如果没有指定,该属性被设置为2097152(2兆字节)。上传提交的时候可以用的
maxSavePostSize 将被容器在FORM或CLIENT-CERT认证中保存/缓冲的POST的最大尺寸(以字节为单位)。对于这两种类型的身份验证,在用户身份验证之 前,POST将被保存/缓冲。对于POST CLIENT-CERT认证,处理该请求的SSL握手和缓冲清空期间,POST将被缓存。对于Form认证,POST将被保存,同时用户将被重定向到登陆 表单。POST将被一直保留直到用户成功认证或者认证请求关联的会话超时。将此属性设置为-1可以禁用此限制。将此属性设置为0,POST数据在身份验证 过程中将不被保存。如果没有指定,该属性设置为4096(4千字节)。
parseBodyMethods 以逗号分隔的HTTP方法列表,通过方法列表,等同于POST方法,request 正文将被解析成请求参数。这在RESTful应用程序要支持以POST式的语义解析PUT请求中是非常有用的。需要注意的是设置其他值(不是POST)会导致Tomcat的行为违反servlet规范的目的。在这里为了符合HTTP规范明确禁止HTTP方法TRACE。默认值是POST
port TCP端口号,连接器利用该端口号将创建一个服务器套接字,并等待传入的连接。你的操作系统将只允许一个服务器应用程序在一个特定的IP地址侦听特定的端口号。如果使用特殊值0(零),则Tomcat将为连接器随机选择一个空闲的端口。这是通常只用在嵌入式和测试应用程序。
protocol 设置协议来处理传入流量。默认值是 HTTP/1.1,将使用自动切换机制来选择阻塞的基于Java的连接器或APR /native 为基础的连接器。如果PATH(Windows)或LD_LIBRARY_PATH(在大多数Unix系统)的环境变量包含在Tomcat的本地库里,APR /native 连接器将被使用。如果在本地库中无法找到,阻断基于Java的连接器将被使用。需要注意的是使用HTTPS比Java连接器与APR /native 连接器有不同的设置。一个明确的协议,而不是依靠上述自动切换机构,可用以下值: 指定模式 org.apache.coyote.http11.Http11Protocol -阻塞式的Java连接器、 org.apache.coyote.http11.Http11NioProtocol -不阻塞Java连接器、org.apache.coyote.http11.Http11AprProtocol的 -的APR / native 连接器。 也可以使用的用户自定义的实现。看一看在我们的连接器比较图。Java连接器,HTTP和HTTPS,配置是相同的。 APR连接器和APR特定的SSL设置的更多信息,请访问APR文档
proxyName 如果这个连接正在使用的代理服务器配置,配置该属性指定的服务器的名称,可以调用request.getServerName()返回。有关更多信息,请参见代理支持。
proxyPort 如果这个连接正在使用的代理服务器配置,配置该属性指定服务器端口,可以调用request.getServerPort()返回。有关更多信息,请参见代理支持。
redirectPort 如果该连接器支持非SSL请求,并且接收到的请求为满足安全约束需要SSL传输, Catalina 将自动将请求重定向到指定的端口号。
scheme 将该属性设置为你想调用request.getScheme()返回的协议的名称。例如,对于SSL连接器,你会将此属性设置为“HTTPS ”。默认值是“ HTTP ”。
secure 如果你想调用request.isSecure()收到此连接器的请求返回true,请该该属性设置为true。您希望SSL连接器或非SSL连接器接收数据通过一个SSL加速器,像加密卡,SSL设备,甚至一个web服务器。默认值是假的。
URIEncoding 解决我们的乱码问题,这将指定使用的字符编码​​,来解码URI字符。如果没有指定,ISO-8859-1将被使用。
useBodyEncodingForURI 这指定是否应该用于URI查询参数,而不是使用URIEncoding contentType中指定的编码。此设置兼容性Tomcat 4.1.x版(该版在contentType中指定编码,或者使用request.setCharacterEncoding的方法显式设置(参数为 URL传来的值)。默认值false。
useIPVHosts 将该属性设置为true会导致Tomcat使用收到请求的IP地址,来确定将请求发送到哪个主机。默认值是假的。
xpoweredBy 将此属性设置为true会导致Tomcat支持使用Servlet规范的通知,(在规范中推荐使用头字段)。默认值是假的。

2、标准实现

除了上面列出的常见的连接器属性,标准的HTTP连接器(BIO,NIO和APR/native)都支持以下属性。

Attribute Description
acceptCount 当所有可能的请求处理线程都在使用时,传入连接请求的最大队列长度。当队列满时收到的任何请求将被拒绝。默认值是100。
acceptorThreadCount 用于接受连接的线程的数量。在一个多CPU的机器上,增加该值,虽然你可能不会真正需要超过2个。此外,有很多非保持活动连接,您可能需要增加这个值。默认值是 1。
acceptorThreadPriority 接收器线程的优先级。该线程用来接受新的连接。默认值是5(java.lang.Thread.NORM_PRIORITY常量)。更多这个优先级是什么意思的详细信息,请查看java.lang.Thread的类的JavaDoc 。
address 对于拥有多个IP地址的服务器,该属性指定哪个地址将被用于在指定端口上监听。默认情况下,该端口将被用于与服务器相关联的所有IP地址。
bindOnInit 控制连接器绑定时套接字的使用。缺省情况,当连接器被启动时套接字被绑定和当连接器被销毁时套接字解除绑定。如果设置为false,连接器启动时套接字被绑定,连接器停止时套接字解除绑定。
compressableMimeType 该值是一个被用于HTTP压缩的逗号分隔的MIME类型列表。默认值是text / html类型,为text / xml,text / plain。
compression 通常会在ngnix里面配置压缩 ,开启压缩GZIP 为了节省服务器带宽,连接器可以使用HTTP/1.1 GZIP压缩。可接受的参数的值是“off ”(禁用压缩),“on ”(允许压缩,这会导致文本数据被压缩),“force ”(强制在所有的情况下压缩),或者一个整数值(这是相当于为“on”,但指定了输出之前被压缩的数据最小量)。如果不知道内容长度但被设置为“on”或更积极的压缩,输出的数据也将被压缩。如果没有指定,该属性被设置为“关”。 注意:这是使用压缩(节省您的带宽)和使用sendfile功能(节省你的CPU周期)之间的权衡。如果连接器支持sendfile功能,例如NIO连接,则使用sendfile将优先于压缩。症状是48 KB的静态文件将未压缩就发送。你可以如下文所述通过设置连接器的useSendfile属性来关闭sendfile,或在默认的conf/web.xml或者你的web应用的web.xml中配置DefaultServlet来改变sendfile的使用量阈值。
compressionMinSize 如果压缩被设置为“on”,那么该属性可以用于指定在输出之前被压缩的数据的最小量。如果未指定,此属性默认为“2048”。
connectionLinger 连接器的套接字被关闭时的逗留秒数。如果没有指定,将使用默认的JVM。
connectionTimeout 在将提交的请求URI行呈现之后,连接器将等待接受连接的毫秒数。使用值-1表示没有超时(即无限)。默认值是60000(60秒),但请注意,Tomcat的标准server.xml中,设置为20000(即20秒)。
connectionUploadTimeout 上传数据过程中,指定的以毫秒为单位超时时间。只有在设置disableUploadTimeout为false有效。
disableUploadTimeout 此标志允许servlet容器在数据上传时使用不同的连接超时,通常较长。如果没有指定,该属性被设置为true,禁用上传超时。
executor 指向Executor元素的引用。如果这个属性被设置,并且被命名的executor存在,连接器将使用这个executor,而其他所有线程相关属性将被忽略。请注意共享的executor如果没有指定到一个连接器,则该连接器将使用一个私有的,内部的executor来提供线程池。
executorTerminationTimeoutMillis The time that the private internal executor will wait for request processing threads to terminate before continuing with the process of stopping the connector. If not set, the default is 0 (zero) for the BIO connector and 5000 (5 seconds) for the NIO and APR/native connectors.
keepAliveTimeout 此连接器在关闭连接之前将等待另一个HTTP请求的毫秒数。默认值是使用已设置的connectionTimeout属性的值。使用值-1表示没有超时(即无限)。
maxConnections 在任何给定的时间服务器接受并处理的最大连接数。当这个数字已经达到了,服务器将不会接受任何连接,直到连接的数量降到低于此值。基于acceptCount的设置,操作系统可能仍然接受连接。默认值根据不同的连接器类型而不同。对于BIO,默认的是maxThreads的值,除非使用了Executor,在这种情况下默认值是executor的maxThreads值 。对于NIO的默认值是10000。APR /native的默认值是8192。 需要注意的是Windows系统的APR/native,所配置的值将减少到小于或等于maxConnections的1024的倍数的最大值。这样做是出于性能方面的考虑。如果设置的值-1,maxConnections功能被禁用,而且连接数将不做计算。
maxExtensionSize Limits the total length of chunk extensions in chunked HTTP requests. If the value is -1, no limit will be imposed. If not specified, the default value of 8192 will be used.
maxHttpHeaderSize 请求和响应的HTTP头的(以字节为单位的)最大尺寸。如果没有指定,该属性被设置为8192(8 KB)。
maxKeepAliveRequests HTTP请求最大长连接个数。将此属性设置为1,将禁用HTTP/1.0、以及HTTP/1.1的长连接。设置为-1,不禁用。如果没有指定,该属性被设置为100。
maxSwallowSize The maximum number of request body bytes (excluding transfer encoding overhead) that will be swallowed by Tomcat for an aborted upload. An aborted upload is when Tomcat knows that the request body is going to be ignored but the client still sends it. If Tomcat does not swallow the body the client is unlikely to see the response. If not specified the default of 2097152 (2 megabytes) will be used. A value of less than zero indicates that no limit should be enforced.
maxThreads 最多同时处理的连接数,Tomcat使用线程来处理接收的每个请求。这个值表示Tomcat可创建的最大的线程数。如果没有指定,该属性被设置为200。如果使用了execute将忽略此连接器的该属性,连接器将使用execute,而不是一个内部线程池来处理请求。
maxTrailerSize 限制一个分块的HTTP请求中的最后一个块的尾随标头的总长度。如果该值是-1,没有限制的被强加。如果没有指定,默认值是8192。
minSpareThreads 始终保持运行最小线程数。如果没有指定,则默认为10。
noCompressionUserAgents 该值是一个正则表达式(使用java.util.regex),匹配不应该使用压缩的HTTP客户端的用户代理标头。因为这些客户端,虽然他们宣称支持压缩功能,但实现不完整。默认值是一个空字符串(正则表达式匹配禁用)。
processorCache 协议处理器缓存Processor对象以提高性能。此设置规定了这些对象有多少能得到缓存。-1意味着无限制,默认为200。如果不使用Servlet 3.0的异步处理,一个好的默认是使用maxThreads设置。如果使用Servlet 3.0的异步处理,一个好的默认是使用maxThreads和最大预期的并发请求(同步和异步)的最大值中的较大值。
restrictedUserAgents 该值是一个正则表达式(使用java.util.regex),匹配用户代理头的HTTP浏览器将不能使用HTTP/1.1或HTTP/1.0长连接,即使该浏览器宣称支持这些功能的。默认值是一个空字符串(正则表达式匹配禁用)。
server 覆盖服务器的HTTP响应头。如果设置了这个属性的值将覆盖Web应用程序设置的Tomcat的默认头和任何服务器头。如果没有设置,应用程序指定的任何值将被使用。如果应用程序没有指定一个值,那么Apache-Coyote/1.1将被使用。除非你是偏执狂,你将不再需要此功能。
socketBuffer 为套接字输出缓冲而提供的缓冲区的大小(以字节为单位)。-1可以被指定来禁止使用的缓冲区。默认情况下,一个9000个字节的缓冲区将被使用。
SSLEnabled 在连接器上使用此属性来启用SSL加密传输。如果要打开SSL握手/加密/解密,请设置true。默认值是false。当设置这个值为true时,为了传递正确的request.getScheme()和 request.isSecure()到servlets,你需要设置scheme和secure属性。更多信息请查看SSL支持。
tcpNoDelay 如果设置为true,TCP_NO_DELAY选项将被设置在服务器上的套接字上,在大多数情况下,这样可以提高性能。默认设置为true。
threadPriority 在JVM中请求处理线程的优先级。默认值是5(java.lang.Thread.NORM_PRIORITY常量值)。关于优先级的更多详细信息,请查看java.lang.Thread的类的JavaDoc
upgradeAsyncWriteBufferSize The default size of the buffer to allocate to for asynchronous writes that can not be completed in a single operation. Data that can't be written immediately will be stored in this buffer until it can be written. If more data needs to be stored than space is available in the buffer than the size of the buffer will be increased for the duration of the write. If not specified the default value of 8192 will be used.

3、NIO的具体配置

Attribute Description
pollerThreadCount (int)用来处理轮询事件的线程的数量。在版本7.0.27及以前版本,默认值是每个处理器1个。版本7.0.28的默认值是每个处理器1个,但不超过2个。当接受一个套接字,操作系统拥有全局的锁。所以超过2个线程的好处而迅速减小。有一个以上的线程是因为系统需要非常迅速地接受连接。但通常只要增加acceptCount值就可以解决这个问题。增加该值也可能是有用的,当大量发送文件操作发生的时候。
pollerThreadPriority (int)轮询线程的优先级。默认值是5(java.lang.Thread.NORM_PRIORITY常量值)。优先级的更多详细信息,可以查考java.lang.Thread类的JavaDoc 。
selectorTimeout (int)选择轮询器select()的超时时间(以毫秒为单位)。这个值非常重要,因为连接清理工作也是在同一个线程里的,所以不要将此值设置为一个非常高的。默认值是1000毫秒。
useComet (bool)是否允许Comet servlet。默认值是 true。
useSendfile (bool)使用此属性来启用或禁用sendfile的能力。默认值是true。
socket.directBuffer (bool)选择使​​用直接ByteBuffers或Java映射的ByteBuffers。默认是false。当您使用直接ByteBuffers,请确保你分配适当的内存量给直接内存空间。在Sun的JDK中,配置如-XX:MaxDirectMemorySize = 256M。
socket.appReadBufSize (int)在Tomcat中每个连接的开辟连接一个读ByteBuffer。此属性控制这个缓冲区的大小。默认情况下,这个读缓冲区大小为8192字节。对于较低的并发,你可以增加这个值以缓冲更多的数据。对于长连接数很多的情况,你需要降低这个数值或者增加堆大小。
socket.appWriteBufSize (int)在Tomcat中每个连接的开辟连接一个写ByteBuffer。此属性控制这个缓冲区的大小。默认情况下,这个写缓冲区大小为8192字节。对于较低的并发,你可以增加这个值以缓冲更多的响应数据。对于长连接数很多的情况,你需要降低这个数值或者增加堆大小。这里的默认值是相当低的,如果面对的不是几万并发连接,你应该增大该值。
socket.bufferPool (int)NIO连接器使用NioChannel这个类来持有链接到一个套接字的元素。为了减少垃圾收集,NIO连接器缓存这些通道的对象。此值指定这个缓存的大小。默认值是500,表示缓存将持有500个 NioChannel的对象。-1表示不限制缓存大小,0表示不缓存。
socket.bufferPoolSize (int)NioChannel池,也可以是基于尺寸大小,而不是基于对象数的。该大小的计算如下:NioChannel的缓冲区大小=读取缓冲区大小+写入缓冲区大小 SecureNioChannel的缓冲区大小=应用程序读取缓冲区大小+应用程序写入缓冲区的大小+网络读取缓冲区大小+网络写入缓冲区的大小值(以字节为单位),默认值1024 * 1024 * 100 (100MB)。
socket.processorCache (int)以减少垃圾收集,Tomcat缓存SocketProcessor对象。该值指定保持在缓存中最多有多少个对象。默认值是500。-1表示不限制缓存大小,0表示不缓存。
socket.keyCache (int)以减少垃圾收集,Tomcat缓存KeyAttachment对象。该值指定保持在缓存中最多有多少个对象。默认值是500。-1表示不限制缓存大小,0表示不缓存。
socket.eventCache (int)以减少垃圾收集,Tomcat缓存PollerEvent对象。该值指定保持在缓存中最多有多少个对象。默认值是500。-1表示不限制缓存大小,0表示不缓存。
selectorPool.maxSelectors (int)以减少选择器的争用,在池中使用的选择器最大个数。命令行org.apache.tomcat.util.net.NioSelectorShared值设置为false时,使用此选项。默认值是200。
selectorPool.maxSpareSelectors (int)以减少选择器的争用,在池中使用的最大备用选择器个数。当选择器返回到池中时,系统可以决定保留它或者让他垃圾回收。当org.apache.tomcat.util.net.NioSelectorShared 值设置为false时,使用此选项。默认值是-1(无限制)。
command-line-options 下面的命令行选项可用于NIO连接器:-Dorg.apache.tomcat.util.net.NioSelectorShared=true或false 默认情况下是true。如果你想每个线程使用一个选择器,将此值设置为false。当你将它设置为false,你可以通过使用selectorPool.maxSelectors属性控制选择器池的大小。
oomParachute (int)NIO连接器实现了一个名叫parachute的OutOfMemoryError错误的策略。它拥有一个块的数据作为一个字节数组。在一个OOM的情况下,这个数据块被释放,并报告错误。这会给VM足够的空间来清理。oomParachute代表parachute(字节数组)的大小(以字节为单位)。默认值是 1024 * 1024(1MB)。请注意,这仅适用于关于Java堆空间的OOM错误,也不是绝对保证,你将能够恢复所有。如果你有一个Java堆之外OOM的,那么这个parachute也无济于事。

推荐阅读更多精彩内容

  • Tomcat在各位JavaWeb从业者常常就是默认的开发环境,但是Tomcat的默认配置作为生产环境,尤其是内存和...
    泡菜爱上WaSabi阅读 468评论 0 0
  • tomcat通常是作为开发环境的容器,其配置也默认是开发环境的,在性能提升方面还有很大空间。 本文主要从三个方面介...
    北你妹的风阅读 2,423评论 0 3
  • 1、目录:a、基础调优b、JVM 优化c、高级调优2、基础调优:2.1、tomcat的各版本的优化参数有点不一样,...
    笑才阅读 5,727评论 2 5
  • 增加JVM内存,修复JRE内存泄漏,线程池设置,安装apr,压缩 Tomcat性能优化方案整理 考虑一下这种场景,...
    SkTj阅读 717评论 0 0
  • 试想以下这个情景: 你已经开发好了一个程序,这个程序的排版很不错,而且有着最前沿的功能和其他一些让你这程序增添不少...
    FTOLsXD阅读 392评论 0 3
  • 格格独自出门,锁好了门,进了电梯,在电梯里的一个叔叔问“你怎么一个人啊?”,格格回答道“我今天一个人去幼儿...
    阿连格格阅读 172评论 0 0
  • 天气太热了,小狗躺在地上不愿意起来。湖南怀化这个地方,我怎么说你好呢?
    萍果粒阅读 82评论 1 1
  • 白色氢气球与黑色氢气球,虽然颜色不一,但是唯一相同的是气球里装满了氢气,它们都能飞上天空。—— 这也是说,一个人...
    不知会遇见lee阅读 82评论 0 0