白话分布式系统

一、什么叫分布式系统?

1、单体应用介绍:
所谓单体应用,就是一些小型的应用,一个系统就是eclipse中的一个工程,然后打一个jar包或者war运行,这个jar包或者war就是整个系统服务。这就叫单体应用。


欢迎大家关注我的公众号 javawebkf,目前正在慢慢地将简书文章搬到公众号,以后简书和公众号文章将同步更新,且简书上的付费文章在公众号上将免费。


2、分布式系统介绍:
如果项目小,那么单体应用就可以了,如果项目很复杂,访问量特别多,还是打一个包的话,那可能就会崩掉了。所以就出现了分布式系统。就是把项目中的不同的功能模块独立成一个系统,单独部署。比如京东商城,把订单系统部署到A服务器,用户系统部署到B服务器……这样的就叫分布式系统。说白了,就是把一个大系统分成各个功能模块,然后把不同的功能模块部署到不同的计算机上。

3、分布式和微服务:
微服务是一种思想,就是上面说的把大系统拆分成不同的功能模块,做成一个个的服务,然后这些服务协调运作,对外提供一个完整的大的系统的服务。若是把这些不同的功能模块部署到不同的计算机,那就叫分布式。

二、dubbo介绍

1、dubbo是干嘛的?
上面说到了分布式系统,把功能模块独立部署在不同的计算机上,但是这些功能模块相互之间可能也会相互调用。比如订单模块部署在A计算机,用户模块部署在B计算机,订单模块需要调用用户模块查询用户的收货地址等信息。dubbo就是用来治理这些不同的功能模块的。

2、RPC是什么?
RPC中文名叫远程过程调用。上面说了不同的功能模块部署在不同的计算机上,然后它们又要相互调用,那么就可以采用RPC。也就是A计算机上的订单模块要调用B计算机上的用户模块,我们可以采用的调用方法之一就叫RPC。RPC就是A和B两台计算机之间通过sockets进行通信。上面说到dubbo就是来治理这些服务,其实dubbo就是一个RPC调度框架。一个RPC框架性能如何,主要看两点。第一:建立socket连接的速度快不快;第二:订单模块调用用户模块的时候要传参数,参数可能是对象,对象要在网络上传输就要序列化。所以第二点就是看序列化和反序列化的速度快不快。

3、dubbo智能负载均衡:
比如用户模块压力比较大,那就再多搞几台计算机来部署用户模块。假设现在有B、C、D、E四台计算机运行着用户模块,那么一个请求过来是到了这四台计算机中的哪一台呢?dubbo就会自动选择一台请求比较少的计算机。这就叫智能负载均衡。

三、注册中心

1、注册中心是什么?
上面说了dubbo会智能地选择BCDE四台计算机中比较空闲的一台去响应请求,那么dubbo是如何知道这四台计算机哪一台比较闲呢?又或者说其中有一台计算机不能正常工作了,dubbo要如何知道这件事呢?这就引入了注册中心。A计算机告诉注册中心它可以提供订单模块的功能,BCDE计算告诉注册中心它可以提供用户模块的功能。也就说,注册中心就维护了一个清单,清单上写着哪台计算机可以提供什么服务。比如现在A服务器的订单模块要调用用户模块时,dubbo就会去问注册中心:“用户模块在哪些服务器上有?” 注册中心就会告诉dubbo:“在BCDE上都有。” dubbo就会选择一个负载最少的去调用。dubbo支持很多注册中心,一般使用zookeeper。

2、dubbo运行流程:
把服务注册到注册中心 ------> 订阅注册中心的服务 --------> dubbo框架进行RPC调用。同时dubbo还有监控中心,可以监控各个服务状况。

3、安装zookeeper:
去官网下载zookeeper ------> 解压后去conf目录,复制zoo_sample.cfg文件,改名为 zoo.conf,放在conf目录下 ------> 去bin目录下运行zkServer.cmd即可启动,运行zkCli.cmd就可启动客户端。

四、dubbo在spring项目中的使用

  • 需求:现在订单模块和用户模块。订单模块在A服务器,用户模块在B服务器。A的订单模块远程调用B的用户模块。

上面介绍了dubbo和注册中心,现在就看看在项目中实际应该如何使用,话不多说,开打。

