分布式及RPC出现的背景:
1.我们传统的网站结构为单一应用架构,也就是把所有的功能都放在一个项目工程里,部署在一台服务器上。
2.但是当访问量越来越大,我们需要通过不断添加服务器的方式来应对越来越大的访问量,产生了集群;或是将应用拆分成几个不相干的应用部署在不同的服务器上,产生了分布式系统。
集群:将相同的程序、功能部署在两台或是多台服务器上,这些服务器对外提供的功能是完全一样的,集群就是通过不同横向扩展增加服务器的方式,以提高服务的能力。
分布式系统:将两个或多个程序、功能分别运行在两台或多台主机服务器上,这些服务对外提供的功能并不一样,它们通过相互协作最终完成某一服务或是功能。
3.随着用户数的增加及业务的发展,拆分的应用越来越多,应用之间的交互及数据传输不可避免,则将核心业务抽取出来,作为独立的服务,形成稳定的服务中心,这其中就涉及到了RPC(远程过程调用),它主要为解决两个问题。
(1)解决分布式系统中,服务之间的调用问题。
(2)远程调用时,要能够像本地调用一样方便,让调用者感知不到远程调用的逻辑。
RPC数据传输协议:
在RPC中进行数据传输人们首先想到http协议,这是可行的,但是有些情况下并没有必要,毕竟我们只需要传输数据而已,不需要使用应用层的http协议,所以在不同的RPC框架里使用了自定义的适用于自身的数据传输协议,比如dubbo(阿里)使用基于tcp的dubbo协议,面向java语音;spring cloud使用http协议,面向java语言;Grpc(谷歌)使用http2协议,跨语言,使用率最高;Thrift(先facebook后apache),使用RPC协议,基于tcp,跨语言。
dubbo框架:
说明:
Provider: 暴露服务的服务提供方。
Consumer: 调用远程服务的服务消费方。
Registry: 服务注册与发现的注册中心。
Monitor: 统计服务的调用次调和调用时间的监控中心。
调用关系说明:
服务提供者在启动时,向注册中心注册自己提供的服务。
服务消费者在启动时,向注册中心订阅自己所需的服务。
注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
使用dubbo框架实现简单的rpc
首先按照相应目录结构,在dubbo项目中建立三大模块:
dubbo-api : 存放公共接口;
dubbo-consumer : 调用远程服务;
produce : 提供远程服务。
1.1 dubbo-api 接口层开发
Api层开发HelloService接口
package com.qcby.service;
public interface HelloService {
public void saySomething(String msg);
}
1.2 配置POM.xml文件
· dubbotest父级目录配置pom.xml全局文件,所加载资源适用于所有子级工程。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.qcby</groupId>
<artifactId>dubbotest</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>dubbo_api</module>
<module>dubbo_consumer</module>
</modules>
<name>dubbotest</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<motan.version>0.3.0</motan.version>
<dubbo.version>2.5.3</dubbo.version>
<dubbox.version>2.8.4</dubbox.version>
<spring.version>4.3.6.RELEASE</spring.version>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.3</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
<!-- spring相关 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</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-context</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-web</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-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>4.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.7.4</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.11</version>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
consumer及produce模块下的pom文件中要依赖于dubbo_api
<dependency>
<groupId>com.qcby</groupId>
<artifactId>dubbo_api</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
7.3 dubbo-provider 服务提供者开发
7.3.1 HelloService接口实现类HelloServiceImpl 开发
package com.qcby.service.Impl;
import com.alibaba.dubbo.config.annotation.Service;
import com.qcby.service.HelloService;
@Service(version = "1.0",interfaceName = "helloService")
public class HelloServiceImpl implements HelloService {
@Override
public void saySomething(String msg){
System.err.println(msg);
}
}
7.3.2 dubbo-consumer.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:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!-- 提供方应用信息,用于计算依赖关系 -->
<dubbo:application name="dubbo_provider" />
<!-- 使用zookeeper注册中心暴露服务地址 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181" />
<!-- 用dubbo协议在20880端口暴露服务 -->
<dubbo:protocol name="dubbo" port="20880" />
<!-- 声明需要暴露的服务接口 -->
<dubbo:service interface="com.qcby.service.HelloService" ref="helloService" />
<!-- 接口实现类-->
<bean id="helloService" class="com.qcby.service.Impl.HelloServiceImpl"/>
</beans>
7.3.3 provider简单测试
· provider工程目录下新建Main类
package com.qcby.service;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
public class ProviderTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:springmvc.xml");
context.start();
System.out.println("Dubbo provider");
try {
System.in.read(); // 按任意键退出
} catch (IOException e) {
e.printStackTrace();
}
}
}
7.4 dubbo-consumer 服务请求者开发
7.4.1 dubbo-consumer .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:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd ">
<!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
<dubbo:application name="dubbo_consumer" />
<!-- 使用multicast广播注册中心暴露发现服务地址 -->
<dubbo:registry protocol="zookeeper" address="zookeeper://127.0.0.1:2181" />
<!-- 生成远程服务代理,可以和本地bean一样使用demoService -->
<dubbo:reference id="helloService" interface="com.qcby.service.HelloService" />
</beans>
7.4.2 consumer简单测试
· 请求Zookeeper进行服务端资源访问
package com.qcby;
import com.qcby.service.HelloService;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
public class ConsumerTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "classpath:springmvc.xml" });
context.start();
HelloService demoService = (HelloService) context.getBean("helloService");
demoService.saySomething("Hello World!wj");
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行结果:
下一篇我们介绍一下RPC中使用的消息中间件以及一些集群策略。