互联网公司与传统公司的信息化一个很大的不同就是架构更加偏向分布式,并非这个比较高级或则是某个人的偏好,而是由于业务基因所决定,因为传统公司往往需求是明确的,开发结束就能够长期稳定运行,互联网公司就不一样,大多都是从一个小的产品迭代而来,需求往往不明确,所以像传统公司按照需求来评估硬件资源变的不现实,分布式开发开辟了另一个横向扩展 scale out的思路用分布式集群达到提供强大服务的方式。
最开始我们使用spring boot 一整套分布式集群的解决方案,但是发现restful的接口设计虽然比较轻量但是沟通成本比较高,主要在于接口的调用,可能还因为团队对Dubbo比较熟悉,相比在项目时间比较紧的情况下用spring boot全套感觉坑不少,因此紧急掉头转向了Dubbo,其实spring boot与dubbo并非不能共存,只是我们在服务发现和治理这一块采用了dubbo,但是单体应用开发的简洁性还是受益于spring boot。
@SpringBootApplication
@RestController
public class Application {
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(Application.class);
springApplication.run(args);
}
}
这样一个webapp就好了,完全不需要去配置web.xml和servlet的那一套模板式的文件。@SpringBootApplication是一个组合注解,它里面组合了@Enable*等等注解,这就是springboot的精髓所在,这些注解本身只提供一个元数据,但基于这些注解的自动配置处理器会加载并且使用大量的默认配置去启动这个应用,spring应用就启动了。其他的相关组件包括hibernate jpa也对spring boot提供了支持的包,在Github上的spring boot的迭代速度也十分的惊人。可以说spring boot是当前J2EE微服务化的旗舰产品。
Dubbo
Dubbo是阿里团队的产品,集成了Zookeeper和一大堆服务治理的组件,我虽然之前没使用过dubbo,但是久仰已久,也在一天内自己学习了一下然后改造了我们的产品。网上说Dubbo在国内比较火一个原因阿里的影响力,现在阿里已经不用Dubbo,不知道因为开源了不用,还是不用了才开源,还是说Dubbo已经无法满足阿里的业务需求。总之现在由于开源社区的沉寂,当当在Dubbo上扩展出Dubbox在维护,在开源社区的活跃度上来说Dubbo与spring boot不在一个级别,或则Dubbo已经是一个非常完善的中间件所以不需要迭代了,我不太认可这个看法。
关于分布式的对比
Dubbo使用的是特有协议的生产消费模式,最新的Dubbox也支持rest的风格,暴露Java接口然后以Bean的方式共享出去,服务提供方被注册到Dubbo的注册中心,然后服务消费者能够使用接口然后在spring的支持下连接到Dubbo注册中心拿到服务并且消费。对于应用来说基本可以做到RPC的透明。个人感觉开发体验还是比较好的,缺点就是Dubbo比较重,主要体现在它提供的一整套解决方案,不如spring那样更加轻量的模块化设计。springcloud采用的是eureka等等一些工具去完成服务发现,Dubbo使用的是zookeeper。个人认为spring的支持对于spring cloud的兼容性更好,后续的支持也更加完善。
zookeeper安装
接下来实现简单的Dubbo应用。首先安装Zookeeper(简称zk),去官网下载然后解压,demo只演示一台机器,生产环境zk至少是三台机器的集群(一般是奇数个)做到高可用的服务发现支持。然后在目录下找到:zookeeper-3.3.6/bin/zkServer.sh,这个是服务的启动脚本,关于zk的启动会输出到zookeeper.out。如果启动异常可以查看该文件,启动zk的命令是./zkServer.sh start 。它会自动去查找zk的配置文件,这个配置文件在zk目录下的zoo.cfg,直接复制zoo_sample.cfg命名为zoo.cfg即可。里面的具体配置不作详解。
可以关注下这个配置:
clientPort=2181
这个是zk服务暴露的端口。稍后Dubbo的生产消费会注册到这个端口.
执行启动脚本:
./zkServer.sh start
提示信息显示STARTED….则启动了zk。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
<version>1.5.4.RELEASEversion>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>dubboartifactId>
<version>2.5.3version>
dependency>
<dependency>
<groupId>com.github.sgroschupfgroupId>
<artifactId>zkclientartifactId>
<version>0.1version>
dependency>
yml配置:
server :
port : 8088
zookeeper:
connect-urls: zookeeper://{zk的ip}:2181
namespace: dubbo-produer
8080为当前spring-boot服务的暴露端口,yml为比json更加简洁的配置,springboot可以说是把简洁贯穿到底了。
暴露的Java接口:
public interface ProductService {
String getProductByName(String name);
}
服务提供者当然要实现这个接口:
@Component("productService")
public class ProducerServiceImpl implements ProductService{
public String getProductByName(String name) {
if (name.equals("product1")) {
return "P1";
}
return null;
}
}
dubbo.xml
<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-4.1.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
">
<import resource="produce.xml" />
<dubbo:application name="${zookeeper.namespace}"
owner="platform" />
<dubbo:monitor protocol="registry">dubbo:monitor>
<dubbo:registry address="${zookeeper.connect-urls}"
timeout="20000" />
<dubbo:protocol name="dubbo" port="8088" threadpool="cached"
threads="600" />
beans>
这里配置了连接到Dubbo配置中心服务发现的配置,主要是zk的地址,和提供的端口,具体的生产者,produce.xml:
<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:service interface="com.micro.spring.dubbo.api.ProductService"
ref="productService" version="1.0.0" delay="-1" protocol="dubbo">
dubbo:service>
beans>
这两个配置主要告诉了 “我是谁,我提供什么服务,我在哪里提供服务“。
springboot的启动应用:
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
@ImportResource("classpath:dubbo/dubbo.xml")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
由于我们没有使用dataSource 所以@SpringBootApplication的exclude去除掉一些关于jpa的自动配置,否则会报错。
去Github上clone Dubbo admin,然后放到tomcat的webapp下的 ROOT下面;如果是jdk8可能会报错,URI error,只要升级下maven依赖的jar版本即可解决:
<dependency>
<groupId>com.alibaba.citrusgroupId>
<artifactId>citrus-webx-allartifactId>
<version>3.1.6version>
dependency>
<dependency>
<groupId>org.apache.velocitygroupId>
<artifactId>velocityartifactId>
<version>1.7version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>dubboartifactId>
<version>${project.parent.version}version>
<exclusions>
<exclusion>
<groupId>org.springframeworkgroupId>
<artifactId>springartifactId>
exclusion>
exclusions>
dependency>
可以看到我们的生产者已经注册到了dubbo,接下来是消费者:
项目结构:
maven依赖一样,但是要依赖服务提供者提供的Java的api的jar.主要看下配置文件:
application.yml:
server :
port : 8081
zookeeper:
connect-urls: zookeeper://115.126.86.143:2181
namespace: dubbo-consumer
dubbo.xml:
<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-4.1.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
">
<import resource="consumer.xml" />
<dubbo:application name="${zookeeper.namespace}"
owner="platform" />
<dubbo:monitor protocol="registry">dubbo:monitor>
<dubbo:registry address="${zookeeper.connect-urls}"
timeout="20000" />
<dubbo:protocol name="dubbo" port="8811" threadpool="cached"
threads="600" />
beans>
<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:reference id="productService" interface="com.micro.spring.dubbo.api.ProductService" version="1.0.0"/>
beans>
然后看Application.java :
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
@Component
@ImportResource("classpath:dubbo.xml")
@RestController
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Autowired
private ProductService prodcutService;
@PostConstruct
public void test() {
String p = prodcutService.getProductByName("product1");
System.out.println("get p : " + p);
}
}