1、项目的结构:
根据需求,订单服务是一个独立的工程,用户服务是一个独立的工程,然后订单服务中要调用用户服务,例如在订单服务的某个方法中肯定要用到UserService。但是UserService是在用户服务工程中的,怎么调用?直接把用户工程打jar包依赖过来吗?那这样就不是分布式应用了。正确的做法是:
将两个工程中要用到的接口、实体类等抽取出来独立成一个工程,具体的实现放到对应的具体工程中去。

2、common-api 工程:
这就是用户服务和订单服务会公用到的一些东西,放在这个工程中,然后打jar包,让用户服务工程和订单服务工程依赖即可。

工程结构
  • UserAddress.java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserAddress implements Serializable {

    private Integer id;
    private String userAddress;
    private String phoneNumber;
}
  • OrderService.java
public interface OrderService {
    public List<UserAddress> initOrder(String userId);
}
  • UserService.java
public interface UserService {
    public List<UserAddress> getUserAddressList(String userId);
}

3、user-service 工程:

工程结构

  • pom.xml
 <!-- dubbo依赖 -->
    <dependency>
      <groupId>org.apache.dubbo</groupId>
      <artifactId>dubbo</artifactId>
      <version>2.7.2</version>
    </dependency>
    <!-- zookeeper注册中心 -->
    <dependency>
      <groupId>org.apache.curator</groupId>
      <artifactId>curator-framework</artifactId>
      <version>2.12.0</version>
    </dependency>
    <dependency>
      <groupId>org.apache.curator</groupId>
      <artifactId>curator-recipes</artifactId>
      <version>2.12.0</version>
    </dependency>
  • UserServiceImpl.java
@Service
public class UserServiceImpl implements UserService {
    @Override
    public List<UserAddress> getUserAddressList(String userId) {
        if (userId.equals("1")){
            UserAddress userAddress1 = new UserAddress(1, "广东省深圳市宝安区","8008208820");
            UserAddress userAddress2 = new UserAddress(2, "广东省东莞市厚街镇","8008208820");
            return Arrays.asList(userAddress1,userAddress2);
        }
       else return null;
    }
}

接下来就需要在xml文件中将这个用户服务注册到注册中心去。

  • provider.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://dubbo.apache.org/schema/dubbo"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                           http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://dubbo.apache.org/schema/dubbo 
        http://dubbo.apache.org/schema/dubbo/dubbo.xsd
        http://code.alibabatech.com/schema/dubbo 
        http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <context:component-scan base-package="com.zhu.study.service"/>
    <!-- 1、指定当前服务/应用的名字(同样的服务名字相同,不要和别的服务同名) -->
    <dubbo:application name="user-service"></dubbo:application>
    
    <!-- 2、指定注册中心的位置 -->
    <!-- <dubbo:registry address="zookeeper://127.0.0.1:2181"></dubbo:registry> -->
    <dubbo:registry protocol="zookeeper" address="127.0.0.1:2181"></dubbo:registry>

    <!-- 3、指定通信规则(通信协议?通信端口)服务提供者和调用者通信规则 -->
    <dubbo:protocol name="dubbo" port="20882"></dubbo:protocol>
    
    <!-- 4、暴露服务   ref:指向服务的真正的实现对象 -->
    <dubbo:service interface="com.zhu.study.service.UserService"
        ref="userServiceImpl" timeout="1000" version="1.0.0">
        <dubbo:method name="getUserAddressList" timeout="1000"/>
    </dubbo:service>
    
</beans>

在这个配置文件中,首先给这个服务起个名字,然后注册到2181端口的注册中心去,再指定通信规则和端口,最后把用户模块的UserService暴露出去,同时用ref引用实现类。当然这个UserServiceImpl需要加入到spring容器中。

  • App.java
    现在编写启动类,加载配置文件。
public class App 
{
    public static void main( String[] args ) throws IOException {
        ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("provider.xml");
        ioc.start();
        System.in.read(); // 保留启动的状态
    }
}

运行这个启动类的前提是注册中心zookeeper启动起来了。运行之后,访问管理控制台就可以看到服务了(去dubbo的GitHub地址,找到dubbo-admin项目,下载下来,然后用maven打个jar运行,这就是管理控制台)。


