[Technical Application] Springboot built-in tomcat configures unix domain socket attributes

I. Introduction

Recently, I have summarized a lot of unix domain socketapplications of **UNIX Domain Socket Protocol ( )** in work, but there is one component that is most used in work and supports UNIX DOMAIN SOCKET协议application examples that have not been summarized, that is: tomcat supports UNIX domain sockets. Application examples of word protocol (unix domain socket) , summarized today;

Examples of previous applications of the UNIX domain socket protocol in components:

1. [Technical application] Java connects to redis based on UNIX domain socket (unix domain socket)

2. [Technical application] Java connects to postgresql database based on UNIX domain socket (unix domain socket)

3. [Technical application] Java connects to mysql database based on UNIX domain socket (unix domain socket)

2. Springboot has built-in tomcat

1. Springboot supports the built-in functions of tomcat. The project can be directly compiled into a jar package and run. Tomcat can be compiled into the jar, which simplifies the application. This is also a major feature of springboot;

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

2. The configuration item attributes of springboot’s built-in tomcat are usually application.yml配置文件set in, as follows:

server:
  tomcat:
    accept-count: 80 #挂起的请求队列最大连接数,默认100
    max-connections: 2000  #最大连接数,默认10000,tomcat内tcp连接池的大小
    max-threads: 200 #最大线程数,默认200,超过加入等待队列,默认是100,当等待队列达到100后,直接拒绝此次请求返回connection refused。连接超时时间默认为20秒
    min-spare-threads: 5  #最小工作线程数
    connection-timeout: 60000  #server端的socket超时间,默认60s
    accesslog:
      enabled: true #启动tomcat访问日志

However, after analyzing all configuration items, no unixdomainsocketrelevant configuration information was found, so apllication.yml配置文件the unixdomainsocket function cannot be implemented;

3. Configure the built-in tocmat property through code in springboot;

1) Configure the port of the Servlet container to 9000

import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import
org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.stereotype.Component;
@Component
public class MyWebServerFactoryCustomizer implements
WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
    
    
  @Override
  public void customize(ConfigurableServletWebServerFactory server) {
    
    
  server.setPort(9000);
  }
}

2) Use ConfigurableServletWebServerFactorysubclasses (for example TomcatServletWebServerFactory) to configure the Servlet container

import java.time.Duration;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.stereotype.Component;
@Component
public class MyTomcatWebServerFactoryCustomizer implements
WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
    
    
  @Override
  public void customize(TomcatServletWebServerFactory server) {
    
    
  server.addConnectorCustomizers((connector) ->
connector.setAsyncTimeout(Duration.ofSeconds(20).toMillis()));
  }
}

3. Analysis of tomcat’s support for unix domain socket protocol

1. The composition of tomcat can be divided into two parts: 连接器and 容器
connector : specifically used to deal with issues related to network connections, such as Socket links in web development, request encapsulation, connection thread pools, etc.
Container (servlet) : used to store the website programs we write. Tomcat has four containers in total: Engine, Host, Context and Wrapper. A Wrapper corresponds to a Servlet, a Context corresponds to an application (for example, by default, the main application stored in webapps/ROOT corresponds to the root directory of a site), a Host corresponds to a site (for example, different domain names), and Engine is the engine .

2. The protocols responsible for processing requests in the connector are mainly based on bio,nio,nio2,aprseveral different http protocols, and 支持NIO协议the attribute settings support unixdomainsocket属性configuration;

pollerThreadPriority:(int)The priority of the poller threads
selectorTimeout:(int)The time in milliseconds to timeout on a select() for the poller
useSendfile:(bool)Use this attribute to enable or disable sendfile capability
socket.directBuffer:(bool)Boolean value, whether to use direct ByteBuffers or java mapped ByteBuffers
 
socket.directSslBuffer:(bool)Boolean value, whether to use direct ByteBuffers or java mapped ByteBuffers for the SSL buffers
socket.appReadBufSize:(int)Each connection that is opened up in Tomcat get associated with a read ByteBuffer
socket.appWriteBufSize:(int)Each connection that is opened up in Tomcat get associated with a write ByteBuffer
socket.bufferPool:(int)The NIOx connector uses a class called NioXChannel that holds elements linked to a socket
socket.bufferPoolSize:(int)The NioXChannel pool can also be size based, not used object based
 
socket.processorCache:(int)Tomcat will cache SocketProcessor objects to reduce garbage collection
socket.eventCache:(int)Tomcat will cache PollerEvent objects to reduce garbage collection
 
unixDomainSocketPath:Where supported, the path to a Unix Domain Socket that this Connector will create and await incoming connections
unixDomainSocketPathPermissions:Where supported, the posix permissions that will be applied to the to the Unix Domain Socket specified with unixDomainSocketPath above
useInheritedChannel:(bool)Defines if this connector should inherit an inetd/systemd network socket

Therefore, we only need to set the unixDomainSocketPath attribute;

