Linux中,Tomcat 怎么承载高并发(深入Tcp参数 backlog)

一、前言

这两天看tomcat,查阅 tomcat 怎么承载高并发时,看到了backlog参数。我们知道,服务器端一般使用mq来减轻高并发下的洪峰冲击,将暂时不能处理的请求放入队列,后续再慢慢处理。其实操作系统已经帮我们做了一些类似的东西了,这个东西就是backlog。服务端一般通过 accept 调用,去获取socket。但是假设我们的程序处理不过来(比如因为程序bug,或者设计问题,没能及时地去调用 accept),那么此时的网络请求难道就直接丢掉吗?

当然不会!这时候,操作系统会帮我们放入 accept 队列,先暂存起来。等我们的程序缓过来了,直接调用  accept 去 队列取就行了,这就达到了类似mq的效果。

而 backlog,和另一个参数 /proc/sys/net/core/somaxconn 一起,决定了队列的容量,算法为:min(/proc/sys/net/core/somaxconn, backlog) 。

文章比较长,如果只需要结论,看第三章的总结即可,有时间的话,可以仔细看看正文、第四章的验证部分。 如果只想知道怎么设置这个值,直接跳到最后即可。

下面这篇文章,基础原理讲得很不错。但是是外国人写的,我这里简(tong)单(ku)翻译一下,我也会结合自己的理解,做一些补充。原文链接:http://veithen.io/2014/01/01/how-tcp-backlog-works-in-linux.html

正文之前,查了下linux中的说明。在linux下,执行 man listen,可以看到:

int listen(int sockfd, int backlog);

DESCRIPTION
listen() marks the socket referred to by sockfd as a passive socket, that is, as a socket that will be used to accept incoming connection requests using accept(2).

The backlog argument defines the maximum length to which the queue of pending connections for sockfd may grow. If a connection request arrives when the queue is full, the client may receive an error with an indication of
ECONNREFUSED or, if the underlying protocol supports retransmission, the request may be ignored so that a later reattempt at connection succeeds.

The behavior of the backlog argument on TCP sockets changed with Linux 2.2. Now it specifies the queue length for completely established sockets waiting to be accepted, instead of the number of incomplete connection
requests. The maximum length of the queue for incomplete sockets can be set using /proc/sys/net/ipv4/tcp_max_syn_backlog. When syncookies are enabled there is no logical maximum length and this setting is ignored. See
tcp(7) for more information.

我们着重看上面红色部分,“backlog 的意义从linux 2.2开始,发生了变化。现在,这个参数指定了已完成三次握手的 accept 队列的长度,而不是半连接队列的长度。半连接队列的长度可以通过 /proc/sys/net/ipv4/tcp_max_syn_backlog来设置”

所以,下次,如果面试官问你这个参数的意思是什么,那基本上答上面这句就没问题了。

但我们还是继续拓展下。下面我用渣英语翻译一下,权当锻炼了。

二、翻译正文

1、两种实现方式

当一个程序要进行监听时,需要调用listen函数,此时,需要制定backlog参数。该参数,通常指定socket连接队列的长度。

因为tcp连接的建立需要三次握手,因此,站在服务端的角度,一个到来的连接在变成established之前,需要经过一个中间状态SYN RECEIVED;

进入established状态后,此时如果服务端调用accept操作,即可返回该socket。这意味着,tcp/ip协议栈要实现backlog队列,有两种选择:

1、使用一个单独的队列,队列的长度由 listen 调用的 backlog 参数决定。当收到一个 syn 包时,给客户端返回 SYN/ACK,并将此链接加入到队列。

当对应的 ACK 到达后, 连接状态改变为 ESTABLISHED,然后即可移交给应用程序处理。 这意味着,队列可以包含两种状态的连接: SYN RECEIVED 和 ESTABLISHED。

只有处于 ESTABLISHED 状态的连接,才能返回给应用程序发起的 accept 调用。

2、使用两个队列,一个 SYN 队列(或者叫做 半连接队列) 和一个 accept 队列(或者叫做 完全连接队列)。 处于 SYN RECEIVED 状态的连接将被加入到 SYN 队列,后续当

