大家好,我是melo,一名大二上软件工程在读生,经历了一年的摸滚,现在已经在工作室里边准备开发后台项目啦。
这篇文章我们不谈数据结构了,来谈谈入门分布式踩过的坑。感觉到了分布式这一层,由于技术更新迭代很快,我们似乎很难接触到第一手材料了(就连官方文档都没有实时更新,很多不适用)。几经摸索,看视频,翻文档,找博客,终于把Dubbo+zookeeper的小demo给成功跑起来了,写下这篇是因为里边有好多的坑,具体我都写在代码的注释里边了,希望可以帮到更多小伙伴,少踩一点坑,专心搞技术!
大型互联网项目架构目标
衡量网站的性能指标:
•响应时间:指执行一个请求从开始到最后收到响应数据所花费的总体时间。
•并发数:指系统同时能处理的请求数量。
•并发连接数:指的是客户端向服务器发起请求,并建立了TCP连接。每秒钟服务器连接的总TCP数量
•请求数:也称为QPS(Query Per Second) 指每秒多少请求.
•并发用户数:单位时间内有多少用户
•吞吐量:指单位时间内系统能处理的请求数量。
•QPS:Query Per Second 每秒查询数。
•TPS:Transactions Per Second 每秒事务数。
•一个事务是指一个客户机向服务器发送请求然后服务器做出反应的过程。客户机在发送请求时开始计时,收到服务器响应后结束计时,以此来计算使用的时间和完成的事务个数。
•一个页面的一次访问,只会形成一个TPS;但一次页面请求,可能产生多次对服务器的请求,就会有多个QPS
集群和分布式
传统
- 集群: 很多人干同一件事情
很多台服务器,上边负责同一个模块
- 分布式 : 很多人干不同的事情,合起来是一件大事情
很多台服务器,上边负责不同的小模块,最后合成一个大模块
- 集群和分布式,往往是同时存在的
高可用性
- 一个服务器挂了,不会影响另一个服务器,可以保证服务一直处于可用状态
高伸缩性
- 由于把各个模块尽量抽离开了,降低了彼此之前的耦合关系,所以比如要给E模块加多几个,可用直接加不会影响其他模块
高可扩展性
- 类似开闭原则,因为耦合度不高,所以扩展起来不是很难
架构演变
假设项目由 ABCD基础模块组成 E是公共模块
单体架构
- 一个服务器上,放着一整个项目 ABCDE
垂直架构
- 把项目拆成独立(互相没有关联)的两个模块 如 AB CD , 此时的E呢,因为两个服务器没有关联,所以E就不得不部署多次.即 ABE CDE 两台服务器
缺点
- 公共模块在每个服务器上都需要用到
分布式架构
- 垂直架构看起来已经是 不同服务器干不同的事情了, 不过还有一个公共模块E,在两个服务器中都出现过,我们要优化的话,可以多加一台服务器,单独放E
远程调用E(RPC)
- 用到 HTTP REST风格等(Dubbo都帮我们封装好了)
缺点
- E一但发生了改变,所有调用他的地方都需要去改变
SOA架构
没有什么是再多加一层解决不了的,加一个中间商ESB
微服务架构(待深入)
Dubbo的架构
节点角色说明:
•Provider暴露服务的服务提供方
•Container:服务运行容器
•Consumer:调用远程服务的服务消费方
•Registry:服务注册与发现的注册中心
•Monitor:统计服务的调用次数和调用时间的监控中心
快速入门
Zookeeper下载
官网:https://zookeeper.apache.org/releases.html
我选择的是这个版本,带有bin目录的
Windows
- 直接解压出来
- 将conf目录下的zoo_sample.cfg复制一份,改名为zoo.cfg(因为默认配置文件是这个名字)
- 然后退回安装目录,新建一个空的data 和 log
4 . 进入conf中修改zoo.cfg配置文件,将dataDir=/tmp/zookeeper 修改成 zookeeper 安装目录所在的 data 文件夹,再添加一条添加数据日志的配置(需要根据自己的安装路径修改)。
5 . 双击 bin目录下的 zkServer.cmd 启动程序:
6 . 控制台显示 bind to port 0.0.0.0/0.0.0.0:2181,表示服务端启动成功!
7 . 双击同目录下的zkCli.cmd 启动客户端
出现 Welcome to Zookeeper!,表示我们成功启动客户端。
注意
当需要一直启动zookeeper时,这两个cmd不能关掉不能关掉不能关掉!!!!!!!要保持运行
Linux
tar -zxvf (你下载的压缩包名称)
cd (你的安装目录)
cd conf/
cp zoo_sample.cfg zoo.cfg
vimzoo.cfg
此处需要按照上边一样修改,注意需要根据自己的安装路径修改 , 同样也得创建data和log,修改端口等
cd ..
cd bin/
sh zkServer.sh start
sh zkCli.sh
- 如果下载的版本不一样,可能需要自行查看一下帮助命令
详细配置(SpringBoot)
多模块开发
此处其实用到了三个模块,一个是公共接口模块,一个是provider模块,一个是consumer模块
其中后两个都共同去依赖公共模块
而provider又依赖consumer模块
想要完整源码的话可以评论区联系一下博主
特别注意
我们两个模块都要去@import com.example.dubbo_interface.service.StuService;
- 那这里就意味着什么,别的项目得能找到这个包啊,要怎么把公共接口dubbo_interface里边的包暴露出来,可供别人调用呢,这里是用到了maven的install命令,把dubbo_interface这一模块打包到公共仓库去了,这样别的项目就可以引用里边的内容了!
如果对maven这一块还不太熟悉的话,具体可以参照这篇 maven(先给自己挖个坑,整理好了会发出来的)
以下一切配置都完成了之后,记得先打开zookeeper!打开zookeeper!打开zookeeper!
provider提供服务端
yml文件
dubbo:
application:
#配置应用的名称(应用可以是提供者也可以是消费者)
name: dubbo_service
#协议中心
protocol:
#固定的, 是只有provider才需要吗?
name: dubbo
port: 20882
#指定注册中心的位置,127.0.0.1是ip地址,2181是端口号
registry:
address: zookeeper://127.0.0.1:2181
######这里是关键,很多教程没有配置,导致zookeeper连接不上
timeout: 50000
#要暴露的服务所在的包(配置扫包)
#也可以在注解那里扫包
# scan:
# base-packages: com.example.dubbo_service.service
#指定该项目模块启动的端口,不可与其他项目端口重复
server:
port: 8081
具体Service服务端
package com.example.dubbo_service.service;
import com.example.dubbo_interface.service.StuService;
import org.apache.dubbo.config.annotation.DubboService;
//暴露服务
@DubboService
public class StuServiceImpl implements StuService {
@Override
public String login() {
return "111";
}
}
引入Dubbo依赖和控制zookeeper的客户端
这里使用的是2.7.8版本,搭配2.5.5版本的Springboot
注意依赖接口模块
<!--依赖接口项目-->
<dependency>
<groupId>com.example</groupId>
<artifactId>dubbo_interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- Dubbo Spring Boot Starter -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.8</version>
</dependency>
<!--curator依赖-->
<!--Curator提供了一套Java类库, 可以更容易的使用ZooKeeper。 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>5.1.0</version>
</dependency>
启动类
@EnableDubbo注解一般写在启动类上,默认会扫描当前注解所在类的包路径下的所有@Dubboservice标注的组件,如果需要自定义扫描注册的bean(服务实现),可以使用@DubboComponentScan或扫描属性实现。另外,@EnableDubbo注解等效于在配置文件中使用dubbo.scan.base-packages一步到位(开启dubbo功能+扫描dubbo的服务实现bean)
package com.example.dubbo_service;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//开启基于注解的Dubbo功能,同时扫描要暴露的服务端所在的位置
@EnableDubbo(scanBasePackages = "com.example.dubbo_service.service")
@SpringBootApplication
public class DubboServiceApplication {
public static void main(String[] args) {
SpringApplication.run(DubboServiceApplication.class, args);
}
}
consumer消费者端
注意,其不同于传统的service,这里为了能独立启动,也要设置成web项目那种(再借助Springboot启动)
yml文件
dubbo:
application:
#指定当前服务/应用的名字(同样的服务名字相同,不要和别的服务同名)
name: dubbo_controller
## consumer不需要这个通信协议,因为consumer无需通过Dubbo来远程调用
# protocol:
# name: dubbo
## port: 20881
#指定注册中心的位置,127.0.0.1是ip地址,2181是端口号
registry:
address: zookeeper://127.0.0.1:2181
######这里是关键,很多教程没有配置,导致zookeeper连接不上
timeout: 50000
##发现按照官网只配consumer的话,也还是连不到zookeeper的
consumer:
##后来发现这里就等效于DubboReference注解那里的timeout设置
timeout: 3000
##此处是用在暴露扫包的,consumer不需要暴露服务
# scan:
# base-packages: com.example.dubbo_service.service
#指定该项目模块启动的端口,不可与其他项目端口重复
server:
port: 8082
具体Controller消费者端
package com.example.dubbo_controller.controller;
import com.example.dubbo_interface.service.StuService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/stu")
public class StuController {
/**
* 远程注入
* 从zookeeper注册中心获取该service的访问url
* 进行远程调用RPC
* 将结果封装成一个代理对象,给变量赋值
*/
//没timeout好像就出问题了??连不上??
//也可以在yml里边的consumer的timeout进行配置
@DubboReference/*(timeout = 5000)*/
StuService stuService;
@RequestMapping("/login")
public String login(){
return stuService.login();
}
}
同上引入依赖
<!--依赖接口项目-->
<dependency>
<groupId>com.example</groupId>
<artifactId>dubbo_interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- Dubbo Spring Boot Starter -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.8</version>
</dependency>
<!--curator依赖-->
<!--Curator提供了一套Java类库, 可以更容易的使用ZooKeeper。 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>5.1.0</version>
</dependency>
启动类
package com.example.dubbo_controller;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//开启基于Dubbo的注解
@EnableDubbo
@SpringBootApplication
public class DubboControllerApplication {
public static void main(String[] args) {
SpringApplication.run(DubboControllerApplication.class, args);
}
}
公共接口
因为provider和consumer两个模块都会需要用到这个接口,所以不如抽取出来作为公共的接口
package com.example.dubbo_interface.service;
//公共接口
public interface StuService {
String login();
}
Dubbo-admin
人生建议: 直接用老版本的前后端未分离,直接可以一键启动使用,端口默认在本机的7001
关于老版本的dubbo-admin我是直接用的尚硅谷教程里边的的尚硅谷的文件里边应该会有,如果找不着的话也可以评论留言一下
修改application.properties
server.port
该项目要启动的端口
registry.address
要监测的注册中心的地址
启动之前要先启动zookeeper!!!(如何启动参照上边zookeeper安装)
访问localhost:端口号
默认用户名和密码都是root
最终效果
先开着zookeeper,如何启动service模块,再启动controller模块,最后启动dubbo-admin项目
可以看到有一个服务数,两个应用数,一个是提供者,一个是消费者
服务是我们的接口模块
提供者
消费者
访问我们的接口
完整工程代码
- 这里三个模块的互相依赖关系pom文件,基于个人项目名称不同而有所不同,若对于pom文件和依赖关系还有点迷惑的小伙伴们欢迎评论区微信交流
写在最后
- 分布式这一块还是刚刚入门,原理方面希望也能多了解了解,希望接下来还能继续坚持下去,多多补充这一块的知识。关于Dubbo的一些高级特性,以及zookeeper的具体学习,过段时间再来补充!(flag疯狂立起来了)
PPT来源
- 黑马Dubbo教程
- dubbo-admin文件来源: 尚硅谷