[Technical Application] Java connects to redis based on UNIX domain socket unix domain socket
I. Introduction
Recently, I have summarized a lot of unix domain socket
applications 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. 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 unixdomainsocket
relevant 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 ConfigurableServletWebServerFactory
subclasses (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,apr
several 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.UnixDomainSocketAddress
to 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:
4. Request client
In order to facilitate verification, we use here socket
based on http.sock
sending 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=====================