1.传统项目与互联网项目
相信很多小伙伴或多或少都接触过这两类项目,相较于传统项目,互联网的项目特点如下
- 客户多,用户多
- 流量大!
- 数据量大!
- 安全性要求较高!
- 变更迭代快!
- 功能更复杂一些!
为什么要提这个呢,是为了更好的理解dubbo解决的一些痛点问题。
1.1 互联网项目的指标
- 响应时间!
- 并发数量:单位时间内请求的链接数、用户数、请求数QPS。
- 吞吐量:QPS、TPS(事务数,tps包含了很多链接)
然后一个好的项目的目标是什么呢?怎么衡量项目的成功与否呢?
- 高性能!传统意义上的速度快!用户体验极佳
- 高可用!意思就是你网站崩掉的次数少!或者没有,你看著名的网站崩了是不是都会上热搜?
- 可伸缩!如果我某个服务请求过多了,一台机器搞不定了,我可以部署多个服务器,保持网站的可用性!
- 可扩展!意思就是增加或者删除功能的时候不会牵一发动全身,各个模块之间的耦合性非常低!
- 安全性!被别人攻击获取信息的事情肯定是不能干的是吧!
- 敏捷性!当业内有一个新的功能出现的时候我能够快速的copy实现,懂得都懂!
1.2 集群和分布式
集群就是我一个项目部署多个服务器,注意!项目的代码是一样的,做的事情都是一样的!
分布式就是每个服务器做的事情都是不一样的!不同服务之间相互配合可以做成一个大事!
当然集群和分布式是缺一不可的。相辅相成!
1.3 架构演变
- 单体架构!优点就是部署简便,缺点:当业务代码越来越多,相应的项目启动就会越来越慢!单体项目里面模块之间会相互影响,我一个模块启动有问题,整个项目就会挂掉!拓展性很差,容易牵一发动全身。最后就是性能过低!
- 垂直架构!垂直架构简而言之就是把单体架构的模块拆成一个独立的项目。优点就是缓解了单体架构的一些缺点,当然垂直架构还是会存在单体架构的弊端,只是稍微好一点。缺点就是冗余的代码太多了,比如用户管理,两个不同的项目,肯定用户管理都是自己的,这样一来,我要维护的时候,每个项目都要去改一下,是不是很麻烦?
- 分布式架构!就是把公共的功能拆解出来,其他的服务要用到就来调用。这边就会是用到RPC,远程过程调用。通过这种技术,可以实现服务之间的调用。分布式也会存在新的问题,某个公共的项目如果服务器端口改变了,其他涉及到这个项目的都会要去改。
- SOA架构!目前也是很多公司用的架构体系,都会使用到一个ESB消息总线,每个服务需要调用其他系统的时候,需要把请求先发送给ESB消息总站,然后ESB通过报文头去调用各个服务!那么分布式的问题就能够解决了,我服务端口改变了只需要告诉ESB,其他服务不需要知道我的ip和端口。ESB知道就行!
- 微服务架构!微服务架构其实和SOA非常相似。微服务主要强调的是组件化,模块化,服务化。就是专精做一件事情!
然后这次Dubbo就是SOA时代的产物,SpringCloud是微服务时代的产物。
2.Dubbo
RPC框架、阿里巴巴、阿帕奇收购。记住这些关键词就行。
2.1 Spring集成Dubbo
这边遇到一个错误,这边的错误原因是dubbo服务提供方的接口的包位置和服务方接口的包位置不一致!这边是必须一致的,不然dubbo找不到实现类。先说错误免得踩坑,当然后面也会说最好的方案!解决这个问题,这边代码比较多,可以跳着看。
Caused by: java.lang.IllegalStateException: Failed to check the status of the service com.zx.Controller.Service.UserService. No provider available for the service com.zx.Controller.Service.UserService from the url zookeeper://124.567.99.678:2181/org.apach
2.1.1 服务方的配置文件
web.xml
<?xml version="1.0" encoding="UTF-8" ?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"version="2.5">
<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>
applicationContext.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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://dubbo.apache.org/schema/dubbohttp://dubbo.apache.org/schema/dubbo/dubbo.xsd
"
>
<!-- <context:component-scan base-package="com.zx" />
注册到注册中心的应用名称--><dubbo:application name="dubboService"/>
<!--注册中心地址--><dubbo:registry address="zookeeper://124.110.99.110:2181"/>
<!--dubbo 注解扫描的包--><dubbo:annotation package="com.zx"/>
</beans>
接口和实现类,接口就补贴了很简单
package com.zx.Impl;import com.zx.UserService;
import org.apache.dubbo.config.annotation.Service;@Service//这边的service是dubbo包里的,这个注解会把这个服务注册到zookeeper上去
public class UserServiceImpl implements UserService {public String findName() {return "hasai!";}
}
2.1.2 客户端配置
web.xml
<?xml version="1.0" encoding="UTF-8" ?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"version="2.5"><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*:spring/springmvc.xml</param-value></init-param></servlet><servlet-mapping><servlet-name>springmvc</servlet-name><url-pattern>*.do</url-pattern></servlet-mapping>
</web-app>
springmvc.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:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://dubbo.apache.org/schema/dubbohttp://dubbo.apache.org/schema/dubbo/dubbo.xsd
"
><mvc:annotation-driven/><context:component-scan base-package="com.zx.Controller"/><dubbo:application name="dubboWeb"/><dubbo:registry address="zookeeper://124.223.99.145:2181"/><dubbo:annotation package="com.zx.Controller"/>
</beans>
ctl和接口接口就不贴了
package com.zx.Controller;import com.zx.UserService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/test")
public class UserCtrl {
// @Autowired@Reference//从注册中心去拿地址UserService userService;@RequestMapping("/findName")public String findName(){return userService.findName();}
}
2.1.3 错误原因解析
这个地址必须和服务提供方的接口地址一样,如果接口多了就能保证都一摸一样嘛,为了保证一样可以把接口定义成一个jar,大家商量好,都用这个jar 就行。
2.2 dubbo-admin
M1 Mac安装node.jshttps://blog.csdn.net/qq_33105531/article/details/121873709
dubbo-admin git地址https://github.com/apache/dubbo-admin
clone下来之后改一个注册中心的地址配置文件,改成你自己的注册中心地址。
前端项目先编译
然后在
自此admin启动成功!
界面如下
配置文件服务端的
2.3 序列化
如果想要把对象在网络中传输,那么就要将类序列化,这个就不多说了实现Serializable接口
import java.io.Serializable;
/**所有要在网络中传输的对象,都要实现序列化这个接口*/
public class Yxlm implements Serializable {
2.4 地址缓存
面试题:注册中心挂了,还可以访问嘛?答案是可以的,如果注册中心上的地址我们访问过,就会缓存到本地,就算注册中心挂了,也是可以拿到缓存的地址进行访问。
2.5 超时、重试机制
相信大家在开发过程中也会遇到这个问题,客户端请求服务端的时候,如果对象一直不返回数据,那么我这个客户端的线程就会一直等待,在流量小的时候是没问题的,但是在流量大的时候这个接口有几百万个线程来请求,那么客户端的资源就会用光,从而导致雪崩的效应。为了解决这个问题,dubbo有个超时和重试这两个机制,超时就是我固定时间可以设置超时的时间内不给我返回,我就断开。重试的意思就是我再试试可以固定次数!都不行的话我就不请求了!
当然超时时间客户端和服务端都可以设置。客户端设置的意思就是这么长时间不返回我就不要了,客户端设置的意思,你请求的这个接口时间太长了,我不给你提供服务了。一般常用的超时是配置在服务端
客户端
@Reference(timeout = 1000)HeroServcie heroServcie;
服务端,retries 是重试次数,这边设置的是2次,连上开始的一次一共请求了三次
@Service(timeout = 3000,retries = 2)
public class HeroServiceImpl implements HeroServcie {
2.6 多版本
灰度发布:我一个服务可能会有多个版本,那么部署上去的时候我肯定不会让所有客户端都链接到我新的服务上去,万一有问题,那就是全部都有问题了,灰度发布的意思就是我先让一部分客户端尝尝鲜,但是客户端会有一部分保留继续请求老的版本,如果最后新版本没问题,那么将剩下使用老版本的客户端都改成新版本。
服务端多版本
@Service(timeout = 3000,retries = 2,version = "V2.0")
public class HeroServiceImpl2 implements HeroServcie {@Service(timeout = 3000,retries = 2,version = "V1.0")
public class HeroServiceImpl implements HeroServcie {
客户端可以选择调用某个实现
@Reference(timeout = 1000,version = "V2.0")HeroServcie heroServcie;
2.7 负载均衡
先直接启动某个服务三次,最后在dubboadmin中可以查看到三个服务注意有三个地方的端口要改
第一就是tomcat端口,下面这两个端口也要更改。保证三个服务端口都不冲突
<dubbo:protocol port="20333"></dubbo:protocol><dubbo:application name="dubboService"><dubbo:parameter key="qos.port" value="22122"/></dubbo:application>
并且设置权重
@Service(timeout = 3000,retries = 2,version = "V1.0",weight = 200)
public class HeroServiceImpl implements HeroServcie {
启动成功之后在admin里面界面是这个样子的
服务端调用方式
@Reference(timeout = 1000,version = "V1.0",loadbalance = "random")HeroServcie heroServcie;
这边的loadbalance就是负载均衡策略一共有四种
- random 随机
- RoundRobin 根据权重来调用
- LeastActive 最少活跃调用数,相同活跃数的随机。
- ConsistentHash 一直性hash,相同参数的请求总是发到统一提供者,简而言之你的请求参数相同的都打到同一台机器上
2.8 集群容错
如果调用出错了,我们会采取什么机制,出错了我就不请求了,还是选择再试试。这边就是dubbo给我们提供的容错机制
@Reference(cluster = "failover")//从注册中心去拿地址UserService userService;
- Failover Cluster 失败重试,和上面的超时重试差不多的意思,就是报错我也会重试几次,这边一般是用在查询的操作上,写的操作不能使用这个,会出现问题。
这边我就讲一个但是官网的文档写的非常详细同学们移步官网
2.9 服务降级
@Reference(cluster = "failover",mock = "force:return null")//从注册中心去拿地址UserService userService;
官方文档中也是有的,我这边稍微解释一下,上面的降级方法就是,我请求都不请求了,这个接口返回null
下面的降级方法还是会请求一下的,失败了就返回null。
结束语
以上就是所有dubbo的基本使用,后面有机会,会出一个dubbo源码的解析。