4. Springboot built-in tomcat uses unixdomainsocket protocol example

1. jdk version
When using the built-in tomcat of springboot, the dependent jdk is used 最低版本是jdk16, because Unix sockets are only supported starting from jdk16;
in 2019 Windows Server and Windows 10 provide support for Unix sockets, and Unix sockets are commonly used Communication between local processes. Compared with the TCP protocol, local processes can communicate more efficiently and securely using Unix sockets. JDK16 adds a new interface for Unix sockets java.net.UnixDomainSocketAddressto support this feature

If the jdk version is lower than 16, an error will be reported:

Caused by: java.lang.UnsupportedOperationException: Java Runtime does not support Unix domain sockets. You must use Java 16 to use this feature.
	at org.apache.tomcat.util.compat.JreCompat.openUnixDomainServerSocketChannel(JreCompat.java:337) ~[tomcat-embed-core-9.0.70.jar:9.0.70]
	at org.apache.tomcat.util.net.NioEndpoint.initServerSocket(NioEndpoint.java:252) ~[tomcat-embed-core-9.0.70.jar:9.0.70]
	at org.apache.tomcat.util.net.NioEndpoint.bind(NioEndpoint.java:230) ~[tomcat-embed-core-9.0.70.jar:9.0.70]
	at org.apache.tomcat.util.net.AbstractEndpoint.bindWithCleanup(AbstractEndpoint.java:1227) ~[tomcat-embed-core-9.0.70.jar:9.0.70]
	at org.apache.tomcat.util.net.AbstractEndpoint.init(AbstractEndpoint.java:1240) ~[tomcat-embed-core-9.0.70.jar:9.0.70]
	at org.apache.coyote.AbstractProtocol.init(AbstractProtocol.java:604) ~[tomcat-embed-core-9.0.70.jar:9.0.70]
	at org.apache.coyote.http11.AbstractHttp11Protocol.init(AbstractHttp11Protocol.java:76) ~[tomcat-embed-core-9.0.70.jar:9.0.70]
	at org.apache.catalina.connector.Connector.initInternal(Connector.java:1047) ~[tomcat-embed-core-9.0.70.jar:9.0.70]
	... 21 common frames omitted

So we use jdk19

<properties>
        <java.version>19</java.version>
    </properties>

2. Springboot built-in tomcat attribute configuration

springboot built-in tomcat configuration unix domain socket protocol is very simple, just need to setconnector.setProperty("unixDomainSocketPath","D:\\http.sock")

package com.example.tomcat19.config;

import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Configuration;


@Configuration
public class MyTomcatWebServerFactoryCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
    
    

    @Override
    public void customize(TomcatServletWebServerFactory server) {
    
    
        server.addConnectorCustomizers((connector) -> {
    
    
                    //connector.setAsyncTimeout(Duration.ofSeconds(20).toMillis());
                    //connector.setProperty("protocol","org.apache.coyote.http11.Http11NioProtocol");
                    connector.setProperty("unixDomainSocketPath","D:\\http.sock");
                }
        );
    }
}

3. Server-side test interface

package com.example.tomcat19.action;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
public class TestAction {
    
    

    @GetMapping("/test")
    public String test(){
    
    
        log.info("收到请求id:1");
        return "哈哈哈";
    }

}

Server project structure:
Insert image description here

4. Request client

In order to facilitate verification, we use here socketbased on http.socksending http request messages to the server

package com.sk.init;

import java.net.StandardProtocolFamily;
import java.net.UnixDomainSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public class Test {
    
    

    public static void main(String[] args) throws Exception{
    
    
        // 建立 Unix Socket 连接
        //File sockFile = new File("D:\\http.sock");
        SocketChannel socketChannel = SocketChannel.open(StandardProtocolFamily.UNIX);

        UnixDomainSocketAddress of = UnixDomainSocketAddress.of("D:\\http.sock");
        //UnixDomainSocketAddress of = UnixDomainSocketAddress.of("D:\\test.sock");
        boolean connect = socketChannel.connect(of);
        System.out.println(connect);

        String newData = "this is domain socket..." + System.currentTimeMillis();
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("GET /test HTTP/1.1").append("\n");
       
        stringBuffer.append("Host: 127.0.0.1").append("\r\n");
        stringBuffer.append("Connection: keep-alive").append("\r\n");
        stringBuffer.append("Cache-Control: max-age=0").append("\r\n");
        stringBuffer.append("sec-ch-ua: \" Not A;Brand\";v=\"99\", \"Chromium\";v=\"100\", \"Google Chrome\";v=\"100\"").append("\r\n");
        stringBuffer.append("sec-ch-ua-mobile: ?0").append("\r\n");
        stringBuffer.append("sec-ch-ua-platform: \"Windows\"").append("\r\n");
        stringBuffer.append("Upgrade-Insecure-Requests: 1").append("\r\n");
        stringBuffer.append("User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36").append("\r\n");
        stringBuffer.append("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9").append("\r\n");
        stringBuffer.append("Sec-Fetch-Site: none").append("\r\n");
        stringBuffer.append("Sec-Fetch-Mode: navigate").append("\r\n");
        stringBuffer.append("Sec-Fetch-User: ?1").append("\r\n");
        stringBuffer.append("Sec-Fetch-Dest: document").append("\r\n");
        stringBuffer.append("Accept-Encoding: gzip, deflate, br").append("\r\n");
        stringBuffer.append("Accept-Language: zh-CN,zh;q=0.9").append("\r\n");
        stringBuffer.append("\r\n");

        //stringBuffer.append("Accept: */*").append("\r\n");
        ByteBuffer buf = ByteBuffer.allocate(2048);
        buf.clear();
        buf.put(stringBuffer.toString().getBytes());
        //buf.put(newData.getBytes());
        buf.flip();
        while (buf.hasRemaining()) {
    
    
            socketChannel.write(buf);
        }
        socketChannel.close();
    }

}

