Distributed System Fundamentals
Internet Application Architecture Characteristics
Modern internet applications exhibit distinct characteristics that differentiate them from traditional enterprise software:
- High user volume with global accessibility
- Massive traffic and concurrent requests
- Large-scale data processing requirements
- Vulnerability to malicious attacks
- Complex functionality spanning multiple domains
- Rapid iteration and frequent updates
Traditional vs Internet Applications
User Experience encompasses visual design, feature completeness, response speed, and system stability.
Performance Metrics
Response Time: Total duration from request initiation to final data reception.
Concurrent Requests: Maximum number of simultaneous requests the system can process.
Concurrent Connections: Number of TCP connections established between clients and server per second.
Request Rate (QPS): Queries per second that the system processes.
Concurrent Users: Number of unique users within a time unit.
Throughput: System's capacity to handle requests per time unit.
QPS: Queries Per Second
TPS: Transactions Per Second
A transaction represents one client request and server response cycle.
One page visit generates one TPS but may trigger multiple QPS due to
multiple resource requests.
QPS >= Concurrent Connections >= TPS
Architecture Goals:
- High Performance: Deliver fast访问体验
- High Availability: Ensure continuous service accessibility
Cluster vs Distributed
Cluster: Multiple nodes executing identical tasks. A single business module deployed across multiple servers.
Distributed: Different nodes handling different tasks. These distinct operations combine to complete a larger business objective.
Architecture Evolution
Monolithic Architecture
Advantages: Simplicity in development and deployment, ideal for small projects.
Disadvantages:
- Slow application startup
- Poor reliability
Vertical Architecture
Splits monolithic applications into multiple independent projects, each handling specific business domains.
Issues:
- Significant code duplication across projects
Distributed Architecture
Extracts common business modules as standalone services for reuse. Communication achieved through RPC (Remote Procedure Call).
RPC: Remote Procedure Call enables cross-network service invocation. Multiple protocols implement RPC: HTTP REST, Java RMI, WebService SOAP, Hessian, and others.
Issues:
- Service provider changes require updates to all consumers
SOA (Service-Oriented Architecture):
Component model that splits application functionality into distinct services with well-defined interfaces and contracts.
ESB (Enterprise Service Bus):
Service intermediary facilitating inter-service communication with features including load balancing, flow control, encryption, monitoring, and error handling.
Microservices Architecture:
Evolution of SOA emphasizing complete componentization. Large applications decompose into independently developed, deployed, and operated smaller services interacting via REST APIs.
Characteristics:
- Componentization through independent services
- Technology flexibility per service
- Decentralized data storage
- Automated deployment pipelines
Dubbo Framework Overview
Dubbo is an open-source high-performance Java RPC framework by Alibaba, providing transparent remote service invocation and SOA service governance capabilities.
Node Roles:
- Provider: Service exporter
- Container: Service runtime environment
- Consumer: Service consumer
- Registry: Service registration and discovery center
- Monitor: Call statistics and monitoring
Quick Start Guide
Zookeeper Installation
Zookeeper serves as the service registry for Dubbo.
Installation Steps:
- Install JDK (prerequisite)
- Upload Zookeeper archive (zookeeper-3.4.6.tar.gz) to Linux
- Extract the archive:
tar -zxvf zookeeper-3.4.6.tar.gz
- Create data directory:
mkdir -p zookeeper-3.4.6/data
- Navigate to config directory and rename sample file:
cd zookeeper-3.4.6/conf
mv zoo_sample.cfg zoo.cfg
- Edit zoo.cfg, update data directory:
dataDir=/root/zookeeper-3.4.6/data
- Start Zookeeper:
./zkServer.sh start
- Stop Zookeeper:
./zkServer.sh stop
- Check status:
./zkServer.sh status
Service Provider Development
Project Structure:
Create a Maven project (war packaging) named dubbo-provider with the following pom.xml dependencies:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.0.5.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.12.1.GA</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<configuration>
<port>8081</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
web.xml Configuration:
<web-app>
<display-name>Service Provider Application</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
Service Interface:
package com.example.demo.service;
public interface GreetingService {
String greet(String username);
}
Service Implementation:
package com.example.demo.service.impl;
import com.alibaba.dubbo.config.annotation.Service;
import com.example.demo.service.GreetingService;
@Service
public class GreetingServiceImpl implements GreetingService {
@Override
public String greet(String username) {
return "greeting " + username;
}
}
Spring Configuration (applicationContext-service.xml):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<dubbo:application name="dubbo-provider" />
<dubbo:registry address="zookeeper://192.168.134.129:2181"/>
<dubbo:protocol name="dubbo" port="20881"/>
<dubbo:annotation package="com.example.demo.service.impl" />
</beans>
Service Consumer Development
Create Maven project (war packaging) named dubbo-consumer with identical dependencies, modifying Tomcat port to 8082.
web.xml Configuration:
<web-app>
<display-name>Service Consumer Application</display-name>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-web.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
Copy Service Interface from provider project.
Controller Implementation:
package com.example.demo.controller;
import com.alibaba.dubbo.config.annotation.Reference;
import com.example.demo.service.GreetingService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("/api")
public class GreetingController {
@Reference
private GreetingService greetingService;
@RequestMapping("/greet")
@ResponseBody
public String handleGreet(String username) {
String result = greetingService.greet(username);
System.out.println(result);
return result;
}
}
Spring Configuration (applicationContext-web.xml):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<dubbo:application name="dubbo-consumer" />
<dubbo:registry address="zookeeper://192.168.134.129:2181"/>
<dubbo:annotation package="com.example.demo.controller" />
</beans>
Testing:
Start both applications using tomcat7:run and access:
http://localhost:8082/api/greet.do?username=Jack
Advanced Features
Dubbo Admin Installation
Dubbo Admin provides a graphical interface for service management:
- Retrieve all providers and consumers from registry
- Manage routing rules, dynamic configuration, service degradation
- Control access, adjust weights, and configure load balancing
Dubbo Admin is a frontend (Vue) and backend (Spring Boot) separated application.
Serialization
Dubbo handles serialization internally. POJO classes must implement Serializable:
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String username;
private Integer age;
}
Create a shared module containing POJOs for both provider and consumer dependencies.
Address Caching
Question: Can services operate normally when the registry fails?
Answer: Yes. On first invocation, Dubbo consumer caches provider addresses locally. Subsequent calls bypass the registry. When provider addresses change, the registry notifies consumers.
Timeout Configuration
Service consumers waiting for provider responses can cause thread accumulation during peak traffic, potentially leading to cascading failures.
Dubbo addresses this through timeout configuration. Set a timeout period; connection auto-disconnects if the request exceeds this duration.
@Service(timeout = 3000, retries = 0)
public class UserServiceImpl implements UserService {
// implementation
}
Default timeout: 1000ms
Retry Mechanism
Network instability may cause request failures. Dubbo provides retry capability via the retries attribute (default: 2):
@Service(timeout = 3000, retries = 0)
public class UserServiceImpl implements UserService {
// implementation
}
Set retries = 0 to disable retries.
Multi-Version Support
灰度发布 (Canary Release): Gradually rollout new features to a subset of users before full deployment.
Dubbo uses the version attribute for interface versioning:
Provider Configuration:
@Service(version = "v2.0")
public class UserServiceImplV2 implements UserService {
// implementation
}
Consumer Configuration:
@Reference(version = "v2.0")
private UserService userService;
Load Balancing
Four Strategies:
- Random (default): Weighted random distribution
- RoundRobin: Weighted round-robin
- LeastActive: Route to least active connecsion
- ConsistentHash: Same parameters route to same provider
Provider Configuration:
@Service(weight = 100)
public class UserServiceImpl implements UserService {
// implementation
}
Consumer Configuration:
@Reference(loadbalance = "random")
private UserService userService;
// or
@Reference(loadbalance = "roundrobin")
private UserService userService;
// or
@Reference(loadbalance = "leastactive")
private UserService userService;
// or
@Reference(loadbalance = "consistenthash")
private UserService userService;
Cluster Fault Tolerance
Cluster Strategies:
- Failover Cluster (default): Retry on failure, typically for read operations
- Failfast Cluster: Immediate failure for write operations
- Failsafe Cluster: Ignore errors, return empty result
- Failback Cluster: Schedule retry for failed requests
- Forking Cluster: Parallel calls, return on first success
- Broadcast Cluster: Call all providers, fail if any fails
Consumer Configuration:
@Reference(cluster = "failover")
private UserService userService;
Service Degradation
When system压力 increases, degrade non-critical services to preserve core functionality.
Degradation Modes:
mock = "force:return null": Return null without remote callmock = "fail:return null": Return null after failure
Consumer Configuration:
@Reference(mock = "force:return null")
private UserService userService;
This prevents service unavailability from affecting the consumer application.