管理控制台

可以看到user-service已经成功注册到zookeeper了。接下来就要在订单服务中调用它了。

4、order-service 工程:

工程结构

  • OrderServiceImpl.java
@Service
public class OrderServiceImpl implements OrderService {

    @Resource
    private UserService userService;
    @Override
    public List<UserAddress> initOrder(String userId) {
        // 查询用户收获地址
        List<UserAddress> addressesList = userService.getUserAddressList(userId);
        return addressesList;
    }
}
  • 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://dubbo.apache.org/schema/dubbo"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://dubbo.apache.org/schema/dubbo 
        http://dubbo.apache.org/schema/dubbo/dubbo.xsd
        http://code.alibabatech.com/schema/dubbo 
        http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <context:component-scan base-package="com.zhu.study.service"/>
    <dubbo:application name="order-service"/>
    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
    <dubbo:reference interface="com.zhu.study.service.UserService"
                     id="userService" timeout="5000" retries="3" version="*">
    </dubbo:reference>
</beans>

这里的配置,第一行是开启注解扫描,然后给订单服务起个名字,第三步是注册到zookeeper中去,第四步是引用UserService。这样就完事了,然后写个测试类试试水。

  • App.java
public class App 
{
    public static void main( String[] args ) throws IOException {

        ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("consumer.xml");
        OrderService orderService = ioc.getBean(OrderService.class);
        List<UserAddress> userAddresses = orderService.initOrder("1");
        for (UserAddress userAddress : userAddresses){
            System.out.println(userAddress.toString());
        }
        System.in.read();
    }
}
运行结果

可以看到,成功地调用了UserService服务。同时在管理控制台也可以看到调用者的信息。

五、dubbo与springboot整合

同样是order模块和user模块,看看怎么与springboot整合起来。

    1. 引入 dubbo-spring-boot-starter 依赖;
    1. 在启动类上加上如下注解;
@EnableDubbo
@SpringBootApplication
public class SpringbootOrderServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootOrderServiceApplication.class, args);
    }
}
    1. 将provider.xml 和 consumer.xml中的配置写在application.properties中,如下:
dubbo.application.name=springboot-user-service
dubbo.registry.address=127.0.0.1:2181
dubbo.registry.protocol=zookeeper
dubbo.protocol.name=dubbo
dubbo.protocol.port=20080
dubbo.monitor.protocol=registry
dubbo.application.name=springboot-order-service
dubbo.registry.address=127.0.0.1:2181
dubbo.registry.protocol=zookeeper
dubbo.protocol.name=dubbo
dubbo.protocol.port=20080
dubbo.monitor.protocol=registry
    1. 服务提供者使用dubbo的 @Service 注解暴露服务, 服务消费者使用 @Reference 调用提供者,如下:
@Service
@Component
public class UserServiceImpl implements UserService {
    @Override
    public List<UserAddress> getUserAddressList(String userId) {
        if (userId.equals("1")){
            UserAddress userAddress1 = new UserAddress(1, "广东省深圳市宝安区","8008208820");
            UserAddress userAddress2 = new UserAddress(2, "广东省东莞市厚街镇","8008208820");
            return Arrays.asList(userAddress1,userAddress2);
        }
       else return null;
    }
}
@Service
public class OrderServiceImpl implements OrderService {

    @Reference
    private UserService userService;
    @Override
    public List<UserAddress> initOrder(String userId) {
        // 查询用户收获地址
        System.out.println(userService);
        List<UserAddress> addressesList = userService.getUserAddressList(userId);
        return addressesList;
    }
}

注意: @Reference(url = "dubbo://服务提供者所在的机器IP:通信端口"),如果这个注解加上url,那么就表示绕过注册中心,使用dubbo直连的方式,即这样写了的话没有zookeeper都可以。

上面简单地介绍了分布式架构的思想以及dubbo的简单使用,更多dubbo的配置规则,请参考dubbo官网的开发手册。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,783评论 5 472
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,396评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,834评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,036评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,035评论 5 362
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,242评论 1 278
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,727评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,376评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,508评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,415评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,463评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,140评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,734评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,809评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,028评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,521评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,119评论 2 341

推荐阅读更多精彩内容