Service-to-Service Communication in KCloud-Platform-IoT: HTTP vs gRPC Implementation Guide
KCloud-Platform-IoT employs a hybrid communication strategy that exposes public APIs via HTTP/REST while routing internal high-throughput traffic through gRPC binary protocols integrated with Nacos service discovery.
The KCloud-Platform-IoT repository implements a sophisticated dual-protocol architecture that enables microservices to communicate efficiently across distributed IoT environments. Understanding the specific implementation patterns for HTTP REST endpoints versus gRPC binary channels is critical for optimizing performance in this Spring-based ecosystem. This article examines the source code structure, configuration mechanisms, and service discovery integration that power inter-service communication throughout the platform.
HTTP REST Implementation with Spring MVC
The platform exposes external-facing APIs through standard Spring MVC controllers using text-based JSON payloads. These endpoints follow conventional REST patterns without built-in service discovery mechanisms.
Transport and Protocol
HTTP communication relies on Spring MVC over TCP ports (typically 80 or 8080), utilizing the standard server.port configuration in application.yml. Controllers are annotated with @RestController and handle JSON serialization through Jackson automatically.
Service Discovery Limitations
Unlike the gRPC implementation, HTTP services do not leverage automatic service discovery. Services must be addressed via hard-coded URLs or environment-based host/port values, making this approach suitable for edge-facing APIs rather than internal mesh communication.
Key Implementation Files
Standard REST controllers reside in service-specific web packages, such as laokou-service/laokou-iot/laokou-iot-adapter/src/main/java/org/laokou/iot/web/DevicesController.java, which exposes device management endpoints to external consumers.
gRPC Binary Communication Architecture
For internal service-to-service calls requiring low latency and high throughput, KCloud-Platform-IoT implements gRPC over HTTP/2 using Protocol Buffers for strongly typed, compact message serialization.
Core Components
The gRPC stack utilizes the Spring gRPC starter (version 1.0.2) and Netty as the underlying transport. Server implementations extend generated stub classes from *.proto definitions, while clients inject proxies using the @GrpcClient annotation.
Server-Side Implementation
gRPC services are exposed through classes annotated with @GrpcService. For example, GrpcServerService.java demonstrates the pattern where services extend generated base classes (e.g., SimpleGrpc.SimpleImplBase) and implement RPC methods using StreamObserver for response handling.
Configuration Properties
The gRPC server listens on a dedicated port configured via spring.grpc.server.port (defaulting to 9090). To avoid port conflicts with the HTTP server, the configuration typically sets spring.grpc.server.servlet.enabled: false and assigns a specific Netty port (e.g., 10111) as documented in archive/docs/00.二开指南/02.指南/19.gRPC配置.md.
Nacos Service Discovery Integration
The gRPC implementation features tight integration with Nacos for dynamic service resolution, eliminating the need for hard-coded endpoint addresses.
DiscoveryNameResolver Mechanism
When the application starts, GrpcClientConfig.java registers a DiscoveryNameResolverProvider with the gRPC name resolver registry. This provider intercepts logical service names formatted as discovery://laokou-auth and queries Nacos for physical addresses.
Metadata-Driven Port Resolution
Each gRPC server registers with Nacos including a custom metadata entry grpc_port. The DiscoveryNameResolver.java class extracts this metadata to construct the complete socket address, enabling clients to resolve services without knowing the specific port numbers beforehand.
Channel Factory Creation
The DiscoveryGrpcChannelFactory.java creates Netty channels using the resolved addresses, applying any configured ClientInterceptors and GrpcChannelBuilderCustomizer implementations for TLS or retry policies.
Client-Side Injection Pattern
Developers consume gRPC services through dependency injection managed by GrpcClientBeanPostProcessor.java.
Annotation-Based Stub Injection
Fields annotated with @GrpcClient(serviceId = "laokou-common-grpc") trigger the post-processor to create concrete blocking or async stubs. The processor resolves the service ID through the discovery mechanism and constructs the channel using the factory beans defined in GrpcClientConfig.java.
@Service
public class GreetingClient {
@GrpcClient(serviceId = "laokou-common-grpc")
private SimpleGrpc.SimpleBlockingStub helloStub;
public String greet(String name) {
var req = HelloWorldProto.Request.newBuilder().setName(name).build();
var resp = helloStub.hello(req);
return resp.getMessage();
}
}
Performance and Use Case Comparison
The platform deliberately separates traffic based on consumption patterns and performance requirements.
HTTP/JSON Characteristics
- Latency: Higher due to text-based JSON parsing and HTTP/1.1 framing overhead
- Payload Size: Larger text representations increase network bandwidth
- Tooling: Standard Swagger integration for API documentation and browser compatibility
- Use Cases: Public APIs, UI-oriented services, and simple CRUD operations exposed to external clients
gRPC/Protobuf Characteristics
- Latency: Lower through binary serialization and HTTP/2 multiplexing
- Flow Control: Built-in backpressure management via HTTP/2 windowing
- Type Safety: Strongly typed contracts via Protocol Buffer definitions
- Use Cases: High-throughput internal calls such as distributed ID generation, real-time telemetry ingestion, and inter-service orchestration requiring sub-millisecond response times
Configuration Examples
HTTP Server Configuration
server:
port: 8080
gRPC Server Configuration
spring:
grpc:
server:
port: 9090
servlet:
enabled: false
gRPC Service Implementation
@GrpcService
public class HelloWorldService extends SimpleGrpc.SimpleImplBase {
@Override
public void hello(HelloWorldProto.Request request,
StreamObserver<HelloWorldProto.Response> responseObserver) {
responseObserver.onNext(
HelloWorldProto.Response.newBuilder()
.setMessage("Hello, " + request.getName())
.build());
responseObserver.onCompleted();
}
}
Discovery Configuration
@Configuration(proxyBeanMethods = false)
public class GrpcClientConfig {
@Bean
GrpcClientBeanPostProcessor grpcClientBeanPostProcessor(
GrpcClientFactory factory,
DiscoveryClient discoveryClient,
ExecutorService executor) {
NameResolverRegistry.getDefaultRegistry()
.register(new DiscoveryNameResolverProvider(discoveryClient, executor));
return new GrpcClientBeanPostProcessor(factory);
}
@Bean
DiscoveryGrpcChannelFactory discoveryGrpcChannelFactory(
List<GrpcChannelBuilderCustomizer<NettyChannelBuilder>> customizers,
ClientInterceptorsConfigurer interceptors) {
return new DiscoveryGrpcChannelFactory(customizers, interceptors);
}
}
Summary
- KCloud-Platform-IoT implements a dual-protocol architecture using HTTP for external APIs and gRPC for internal service mesh communication.
- HTTP endpoints reside in standard Spring MVC controllers (
*Controller.java) without automatic service discovery, relying on explicit URL configuration. - gRPC services use
@GrpcServiceannotated classes with Protocol Buffer contracts, listening on dedicated ports (default 9090 or custom 10111) via Netty. - Nacos integration enables dynamic service resolution through
DiscoveryNameResolver.java, which extractsgrpc_portmetadata to route requests to the correct endpoint. - Client injection relies on
@GrpcClientannotations processed byGrpcClientBeanPostProcessor.javato create type-safe stubs bound to logical service names likediscovery://laokou-auth. - The architecture optimizes for both developer experience (HTTP/JSON for external integration) and runtime performance (gRPC binary for internal high-throughput scenarios).
Frequently Asked Questions
When should I use HTTP versus gRPC for service-to-service communication in KCloud-Platform-IoT?
Use HTTP REST when exposing APIs to external clients, browser-based UIs, or third-party integrations where human-readable JSON and standard HTTP tooling are required. Use gRPC for internal microservice calls requiring high throughput, low latency, or strongly typed contracts—particularly for IoT device telemetry processing and distributed transaction coordination.
How does gRPC service discovery work with Nacos in this platform?
The DiscoveryNameResolverProvider registers a custom resolver that intercepts URLs prefixed with discovery://. When a client requests a connection to discovery://laokou-auth, the DiscoveryNameResolver queries Nacos for instances of that service, extracts the grpc_port from each instance's metadata, and returns the socket addresses to the gRPC channel builder.
What ports are typically used in KCloud-Platform-IoT for HTTP and gRPC services?
HTTP services typically use port 8080 (configured via server.port), while gRPC servers default to port 9090 (via spring.grpc.server.port). For dedicated Netty deployment without servlet container interference, the platform often configures port 10111 with spring.grpc.server.servlet.enabled: false.
How do I implement a gRPC client in my Spring service?
Annotate a field with @GrpcClient(serviceId = "target-service-name") where the service ID matches the Nacos-registered name. Ensure your configuration class imports GrpcClientConfig.java to register the discovery resolver. The GrpcClientBeanPostProcessor automatically creates and injects a blocking or async stub instance using the generated protobuf classes from the service's *.proto definitions.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →