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:
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user