状态变为 ESTABLISHED 状态时(比如三次握手中的最后一次 ACK 到达时),被移到 accept 队列。 就像 accept函数的名字所表示的那样, 实现 accept 调用时,只需要简单地从

accept 队列中获取连接即可。 在这种实现方式下, backlog 参数决定了 accept 队列的长度。

2、BSD 的选择

历史上, BSD 系统的 TCP 实现,使用第一种方式。 这种方式下,当 队列达到 backlog 指定的最大值时, 系统将不再给客户端发来的 SYN 返回 SYN/ACK 。 通常, TCP 实现会简单地丢弃 SYN 包(甚至不会返回 RST 包),因此客户端会触发重试。 这个在  W. Richard Stevens 老爷子的 TCP/IP 卷三种的14.5节有讲。值得注意的是, Stevens 老爷子解释了, BSD 实际上确实用了两个单独的队列, 但是它们表现的和一个单独的,具有backlog参数指定的长度的队列没什么差别。比如,BSD 逻辑上表现得和下面的表述一致:

队列的大小是半连接队列的长度 和 全连接队列的长度之和。(意思是 sum = 半连接队列长度 + 全连接队列长度)

3、Linux 的选择

在linux 上,事情不太一样,在 listen 调用的 man page 上(就是咱们前言那一段):

The behavior of the backlog argument on TCP sockets changed with Linux 2.2. Now it specifies the queue length forcompletely established sockets waiting to be accepted,

instead of the number of incomplete connection requests. The maximum length of the queue for incomplete sockets can be set using /proc/sys/net/ipv4/tcp_max_syn_backlog.

这意味着, Linux非要对着干,选了第二种方案: 一个 SYN 队列, 大小由 系统级别的参数指定 ; 一个 accept 队列, 大小由应用程序指定。

下面图的意思是,服务端收到 SYN 后,会把该socket 放入 syns queue ,当该 socket 的 ack到来时, 服务端将其从 syns queue取出来,移到 accept queue 中。应用程序调用 accept 时,其实就是去 accept 队列取。

4、linux实现中, accept 队列满了怎么办

有个问题是, 如果 accept 队列满了, 一个连接又需要从 SYN 队列移到 accept 队列时(比如收到了三次握手中的第三个包,客户端发来的 ack),linux 下的该种实现会如何表现呢?

这种场景下的代码处理在 net/ipv4/tcp_minisocks.c 中的 tcp_check_req 函数:

 child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL);
        if (child == NULL)
                goto listen_overflow;

对于 ipv4, 代码中第一行会最终调用net/ipv4/tcp_ipv4.c 中的 tcp_v4_syn_recv_sock:

ctcp_v4_syn_recv_sock的方法实现:

if (sk_acceptq_is_full(sk))
                goto exit_overflow;

这里,我们看到有对accept 队列的检测。 exit_overflow 后的代码,会进行一些清理工作, 更新 /proc/net/netstat中的 ListenOverflows 和 ListenDrops 统计信息 。 这会触发 tcp_check_req 中 listen_overflow的执行:

## 看起来像我们的监听者模式。。。listen_overflow:
        if (!sysctl_tcp_abort_on_overflow) {
                inet_rsk(req)->acked = 1;
                return NULL;
        }

这个什么意思呢? 意思是,除非  /proc/sys/net/ipv4/tcp_abort_on_overflow 设为 1 ,(这种情况下,会发送 RST 包),否则就什么都不做。

(emmmm 。。。。。。有点偷懒?)

总结一下, 如果 linux 下的tcp实现,在 accept 队列满的情况下,收到了 三次握手中的最后一次 ack 包, 它就直接无视这个包。 一开始,看起来有点奇怪,但是记得, SYN RECEIVED 状态下的 socket 有一个定时器。

该定时器的机制: 如果 ack 包没收到(或者被无视,就像我们上面描述的这个情况), tcp 协议栈 会重发 SYN/ACK 包。(重发次数由 /proc/sys/net/ipv4/tcp_synack_retries  指定)

译者这里补充下:

答案: 若 /proc/sys/net/ipv4/tcp_abort_on_overflow = 0,服务端直接忽略该ack,因为服务端一直处于 SYN RECEIVED,触发了定时器,该定时器会重传 SYN/ACK 给客户端,(不超过 /proc/sys/net/ipv4/tcp_synack_retries 指定的次数 );如果 /proc/sys/net/ipv4/tcp_abort_on_overflow = 1, 则服务端会直接返回 RST,而不会重传 SYN/ACK。