5. Request results

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::       (v3.0.2-SNAPSHOT)

23:06:54.720 [main] INFO  org.springframework.boot.StartupInfoLogger.logStarting(StartupInfoLogger.java:51) - Starting Tomcat19Application using Java 19.0.1 with PID 6248 (G:\work3\UDS redis\tomcat19\target\classes started by Administrator in G:\work3\UDS redis\tomcat19)
23:06:54.962 [main] INFO  org.springframework.boot.SpringApplication.logStartupProfileInfo(SpringApplication.java:630) - No active profile set, falling back to 1 default profile: "default"
23:06:55.895 [main] INFO  org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:108) - Tomcat initialized with port(s): 8086 (http)
23:06:55.905 [main] INFO  org.apache.juli.logging.DirectJDKLog.log(DirectJDKLog.java:173) - Initializing ProtocolHandler ["http-nio-D:\\http.sock"]
23:06:55.906 [main] INFO  org.apache.juli.logging.DirectJDKLog.log(DirectJDKLog.java:173) - Starting service [Tomcat]
23:06:55.906 [main] INFO  org.apache.juli.logging.DirectJDKLog.log(DirectJDKLog.java:173) - Starting Servlet engine: [Apache Tomcat/10.1.4]
23:06:55.996 [main] INFO  org.apache.juli.logging.DirectJDKLog.log(DirectJDKLog.java:173) - Initializing Spring embedded WebApplicationContext
23:06:55.996 [main] INFO  org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.prepareWebApplicationContext(ServletWebServerApplicationContext.java:291) - Root WebApplicationContext: initialization completed in 991 ms
23:06:56.344 [main] INFO  org.apache.juli.logging.DirectJDKLog.log(DirectJDKLog.java:173) - Starting ProtocolHandler ["http-nio-D:\\http.sock"]
23:06:56.364 [main] INFO  org.springframework.boot.web.embedded.tomcat.TomcatWebServer.start(TomcatWebServer.java:220) - Tomcat started on port(s): -1 (http) with context path ''
23:06:56.374 [main] INFO  org.springframework.boot.StartupInfoLogger.logStarted(StartupInfoLogger.java:57) - Started Tomcat19Application in 2.287 seconds (process running for 4.057)
23:07:12.012 [http-nio-D:\\http.sock-exec-1] INFO  org.apache.juli.logging.DirectJDKLog.log(DirectJDKLog.java:173) - Initializing Spring DispatcherServlet 'dispatcherServlet'
23:07:12.032 [http-nio-D:\\http.sock-exec-1] INFO  org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:532) - Initializing Servlet 'dispatcherServlet'
23:07:12.033 [http-nio-D:\\http.sock-exec-1] INFO  org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:554) - Completed initialization in 1 ms
23:07:12.062 [http-nio-D:\\http.sock-exec-1] INFO  com.example.tomcat19.action.TestAction.test(TestAction.java:13) - 收到请求id:1

Five, springboot external tomcat configuration unixdomainsocket

<Service name="CatalinaLocal">
        <Connector
            protocol="org.apache.coyote.http11.Http11AprProtocol"
            unixDomainSocketPath="/opt/app-name/http.sock" />
        <Engine
            defaultHost="localhost"
            name="Catalina">
            <Host
                name="localhost"
                appBase="webapps"
                unpackWARs="true"
                autoDeploy="false"
                deployIgnore="(?!.*hawtio).*">
                <Valve
                    className="org.apache.catalina.valves.RemoteIpValve" />
            </Host>
        </Engine>
    </Service>

Note: The configuration here has not been verified, and those who are interested can test it

6. Summary

unix域套接字协议It is still very useful, especially when it comes to performance optimization. Many major manufacturers’ microservice architectures support the Unix Domain Socket Protocol;

=If the article is helpful to you, please like and collect it=====================

Guess you like

Origin blog.csdn.net/weixin_37598243/article/details/128488839