add option to enable compression for gRPC-server (#133)

* add grpc server compression

* change compression config defaults

* fix review issue

* add note about compression in readme

* add compression section to server config doc
This commit is contained in:
Vadim Vlasov
2023-02-10 17:27:52 +08:00
committed by GitHub
parent fc36e63ea6
commit 8649cc03aa
7 changed files with 116 additions and 2 deletions

View File

@@ -59,6 +59,11 @@ port: 2449
tls: tls:
enabled: false enabled: false
compression:
grpc:
server:
enabled: false
proxy: proxy:
host: 0.0.0.0 host: 0.0.0.0
port: 8545 port: 8545
@@ -103,6 +108,7 @@ Which sets the following:
- gRPC access through 0.0.0.0:2449 - gRPC access through 0.0.0.0:2449
** TLS security is disabled (_please don't use in production!_) ** TLS security is disabled (_please don't use in production!_)
** compression is disabled for gRPC server (enabled by default)
- JSON RPC access through 0.0.0.0:8545 (both HTTP and WebsScket) - JSON RPC access through 0.0.0.0:8545 (both HTTP and WebsScket)
** proxy requests to Ethereum and Kovan upstreams ** proxy requests to Ethereum and Kovan upstreams
** request path for Ethereum Mainnet is `/eth`, `/kovan` for Kovan Testnet, and `/btc` for bitcoin ** request path for Ethereum Mainnet is `/eth`, `/kovan` for Kovan Testnet, and `/btc` for bitcoin

View File

@@ -21,6 +21,12 @@ tls:
client: client:
require: true require: true
ca: "ca.crt" ca: "ca.crt"
compression:
grpc:
server:
enabled: false
cluster: cluster:
include: "upstreams.yaml" include: "upstreams.yaml"
---- ----
@@ -29,6 +35,7 @@ It configures following:
- server is listening with gRCP API on `0.0.0.0:2449` - server is listening with gRCP API on `0.0.0.0:2449`
- TLS is enabled - TLS is enabled
- compression is disabled for gRPC server (enabled by default)
- server certificate is located at `server.crt` with the key for it at `server.p8.key` - server certificate is located at `server.crt` with the key for it at `server.p8.key`
- the server requires a client authentication by TLS client certificate signed by `ca.crt` certificate - the server requires a client authentication by TLS client certificate signed by `ca.crt` certificate
- no JSON RPC is configured - no JSON RPC is configured
@@ -51,6 +58,10 @@ a| `tls`
| TLS configuration for gRPC. | TLS configuration for gRPC.
See link:08-authentication.adoc[Authentication] for details See link:08-authentication.adoc[Authentication] for details
a| `compression`
|
| Compression configuration
a| `proxy` a| `proxy`
| |
| Proxy configuration | Proxy configuration
@@ -60,6 +71,21 @@ a| `upstreams`
| Upstreams configuration | Upstreams configuration
|=== |===
=== Compression
Compression is enabled by default on the gRPC server
(the server accepts compressed requests and can send compressed responses).
Responses will be compressed if a client supports compression (sends relevant headers),
otherwise, communication will be uncompressed.
But if for some reason you need to disable compression forcibly,
add the lines below to the config:
[source,yaml]
----
compression:
grpc:
client:
enabled: false
----
=== Enabling JSON RPC proxy === Enabling JSON RPC proxy
In addition to the gRPC protocol, Dshackle provides access compatible with Bitcoin and Ethereum JSON RPC. In addition to the gRPC protocol, Dshackle provides access compatible with Bitcoin and Ethereum JSON RPC.

View File

@@ -18,7 +18,11 @@ package io.emeraldpay.dshackle
import io.emeraldpay.dshackle.config.MainConfig import io.emeraldpay.dshackle.config.MainConfig
import io.emeraldpay.dshackle.monitoring.accesslog.AccessHandlerGrpc import io.emeraldpay.dshackle.monitoring.accesslog.AccessHandlerGrpc
import io.grpc.Codec
import io.grpc.Server import io.grpc.Server
import io.grpc.ServerCall
import io.grpc.ServerCallHandler
import io.grpc.ServerInterceptor
import io.grpc.netty.NettyServerBuilder import io.grpc.netty.NettyServerBuilder
import io.micrometer.core.instrument.Metrics import io.micrometer.core.instrument.Metrics
import io.micrometer.core.instrument.binder.jvm.ExecutorServiceMetrics import io.micrometer.core.instrument.binder.jvm.ExecutorServiceMetrics
@@ -42,6 +46,17 @@ open class GrpcServer(
private var server: Server? = null private var server: Server? = null
class CompressionInterceptor : ServerInterceptor {
override fun <ReqT : Any, RespT : Any> interceptCall(
call: ServerCall<ReqT, RespT>,
headers: io.grpc.Metadata,
next: ServerCallHandler<ReqT, RespT>
): ServerCall.Listener<ReqT> {
call.setCompression(Codec.Gzip().messageEncoding)
return next.startCall(call, headers)
}
}
@PostConstruct @PostConstruct
fun start() { fun start() {
log.info("Starting gRPC Server...") log.info("Starting gRPC Server...")
@@ -53,9 +68,12 @@ open class GrpcServer(
.let { .let {
if (mainConfig.accessLogConfig.enabled) { if (mainConfig.accessLogConfig.enabled) {
it.intercept(accessHandler) it.intercept(accessHandler)
} else {
it
} }
if (mainConfig.compression.grpc.serverEnabled) {
it.intercept(CompressionInterceptor())
log.info("Compression enabled for gRPC server")
}
it
} }
tlsSetup.setupServer("Native gRPC", mainConfig.tls, true)?.let { tlsSetup.setupServer("Native gRPC", mainConfig.tls, true)?.let {

View File

@@ -0,0 +1,27 @@
package io.emeraldpay.dshackle.config
class CompressionConfig(
var grpc: GRPC = GRPC()
) {
/**
* Config example:
* ```
* compression:
* grpc:
* server:
* enabled: true
* client:
* enabled: false
* ```
*/
class GRPC(
var serverEnabled: Boolean = true,
var clientEnabled: Boolean = true
)
companion object {
fun default(): CompressionConfig {
return CompressionConfig()
}
}
}

View File

@@ -0,0 +1,32 @@
package io.emeraldpay.dshackle.config
import org.yaml.snakeyaml.nodes.MappingNode
import java.io.InputStream
class CompressionConfigReader : YamlConfigReader(), ConfigReader<CompressionConfig> {
fun read(input: InputStream): CompressionConfig? {
val configNode = readNode(input)
return read(configNode)
}
override fun read(input: MappingNode?): CompressionConfig {
val config = CompressionConfig()
getMapping(input, "compression")?.let { node ->
readGRPC(config.grpc, getMapping(node, "grpc"))
}
return config
}
private fun readGRPC(grpcCompressionConfig: CompressionConfig.GRPC, input: MappingNode?) {
getMapping(input, "server")?.let { serverNode ->
getValueAsBool(serverNode, "enabled")?.let {
grpcCompressionConfig.serverEnabled = it
}
}
getMapping(input, "client")?.let { clientNode ->
getValueAsBool(clientNode, "enabled")?.let {
grpcCompressionConfig.clientEnabled = it
}
}
}
}

View File

@@ -28,4 +28,5 @@ class MainConfig {
var accessLogConfig: AccessLogConfig = AccessLogConfig.default() var accessLogConfig: AccessLogConfig = AccessLogConfig.default()
var health: HealthConfig = HealthConfig.default() var health: HealthConfig = HealthConfig.default()
var signature: SignatureConfig? = null var signature: SignatureConfig? = null
var compression: CompressionConfig = CompressionConfig.default()
} }

View File

@@ -37,6 +37,7 @@ class MainConfigReader(
private val accessLogReader = AccessLogReader() private val accessLogReader = AccessLogReader()
private val healthConfigReader = HealthConfigReader() private val healthConfigReader = HealthConfigReader()
private val signatureConfigReader = SignatureConfigReader(fileResolver) private val signatureConfigReader = SignatureConfigReader(fileResolver)
private val compressionConfigReader = CompressionConfigReader()
fun read(input: InputStream): MainConfig? { fun read(input: InputStream): MainConfig? {
val configNode = readNode(input) val configNode = readNode(input)
@@ -83,6 +84,9 @@ class MainConfigReader(
signatureConfigReader.read(input).let { signatureConfigReader.read(input).let {
config.signature = it config.signature = it
} }
compressionConfigReader.read(input).let {
config.compression = it
}
return config return config
} }
} }