通过下面的网络跟踪包(一个客户端试图连接到一个服务端的,队列已达到最大 backlog 值的监听 socket),我们看看会是神马情况:

0.000  127.0.0.1 -> 127.0.0.1  TCP 74 53302 > 9999 [SYN] Seq=0 Len=0
  0.000  127.0.0.1 -> 127.0.0.1  TCP 74 9999 > 53302 [SYN, ACK] Seq=0 Ack=1 Len=0
  0.000  127.0.0.1 -> 127.0.0.1  TCP 66 53302 > 9999 [ACK] Seq=1 Ack=1 Len=0
  0.000  127.0.0.1 -> 127.0.0.1  TCP 71 53302 > 9999 [PSH, ACK] Seq=1 Ack=1 Len=5
  0.207  127.0.0.1 -> 127.0.0.1  TCP 71 [TCP Retransmission] 53302 > 9999 [PSH, ACK] Seq=1 Ack=1 Len=5
  0.623  127.0.0.1 -> 127.0.0.1  TCP 71 [TCP Retransmission] 53302 > 9999 [PSH, ACK] Seq=1 Ack=1 Len=5
  1.199  127.0.0.1 -> 127.0.0.1  TCP 74 9999 > 53302 [SYN, ACK] Seq=0 Ack=1 Len=0
  1.199  127.0.0.1 -> 127.0.0.1  TCP 66 [TCP Dup ACK 6#1] 53302 > 9999 [ACK] Seq=6 Ack=1 Len=0
  1.455  127.0.0.1 -> 127.0.0.1  TCP 71 [TCP Retransmission] 53302 > 9999 [PSH, ACK] Seq=1 Ack=1 Len=5
  3.123  127.0.0.1 -> 127.0.0.1  TCP 71 [TCP Retransmission] 53302 > 9999 [PSH, ACK] Seq=1 Ack=1 Len=5
  3.399  127.0.0.1 -> 127.0.0.1  TCP 74 9999 > 53302 [SYN, ACK] Seq=0 Ack=1 Len=0
  3.399  127.0.0.1 -> 127.0.0.1  TCP 66 [TCP Dup ACK 10#1] 53302 > 9999 [ACK] Seq=6 Ack=1 Len=0
  6.459  127.0.0.1 -> 127.0.0.1  TCP 71 [TCP Retransmission] 53302 > 9999 [PSH, ACK] Seq=1 Ack=1 Len=5
  7.599  127.0.0.1 -> 127.0.0.1  TCP 74 9999 > 53302 [SYN, ACK] Seq=0 Ack=1 Len=0
  7.599  127.0.0.1 -> 127.0.0.1  TCP 66 [TCP Dup ACK 13#1] 53302 > 9999 [ACK] Seq=6 Ack=1 Len=0
 13.131  127.0.0.1 -> 127.0.0.1  TCP 71 [TCP Retransmission] 53302 > 9999 [PSH, ACK] Seq=1 Ack=1 Len=5
 15.599  127.0.0.1 -> 127.0.0.1  TCP 74 9999 > 53302 [SYN, ACK] Seq=0 Ack=1 Len=0
 15.599  127.0.0.1 -> 127.0.0.1  TCP 66 [TCP Dup ACK 16#1] 53302 > 9999 [ACK] Seq=6 Ack=1 Len=0
 26.491  127.0.0.1 -> 127.0.0.1  TCP 71 [TCP Retransmission] 53302 > 9999 [PSH, ACK] Seq=1 Ack=1 Len=5
 31.599  127.0.0.1 -> 127.0.0.1  TCP 74 9999 > 53302 [SYN, ACK] Seq=0 Ack=1 Len=0
 31.599  127.0.0.1 -> 127.0.0.1  TCP 66 [TCP Dup ACK 19#1] 53302 > 9999 [ACK] Seq=6 Ack=1 Len=0
 53.179  127.0.0.1 -> 127.0.0.1  TCP 71 [TCP Retransmission] 53302 > 9999 [PSH, ACK] Seq=1 Ack=1 Len=5
106.491  127.0.0.1 -> 127.0.0.1  TCP 71 [TCP Retransmission] 53302 > 9999 [PSH, ACK] Seq=1 Ack=1 Len=5
106.491  127.0.0.1 -> 127.0.0.1  TCP 54 9999 > 53302 [RST] Seq=1 Len=0

由于 客户端的 tcp 协议栈收到了多个 SYN/ACK 包, 因此,它假设 ACK 包丢失了,于是进行重发。(可以看上面的 带有 TCP dup ACK 的行)。

如果服务端监听socket 的 backlog 值降低了 (比如,从 accept 队列消费了一个连接,因此队列变成未满),而且, SYN/ACK 重试次数没有达到最大值的情况下,那么, tcp 协议栈就可以最终处理 客户端发来的 ack 包, 将连接状态从 SYN RECEIVED 改为

ESTABLISHED, 并将其加入到 accept 队列中。 否则, 客户端最终将会拿到一个 RST 包。(上图标红那行)

5、问题延伸

上面的网络抓包,也展示出另一个有趣的方面。 从客户端的角度来说, 收到 服务端发来的 SYN/ACK 后,一直就处于 ESTABLISHED 状态。 如果它发生数据 (不等待服务端发来的数据,毕竟是全双工), 那么数据同样将会重传。 TCP 慢开始算法,会限制发出的包的数量。 (这里意思是, 慢开始算法下,一开始不会传很多包,可能只传一个,收到服务端的响应后,下一次传2个,再一次传4个,这样指数级增长,直到达到一个值后,进入线性增长阶段,因为服务端一直没响应,就不会增大发送的包的个数,避免浪费网络流量)

另一方面, 如果客户端一直等待服务端发送数据,但是服务端的 backlog 一直没有降低(一直没能 accept 该客户端), 那么最终结果是, 客户端该连接为 ESTABLISHED 状态,在服务端,该连接状态为 CLOSED。

还有一个我们没讨论的问题。 listen 的 man page 上说,每个 SYN 包将会添加到 SYN 队列(除非队列满了)。 这个不完全准确。理由是,在 net/ipv4/tcp_ipv4.c 中的 tcp_v4_conn_request 函数中 (该函数负责 SYN 包的处理):

/* Accept backlog is full. If we have already queued enough

* of warm entries in syn queue, drop request. It is better than

* clogging syn queue with openreqs with exponentially increasing

* timeout.

*/

if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) {

NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);

goto drop;

}

这个意味着,如果 accept 队列满了, 那么内核会隐式限制 SYN 包接收的速度。 如果收到了太多的 SYN 包, 部分会被丢弃。 在这种情况下, 由客户端决定 进行重发,然后我们最终表现就和在 BSD 下的实现一样。

总结下,为什么linux的设计,会比传统的BSD下的实现更为优越。 Stevens老爷子做了如下的观点(这个翻译太崩溃了。。。深奥。。。智商不行了。。。):

队列长度将会达到backlog 限定值,如果全连接队列满了的话(比如,服务器太忙,以至于进程无法足够快地调用 accept 进行处理,好方便从 accept 队列中腾出位置);或者,在半连接队列满了时,队列长度也会达到 backlog。 后者就是http服务器面临的问题,当客户端和服务端之间的往返时间较长时,(相对于什么较长?相对于 新连接的到达速率),因为一个新的 syn 包 会占据队列,长达客户端到服务端之间一次往返的时间。

当一个连接放入全连接队列时,它几乎总是空的, 因为当一个连接放入这个队列时, accept 调用就返回了, 然后 服务器将连接从队列中移除。

4、Stevens老爷子的建议

Stevens老爷子的建议是,增加backlog的值。 假设一个程序,打算对backlog 进行调优,不仅要考虑它怎么处理新建立的连接,也要考虑网络状况,比如客户端到服务器的往返时间。

Linux的实现有效地分离了这两个问题:

程序只需要负责调优 backlog,保证它能够尽快地调用 accept,避免堆满 accept 队列;

系统管理员可以基于 网络状况,对 /proc/sys/net/ipv4/tcp_max_syn_backlog 进行调优。

三、译文的测试验证

文章不太好理解,我查了些资料,参考https://www.cnblogs.com/xrq730/p/6910719.html后,我打算本地也进行一次验证。

主要是通过ss命令、以及wireshark抓包,观察这其中的细节。

1、服务端程序

首先,服务端程序为:

import java.net.ServerSocket;

public class ServerSocketClass {

    public static void main(String[] args) throws Exception {
        ServerSocket server = new ServerSocket(8888, 5);

        while (true) {
            // server.accept();
        }
    }

}

2、客户端程序


/** * desc: * * @author : caokunliang * creat_date: 2019/6/11 0011 * creat_time: 10:16 **/import java.io.OutputStream;import java.net.Socket;import java.util.concurrent.locks.LockSupport;

public class ClientSocketClass {

    private static Socket[] clients = new Socket[30];

    public static void main(String[] args) throws Exception {        for (int i = 0; i < 1; i++) {            Socket socket = null;            socket = new Socket("192.168.19.13", 8888);            System.out.println("Client:" + socket + ", isConnected:" + socket.isConnected());            OutputStream outputStream = socket.getOutputStream();            outputStream.write(‘a‘);        }

        // 阻止程序退出,因为退出的话,程序会直接发送一个 RST 给服务器,不能观察 服务器的 ACK/SYN 重传        LockSupport.park();    }

}
 

值得注意的是,这里,我们每次只发一次请求。

3、客户端请求发送5次,填满 accept 队列

观察下面的图,其中ss命令, 如果该条socket记录为监听端口,则Recv-Q 表示 accept 队列中元素的个数, Send-Q 表示 accept 队列中队列的容量。

Recv-Q

Established: The count of bytes not copied by the user program connected to this socket.

Listening: Since Kernel 2.6.18 this column contains the current syn backlog.

Send-Q

Established: The count of bytes not acknowledged by the remote host.

Listening: Since Kernel 2.6.18 this column contains the maximum size of the syn backlog.

启动服务端程序,初始时,

每次我们执行客户端,这里便会加1。执行两次后:

4、再次发送连接请求

5次后,Recv-Q队列将会变满。如果此时再发送的话,按照参考博客中的说法,是会报错。但我这边没报错,看 wireshark 抓包:首先看服务端发给客户端的包,我们发现, 服务器确实会一直发送 SYN/ACK 给客户端,一共发了5次(即为: /proc/sys/net/ipv4/tcp_synack_retries)。每次时间间隔加一倍。(参考退火算法)

可以看到,服务端一直给客户端发送 SYN/ACK,所以,客户端假设自己发出去的 ACK (三次握手的最后一次) 丢失了。于是会一直重发:

完整的交互如下:

我们发现,这里, 最后服务端会发送一个 RST ,但如果我们把客户端程序改改:

//            OutputStream outputStream = socket.getOutputStream();
//            outputStream.write(‘a‘);

再次请求,进行抓包的话,会发现不会发送 RST 了:

值得注意的是,在这种情况下,在客户端查看连接状态是 ESTABLISHED ,而在服务器端,查不到对应的连接信息。这也就验证了译文中 “问题延伸” 一节的猜想。

客户端:

服务器:

5、测试tcp_abort_on_overflow 参数

上面步骤都是在tcp_abort_on_overflow 为 false的情况下测试的, 这次我们打开后,再用下面程序测试。

sysctl -w net.ipv4.tcp_abort_on_overflow = 1
import java.net.Socket;
import java.util.concurrent.locks.LockSupport;

public class ClientSocketClass {

    private static Socket[] clients = new Socket[30];

    public static void main(String[] args) throws Exception {
        for (int i = 0; i < 15; i++) {
            Socket socket = null;
            socket = new Socket("192.168.19.13", 8888);
            System.out.println("Client:" + socket + ", isConnected:" + socket.isConnected());
        }

        // 阻止程序退出,因为退出的话,程序会直接发送一个 RST 给服务器,不能观察 服务器的 ACK/SYN 重传
        LockSupport.park();
    }

}

我们发起了15次连接,但是我们的 accept 队列为5,按理说只能成功 5 +1 = 6个连接,剩下的9个连接都会无效。tcp_abort_on_overflow 的作用是,在 accept 队列满时,返回 rst。下面测试:

上图可以看出,成功建立的只有6个,剩下的都被服务器返回了 RST 。

5、服务端正常accept时的连接情况

修改程序:将ServerSocketClass.java中的注释行打开,允许服务器调用accept;客户端循环次数改为20,看看服务器上的情况:

 

四、简单总结

backlog:该参数,每个程序可以在listen时自己设置,和另外一个参数( /proc/sys/net/core/somaxconn)一起,影响 全连接队列的容量。 具体算法是:min (backlog, /proc/sys/net/core/somaxconn ),最终可以建立的连接为 该值 + 1。

/proc/sys/net/ipv4/tcp_max_syn_backlog : 半连接队列的容量。(os层面,只能设一个,由所有程序共享)

/proc/sys/net/ipv4/tcp_synack_retries :分两种情况:

  1. tcp_abort_on_overflow = 0,服务端 accept 队列满了,客户端发来 ack , 服务端直接忽略该ack。因此服务端一直处于 SYN RECEIVED,触发了该状态下的定时器,该定时器会重传 SYN/ACK 给客户端,(不超过 /proc/sys/net/ipv4/tcp_synack_retries 指定的次数 ), 超过后,服务端不再重传,后续也不会再有任何动作;如果客户端此时传输数据的话,服务端会返回 RST;
  2. tcp_abort_on_overflow = 1,服务端 accept 队列满了,客户端发来 ack , 服务端直接返回 RST 。

ps: 查看、修改这些参数的简单方法:

#查看所有系统变量并查找
[[email protected] ~]# sysctl -a |grep somaxconn
net.core.somaxconn = 128

# 设置系统变量
[[email protected] ~]# sysctl -w net.core.somaxconn=129
net.core.somaxconn = 129

五、 Tomcat 、nginx、redis中如何设置 backlog

1、tomcat

在tomcat 中, backlog 参数定义在org.apache.tomcat.util.net.AbstractEndpoint#backlog中,默认值为100。

    /**
     * Allows the server developer to specify the backlog that
     * should be used for server sockets. By default, this value
     * is 100.
     */
    private int backlog = 100;
    public void setBacklog(int backlog) { if (backlog > 0) this.backlog = backlog; }

但是在实际处理中, 会由 Digester 框架,去解析 server.xml,解析到 connector 时, 首先新建 org.apache.catalina.connector.Connector,

然后开始设置属性值:

当设置 acceptCount 时, 会调用 org.apache.catalina.connector.Connector#setProperty:

我们可以看看 replacements的定义:

     protected static HashMap<String,String> replacements =
         new HashMap<String,String>();
     static {
         replacements.put("acceptCount", "backlog");
         replacements.put("connectionLinger", "soLinger");
         replacements.put("connectionTimeout", "soTimeout");
         replacements.put("rootFile", "rootfile");
     }

所以,其实 connector 中 acceptCount 最终是 backlog 的值。

2、nginx

server{
        listen      8080  default_server backlog=1024;
}

3、redis

修改redis.conf

# TCP listen() backlog.
#
# In high requests-per-second environments you need an high backlog in order
# to avoid slow clients connections issues. Note that the Linux kernel
# will silently truncate it to the value of /proc/sys/net/core/somaxconn so
# make sure to raise both the value of somaxconn and tcp_max_syn_backlog
# in order to get the desired effect.
tcp-backlog 511

原文地址:https://www.cnblogs.com/grey-wolf/p/10999342.html

时间: 2024-10-06 05:51:13

Linux中,Tomcat 怎么承载高并发(深入Tcp参数 backlog)的相关文章

Linux中tomcat开机启动配置脚本【参考其他文章的总结备忘录】

参考文章http://blog.sina.com.cn/s/blog_a57562c80101ic47.html http://blog.csdn.net/cheng168520/article/details/4312828 http://blog.sina.com.cn/s/blog_7f395ece0100ti5y.html 以前在自己本机上安装过一个Linux,后台应为系统崩溃,以前配置的开机启动脚本.数据库主从双备份.负载均衡等都没了,所以现在在重新配置一次,赶紧做个笔记防止自己以后又

linux中tomcat内存溢出解决办法

用命令 tail -f /root/apache-tomcat-6.0.20/logs/catalina.out(需要找到tomcat路径) 查看日志,查看是否有错误 linux中tomcat内存溢出解决办法 常见的一般会有下面三种情况:1.OutOfMemoryError: Java heap space2.OutOfMemoryError: PermGen space3.OutOfMemoryError: unable to create new native thread.前两种通常一起进

面试常问问题:银行网上支付项目中怎么控制多线程高并发访问?

面试常问问题:银行网上支付项目中怎么控制多线程高并发访问? synchronized关键字主要解决多线程共享数据同步问题. ThreadLocal使用场合主要解决多线程中数据因并发产生不一致问题. ThreadLocal和Synchonized都用于解决多线程并发访问.但是ThreadLocal与synchronized有本质的区别: synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问.而ThreadLocal为每一个线程都提供了变量的副本,使 得每个线程在某一时

Linux下基于Erlang的高并发TCP连接压力实验

[题解整理]二分题 题目类型: 二分查找: 二分答案. 大致解题思路: 查找注意有序和返回值: 浮点数注意精度: 整数注意返回值,建议另外维护一个变量,用于储存可行解. 题目 分类 传送门 WA点 poj 2785 二分查找 题解 lightoj 1088 二分查找 题解 lightoj 1307 二分查找 题解 longlong poj 2456 整数二分答案 题解 poj 3104 整数二分答案 题解 poj 3258 整数二分答案 题解 poj 3273 整数二分答案 题解 lightoj

基于tomcat为了应对高并发模型实现webserver

在博客上,一个简单的AIOweb来样加工.查看AIO异步处理,依靠操作系统完成IO操作Proactor处理模型确实很强大,它可以实现高并发.高响应server一个很好的选择,但在tomcat中间connector理模型还依然是基于NIO的处理.当然,我觉得这可能会在以后的版本号进行改进,但还有一方面,我更觉得AIO的负载控制方面的处理可能是比較难的,由于AIO api并没有提供我们对分配线程组的处理.而仅仅是提供一个线程组,交给操作系统去解决io处理上的问题,所以,这可能会给须要复杂处理的负载均

Linux中tomcat

Tomcat服务器是一个免费的开放源代码的Web应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP程序的首选. Tomcat和Nginx.Apache(httpd).lighttpd等Web服务器一样,具有处理HTML页面的功能,另外它还是一个Servlet和JSP容器,独立的Servlet容器是Tomcat的默认模式.不过, Tomcat处理静态HTML的能力不如Nginx/Apache服务器. 目前Tomcat最新版本为9.0.Java

使用Visual VM 查看linux中tomcat运行时JVM内存

前言:在生产环境中经常发生服务器内存溢出,假死或者线程死锁等异常,导致服务不可用.我们经常使用的解决方法是通过分析错误日记,然后去寻找代码到底哪里出现了问题,这样的方式也许会奏效,但是排查起来耗费时间比较多,或者说本身代码本身就没有错,而是访问量大时候消耗内存太多,垃圾对象没有及时回收等等其他情况导致的,这样排查异常起来异常困难,那么有没有一些可视化的工具,帮助我们可以详细地查看当前应用服务的内存情况,从而为我们在解决异常.优化代码.优化服务等方面提供一些建议呢?幸好,jdk为我们免费提供一个这

linux中tomcat安装

步骤: 1)上传Tomcat到linux上 2)解压Tomcat到/usr/local下 3)开放Linux的对外访问的端口8080 /sbin/iptables -I INPUT -p tcp --dport 8080 -j ACCEPT /etc/rc.d/init.d/iptables save 4)启动关闭Tomcat 进入tomcat的bin下启动:./startup.sh 进入tomcat的bin下关闭:./shutdown.sh

Linux中tomcat随服务器自启动的设置方法

1. cd到rc.local文件所在目录,一般在 /etc/rc.d/目录. 2. 将rc.local下载到本地windows系统中. 3. 编辑rc.local,将要启动的tomcat  /bin/目录下的startup.sh文件的路径添加进入rc.d 中 touch xxxxx 行的下面即可,如下所示. 原文地址:https://www.cnblogs.com/zhcBlog/p/10078324.html