dubbo

Dubbo 01

 

架构模型

 

传统架构 All in One

测试麻烦,微小修改 全都得重新测

单体架构也称之为单体系统或者是单体应用。就是一种把系统中所有的功能、模块耦合在一个应用中的架构方式。其优点为:项目易于管理、部署简单。缺点:测试成本高、可伸缩性差、可靠性差、迭代困难、跨语言程度差、团队协作难

聚合项目划分

单项目容易 因为某个功能导致整体oom

拆分完 咋实现

SOA 架构: Service-Oriented Architecture

面向服务的架构(SOA)是一个组件模型,它将应用程序拆分成不同功能单元(称为服务)通过这些服务之间定义良好的接口和契约联系起来。接口是采用中立的方式进行定义的,它应该独立于实现服务的硬件平台、操作系统和编程语言。这使得构建在各种各样的系统中的服务可以以一种统一和通用的方式进行交互。

在没有实施SOA的年代,从我们研发的角度来看,只能在代码级别复用,即Ctrl +V。SOA出现,我们开始走向了模块、业务线的复用。

SOA年代的典型实现: SOAP协议,CXF框架,XML传输

xsd,数据校验

SOA架构伴随着软件研发行业20年的发展,在最初的时候,大型it公司内部系统规模越来越大,IT系统越来越复杂,All in One单体架构的思想导致公司内项目业务和数据相互隔离,形成了孤岛。

最初,我们使用数据库作为项目之间数据交互和中转的平台,现在我们有了消息中间件。

最初,我们使用XML完成系统之间解耦与相互关联,现在我们有了RPC,Restful

最初,我们使用业务维度划分整体项目结构,

最初,我们多项目节点维护一个共享数据中心,现在我们做冗余存储,闭环数据,保证高效运行及数据最终一致性

最初,SOA思想指导指导我们把所有的IT系统汇总成一个大的整体,按照业务维度划分服务,集中化管理 现在我们拆分抽象服务使其可以多系统复用相同的功能模块。

 

基于dubbo RPC的微服务式架构

RPC远程过程调用 : Remote Procedure Call Protocol

远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。

原来的RPC也有其他几种比如DCOM,CORBA,RMI(Java)等

  • RMI——Remote Method Invoke:调用远程的方法。“方法”一般是附属于某个对象上的,所以通常RMI指对在远程的计算机上的某个对象,进行其方法函数的调用。

  • RPC——Remote Procedure Call:远程过程调用。指的是对网络上另外一个计算机上的,某段特定的函数代码的调用。

传输协议

  • RPC,可以基于TCP协议,也可以基于HTTP协议

  • HTTP,基于HTTP协议

传输效率

  • RPC,使用自定义的TCP协议,可以让请求报文体积更小,或者使用HTTP2协议,也可以很好的减少报文的体积,提高传输效率

  • HTTP,如果是基于HTTP1.1的协议,请求中会包含很多无用的内容,如果是基于HTTP2.0,那么简单的封装以下是可以作为一个RPC来使用的,这时标准RPC框架更多的是服务治理

性能消耗

  • RPC,可以基于thrift实现高效的二进制传输

  • HTTP,大部分是通过json来实现的,字节大小和序列化耗时都比thrift要更消耗性能

负载均衡

  • RPC,基本都自带了负载均衡策略

  • HTTP,需要配置Nginx,HAProxy来实现

服务治理

  • RPC,能做到自动通知,不影响上游

  • HTTP,需要事先通知,修改Nginx/HAProxy配置

RPC主要用于公司内部的服务调用,性能消耗低,传输效率高,服务治理方便。HTTP主要用于对外的异构环境,浏览器接口调用,APP接口调用,第三方接口调用等。

概念

Dubbo介绍

Apache Dubbo |ˈdʌbəʊ| 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。

Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和Spring框架无缝集成。Dubbo框架,是基于容器运行的.。容器是Spring。

官方网站 : http://dubbo.apache.org/

阿里巴巴已经将dubbo框架捐献给了Apache软件基金会

Dubbo框架结构

角色

registry

注册中心. 是用于发布和订阅服务的一个平台.用于替代SOA结构体系框架中的ESB服务总线的。

发布

开发服务端代码完毕后, 将服务信息发布出去. 实现一个服务的公开.

订阅

客户端程序,从注册中心下载服务内容 这个过程是订阅.

订阅服务的时候, 会将发布的服务所有信息,一次性下载到客户端.

客户端也可以自定义, 修改部分服务配置信息. 如: 超时的时长, 调用的重试次数等.

consumer

服务的消费者, 就是服务的客户端.

消费者必须使用Dubbo技术开发部分代码. 基本上都是配置文件定义.

provider

服务的提供者, 就是服务端.

服务端必须使用Dubbo技术开发部分代码. 以配置文件为主.

container

容器. Dubbo技术的服务端(Provider), 在启动执行的时候, 必须依赖容器才能正常启动.

默认依赖的就是spring容器. 且Dubbo技术不能脱离spring框架.

在2.5.3版本的dubbo中, 默认依赖的是spring2.5版本技术. 可以选用spring4.5以下版本.

在2.5.7版本的dubbo中, 默认依赖的是spring4.3.10版本技术. 可以选择任意的spring版本.

monitor dubbo admin

监控中心. 是Dubbo提供的一个jar工程.

主要功能是监控服务端(Provider)和消费端(Consumer)的使用数据的. 如: 服务端是什么,有多少接口,多少方法, 调用次数, 压力信息等. 客户端有多少, 调用过哪些服务端, 调用了多少次等.

执行流程

  • start: 启动Spring容器时,自动启动Dubbo的Provider

  • register: Dubbo的Provider在启动后自动会去注册中心注册内容.注册的内容包括:

    • Provider的 IP

    • Provider 的端口.

    • Provider 对外提供的接口列表.哪些方法.哪些接口类

    • Dubbo 的版本.

    • 访问Provider的协议.

  • subscribe: 订阅.当Consumer启动时,自动去Registry获取到所已注册的服务的信息.

  • notify: 通知.当Provider的信息发生变化时, 自动由Registry向Consumer推送通知.

  • invoke: 调用. Consumer 调用Provider中方法

    • 同步请求.消耗一定性能.但是必须是同步请求,因为需要接收调用方法后的结果.

  • count:次数. 每隔2分钟,provoider和consumer自动向Monitor发送访问次数.Monitor进行统计.

协议

Dubbo协议(官方推荐协议)

优点:

采用NIO复用单一长连接,并使用线程池并发处理请求,减少握手和加大并发效率,性能较好(推荐使用)

缺点:

大文件上传时,可能出现问题(不使用Dubbo文件上传)

RMI(Remote Method Invocation)协议

优点:

JDK自带的能力。可与原生RMI互操作,基于TCP协议

缺点:

偶尔连接失败.

Hessian协议

优点:

可与原生Hessian互操作,基于HTTP协议

缺点:

需hessian.jar支持,http短连接的开销大

注册中心

Zookeeper(官方推荐)

优点:

支持分布式.很多周边产品.

缺点:

受限于Zookeeper软件的稳定性.Zookeeper专门分布式辅助软件,稳定较优

Multicast

优点:

去中心化,不需要单独安装软件.

缺点:

2.2.1 Provider和Consumer和Registry不能跨机房(路由)

Redis

优点:

支持集群,性能高

缺点:

要求服务器时间同步.否则可能出现集群失败问题.

Simple

优点:

标准RPC服务.没有兼容问题

缺点:

不支持集群.

组件选型及成熟度

http://dubbo.apache.org/zh-cn/docs/user/maturity.html

功能成熟度

      
FeatureMaturityStrengthProblemAdviseUser
并发控制Tested并发控制 试用 
连接控制Tested连接数控制 试用 
直连提供者Tested点对点直连服务提供方,用于测试 测试环境使用Alibaba
分组聚合Tested分组聚合返回值,用于菜单聚合等服务特殊场景使用可用于生产环境 
参数验证Tested参数验证,JSR303验证框架集成对性能有影响试用LaiWang
结果缓存Tested结果缓存,用于加速请求 试用 
泛化引用Stable泛化调用,无需业务接口类进行远程调用,用于测试平台,开放网关桥接等 可用于生产环境Alibaba
泛化实现Stable泛化实现,无需业务接口类实现任意接口,用于Mock平台 可用于生产环境Alibaba
回声测试Tested回声测试 试用 
隐式传参Stable附加参数 可用于生产环境 
异步调用Tested不可靠异步调用 试用 
本地调用Tested本地调用 试用 
参数回调Tested参数回调特殊场景使用试用Registry
事件通知Tested事件通知,在远程调用执行前后触发 试用 
本地存根Stable在客户端执行部分逻辑 可用于生产环境Alibaba
本地伪装Stable伪造返回结果,可在失败时执行,或直接执行,用于服务降级需注册中心支持可用于生产环境Alibaba
延迟暴露Stable延迟暴露服务,用于等待应用加载warmup数据,或等待spring加载完成 可用于生产环境Alibaba
延迟连接Tested延迟建立连接,调用时建立 试用Registry
粘滞连接Tested粘滞连接,总是向同一个提供方发起请求,除非此提供方挂掉,再切换到另一台 试用Registry
令牌验证Tested令牌验证,用于服务授权需注册中心支持试用 
路由规则Tested动态决定调用关系需注册中心支持试用 
配置规则Tested动态下发配置,实现功能的开关需注册中心支持试用 
访问日志Tested访问日志,用于记录调用信息本地存储,影响性能,受磁盘大小限制试用 
分布式事务ResearchJTA/XA三阶段提交事务不稳定不可用 

策略成熟度

FeatureMaturityStrengthProblemAdviseUser
Zookeeper注册中心Stable支持基于网络的集群方式,有广泛周边开源产品,建议使用dubbo-2.3.3以上版本(推荐使用)依赖于Zookeeper的稳定性可用于生产环境 
Redis注册中心Stable支持基于客户端双写的集群方式,性能高要求服务器时间同步,用于检查心跳过期脏数据可用于生产环境 
Multicast注册中心Tested去中心化,不需要安装注册中心依赖于网络拓扑和路由,跨机房有风险小规模应用或开发测试环境 
Simple注册中心TestedDogfooding,注册中心本身也是一个标准的RPC服务没有集群支持,可能单点故障试用 
FeatureMaturityStrengthProblemAdviseUser
Simple监控中心Stable支持JFreeChart统计报表没有集群支持,可能单点故障,但故障后不影响RPC运行可用于生产环境 
FeatureMaturityStrengthProblemAdviseUser
Dubbo协议Stable采用NIO复用单一长连接,并使用线程池并发处理请求,减少握手和加大并发效率,性能较好(推荐使用)在大文件传输时,单一连接会成为瓶颈可用于生产环境Alibaba
Rmi协议Stable可与原生RMI互操作,基于TCP协议偶尔会连接失败,需重建Stub可用于生产环境Alibaba
Hessian协议Stable可与原生Hessian互操作,基于HTTP协议需hessian.jar支持,http短连接的开销大可用于生产环境 
FeatureMaturityStrengthProblemAdviseUser
Netty TransporterStableJBoss的NIO框架,性能较好(推荐使用)一次请求派发两种事件,需屏蔽无用事件可用于生产环境Alibaba
Mina TransporterStable老牌NIO框架,稳定待发送消息队列派发不及时,大压力下,会出现FullGC可用于生产环境Alibaba
Grizzly TransporterTestedSun的NIO框架,应用于GlassFish服务器中线程池不可扩展,Filter不能拦截下一Filter试用 
FeatureMaturityStrengthProblemAdviseUser
Hessian SerializationStable性能较好,多语言支持(推荐使用)Hessian的各版本兼容性不好,可能和应用使用的Hessian冲突,Dubbo内嵌了hessian3.2.1的源码可用于生产环境Alibaba
Dubbo SerializationTested通过不传送POJO的类元信息,在大量POJO传输时,性能较好当参数对象增加字段时,需外部文件声明试用 
Json SerializationTested纯文本,可跨语言解析,缺省采用FastJson解析性能较差试用 
Java SerializationStableJava原生支持性能较差可用于生产环境 
FeatureMaturityStrengthProblemAdviseUser
Javassist ProxyFactoryStable通过字节码生成代替反射,性能比较好(推荐使用)依赖于javassist.jar包,占用JVM的Perm内存,Perm可能要设大一些:java -XX:PermSize=128m可用于生产环境Alibaba
Jdk ProxyFactoryStableJDK原生支持性能较差可用于生产环境 
FeatureMaturityStrengthProblemAdviseUser
Failover ClusterStable失败自动切换,当出现失败,重试其它服务器,通常用于读操作(推荐使用)重试会带来更长延迟可用于生产环境Alibaba
Failfast ClusterStable快速失败,只发起一次调用,失败立即报错,通常用于非幂等性的写操作如果有机器正在重启,可能会出现调用失败可用于生产环境Alibaba
Failsafe ClusterStable失败安全,出现异常时,直接忽略,通常用于写入审计日志等操作调用信息丢失可用于生产环境Monitor
Failback ClusterTested失败自动恢复,后台记录失败请求,定时重发,通常用于消息通知操作不可靠,重启丢失可用于生产环境Registry
Forking ClusterTested并行调用多个服务器,只要一个成功即返回,通常用于实时性要求较高的读操作需要浪费更多服务资源可用于生产环境 
Broadcast ClusterTested广播调用所有提供者,逐个调用,任意一台报错则报错,通常用于更新提供方本地状态速度慢,任意一台报错则报错可用于生产环境 
FeatureMaturityStrengthProblemAdviseUser
Random LoadBalanceStable随机,按权重设置随机概率(推荐使用)在一个截面上碰撞的概率高,重试时,可能出现瞬间压力不均可用于生产环境Alibaba
RoundRobin LoadBalanceStable轮询,按公约后的权重设置轮询比率存在慢的机器累积请求问题,极端情况可能产生雪崩可用于生产环境 
LeastActive LoadBalanceStable最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差,使慢的机器收到更少请求不支持权重,在容量规划时,不能通过权重把压力导向一台机器压测容量可用于生产环境 
ConsistentHash LoadBalanceStable一致性Hash,相同参数的请求总是发到同一提供者,当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动压力分摊不均可用于生产环境 
FeatureMaturityStrengthProblemAdviseUser
条件路由规则Stable基于条件表达式的路由规则,功能简单易用有些复杂多分支条件情况,规则很难描述可用于生产环境Alibaba
脚本路由规则Tested基于脚本引擎的路由规则,功能强大没有运行沙箱,脚本能力过于强大,可能成为后门试用 
FeatureMaturityStrengthProblemAdviseUser
Spring ContainerStable自动加载META-INF/spring目录下的所有Spring配置 可用于生产环境Alibaba
Jetty ContainerStable启动一个内嵌Jetty,用于汇报状态大量访问页面时,会影响服务器的线程和内存可用于生产环境Alibaba
Log4j ContainerStable自动配置log4j的配置,在多进程启动时,自动给日志文件按进程分目录用户不能控制log4j的配置,不灵活可用于生产环境Alibaba

 

zookeeper安装

 

安装jdk

  • rpm -ivh jdk-8u131-linux-x64.rpm

  • java –version 检查是否成功

安装Zookeeper

下载 http://zookeeper.apache.org/ 并上传解压缩

配置zookeeper环境变量

修改文件 vi /etc/profile 追加内容

在path后追加/usr/local/zookeeper/bin

注意中间间隔是: 冒号

export PATH=$PATH:/usr/local/hadoop/bin:/usr/local/hadoop/sbin:/usr/local/zo
​
okeeper/bin

source /etc/profile 重新加载配置

修改zoo.cfg

重命名zoo_sample.cfg 为zoo.cfg

默认加载配置文件会找zoo.cfg这个文件

修改配置文件

vi /usr/local/zookeeper/conf/zoo.cfg

创建数据存放目录

Mkdir /data/zookeeper

创建Myid文件,并写入服务器编号

 

注意:这里写入myid文件的编号和接下来要配置的服务器列表编号一一对应,每台服务器配置的编号也应该不一样。

Myid文件里只有一个数字 1

创建好的这个目录用于存储zookeeper产生的数据

修改datadir为刚才我们创建的目录

dataDir=/data/zookeeper

在最后面加入集群服务器列表

server.1=192.168.2.51:2888:3888
​
server.2=cm02:2888:3888
​
server.3=cm03:2888:3888

配置的服务器集群个数建议是奇数的

半数以上节点存活,就可以对外提供服务

其中 server.x 这里的数字编号 就是我们的myid里写入的数字

Cm01是主机名或ip地址

接下来是对外通讯端口和内部选举端口

启动

zkServer.sh start 命令启动一台zookeeper服务器

没报错的话 使用jps看一下进程

 

QuorumPeerMain是zookeeper的主进程

通过status命令可以查看服务器运行状态

 

 

注意:当我们使用集群模式启动zookeeper的时候,由于我们只启动了一台服务器,集群总共3台,没有满足zookeeper半数以上节点运行原则,所以服务虽然起来了,但是没有办法对外提供服务。

这时我们需要启动第二台服务器

 

Dubbo Hello World

 

环境

SpringBoot + dubbo

Pom.xml 依赖

​
        <!-- Aapche Dubbo -->
​
​
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>${dubbo.version}</version>
        </dependency>
​
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo</artifactId>
            <version>${dubbo.version}</version>
        </dependency>
​
​
        <!-- https://mvnrepository.com/artifact/org.apache.curator/curator-framework -->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>4.2.0</version>
        </dependency>
​
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>4.2.0</version>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.zookeeper</groupId>
                    <artifactId>zookeeper</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
​
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.14</version>
        </dependency>
    </dependencies>

 

服务提供方 provider

配置文件

server.port=8081
​
spring.application.name=DemoProvider
dubbo.scan.base-packages=com.msb.db1.service
​
dubbo.protocol.name=dubbo
dubbo.protocol.port=666
dubbo.protocol.host=192.168.101.106
​
dubbo.registry.address=zookeeper://192.168.150.13:2181

服务接口

public interface DemoService {
    String sayHello(String name);
}
​

接口实现

import org.apache.dubbo.config.annotation.Service;
import org.springframework.stereotype.Component;
​
@Service(version = "1.0.0" ,timeout = 10000, interfaceClass = DemoService.class)
@Component
public class DemoServiceImpl implements DemoService {
​
    @Override
    public String sayHello(String name) {
        // TODO Auto-generated method stub
        System.out.println("来啦~~~!");
        return "hello:" + name;
    }
}

服务消费方 customer

配置

spring.application.name=DemoCustomer
dubbo.scan.base-packages=com.msb.db1.service
​
dubbo.registry.address=zookeeper://192.168.150.13:2181
​

自动注入

	@Reference(version = "1.0.0")
	DemoService serv;
	

接口

public interface DemoService {

    String sayHello(String name);

}

 

 

本地存根(Stub)

服务端的骨架对象(Skeleton)

 

Dubbo 02 微信开发

Dubbo Admin

https://github.com/apache/dubbo-admin

 

原系统微服务改造

mvc层排除数据源检查

Application 入口程序添加

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})

 

新增微信接口微服务

功能:微信登录

前置条件:微信开放平台

https://open.weixin.qq.com/

可以获取snsapi_login

开发测试环境:公众号

公众号(公众平台)获取的scope只包括两种:snsapi_base 和snsapi_userinfo

 

环境搭建

获取测试账号

https://mp.weixin.qq.com

注册登录后使用测试账号开发

反向代理服务器

主要用于开发中内网穿透

http://www.ngrok.cc/

http://www.natapp.cc/

API

微信公众平台开发者文档

https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432

微信开放平台(公众号第三方平台开发)

https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&lang=zh_CN

微信小程序开发文档

https://developers.weixin.qq.com/miniprogram/dev/framework/

微信商户服务中心

https://mp.weixin.qq.com/cgi-bin/readtemplate?t=business/faq_tmpl&lang=zh_CN

微信支付商户平台开发者文档

https://pay.weixin.qq.com/wiki/doc/api/index.html

微信支付H5

https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_1

微信支付代扣费

https://pay.weixin.qq.com/wiki/doc/api/pap.php?chapter=17_1

微信支付单品优惠

https://pay.weixin.qq.com/wiki/doc/api/danpin.php?chapter=9_201&index=3

开发框架

https://github.com/liyiorg/weixin-popular

  • TokenAPI access_token 获取

  • MediaAPI 多媒体上传下载(临时素材)

  • MaterialAPI 永久素材

  • MenuAPI 菜单、个性化菜单

  • MessageAPI 信息发送(客服消息、群发消息、模板消息)

  • PayMchAPI 支付订单、红包、企业付款、委托代扣、代扣费(商户平台版)、分账

  • QrcodeAPI 二维码

  • SnsAPI 网签授权

  • UserAPI 用户管理、分组、标签、黑名单

  • ShorturlAPI 长链接转短链接

  • TicketAPI JSAPI ticket

  • ComponentAPI 第三方平台开发

  • CallbackipAPI 获取微信服务器IP地址

  • ClearQuotaAPI 接口调用频次清零

  • PoiAPI 微信门店 @Moyq5 (贡献)

  • CardAPI 微信卡券 @Moyq5 (贡献)Shak

  • earoundAPI 微信摇一摇周边 @Moyq5 (贡献)

  • DatacubeAPI 数据统计 @Moyq5 (贡献)

  • CustomserviceAPI 客服功能 @ConciseA (贡献)

  • WxaAPI 微信小程序

  • WxopenAPI 微信小程序

  • CommentAPI 文章评论留言

  • OpenAPI 微信开放平台帐号管理

  • BizwifiAPI 微信连WiFi

  • ScanAPI 微信扫一扫

  • SemanticAPI 微信智能

<dependency>
  <groupId>com.github.liyiorg</groupId>
  <artifactId>weixin-popular</artifactId>
  <version>2.8.28</version>
</dependency>

入口层 -> 域名与高并发

在入口层 加入CDN技术可以提高用户响应时间 让系统能够承受更高并发,分发请求

尤其对 全网加速(海外用户)效果明显

 

 

域名

DNS

domain name system

DNS是应用层协议,事实上他是为其他应用层协议工作的,包括不限于HTTP和SMTP以及FTP,用于将用户提供的主机名解析为ip地址。

dns集群

img

CDN

img

微信开发

私服验证

 

菜单管理

创建菜单

{
    "button": [
        {
            "type": "click", 
            "name": "今日歌曲", 
            "key": "V1001_TODAY_MUSIC"
        }, 
        {
            "name": "菜单", 
            "sub_button": [
                {
                    "type": "view", 
                    "name": "搜索", 
                    "url": "http://www.soso.com/"
                }, 
                {
                    "type": "miniprogram", 
                    "name": "wxa", 
                    "url": "http://mp.weixin.qq.com", 
                    "appid": "wx286b93c14bbf93aa", 
                    "pagepath": "pages/lunar/index"
                }, 
                {
                    "type": "click", 
                    "name": "赞一下我们", 
                    "key": "V1001_GOOD"
                }
            ]
        }
    ]
}

 

消息回复

文本

XMLTextMessage xmlTextMessage = new XMLTextMessage(eventMessage.getFromUserName(), eventMessage.getToUserName(), "hi");
​
xmlTextMessage.outputStreamWrite(outputStream);

String mediaId= "YiHQtRD_fDKEG3-yTOwiGWlqv56-SUW5vfEDeEuAKx9a78337LKlSUmI4T-Cj8ij";
XMLImageMessage xmlImageMessage = new XMLImageMessage(eventMessage.getFromUserName(),eventMessage.getToUserName(),mediaId);
xmlImageMessage.outputStreamWrite(outputStream);

连接

​
XMLTextMessage xmlTextMessage2 = new XMLTextMessage(eventMessage.getFromUserName(), eventMessage.getToUserName(), "请先<a href='"+wxConf.getAppDomain()+"/h5/account/register'>完善一下信息</a>");
    

 

    TemplateMessage msg = new TemplateMessage();
​
        msg.setTouser("oStlBwHto08mKRIVUod5IHyevJyE");
        msg.setUrl("http://baidu.com");
        msg.setTemplate_id("gj4jA7HoS-1bmGyBK8VedBBQAXAboRJfWxUpbA8HlvM");
​
        LinkedHashMap<String, TemplateMessageItem> items = new LinkedHashMap<>();
​
        // 填充模板内容
        items.put("content", new TemplateMessageItem(" 宝宝,你好。", "#000000"));
        msg.setData(items);
​
        // 发送提醒
        MessageAPI.messageTemplateSend(TokenManager.getToken(wxConf.getAppID()), msg);
​

Dubbo03restful风格的API根路径协议版本用HTTP协议里的动词来实现资源的增删改查用例单个资源资源集合响应结果swagger(丝袜哥)OpenAPI资源官网 在线编辑器编写API文档整合SpringBoot 官方依赖第三方依赖引入启用注解分组实体模型接口方法

Dubbo03

 

restful风格的API

Representational State Transfer,资源表现层状态转换

根路径

mashibing.com

协议

http://

版本

v1

可以直接写在URL上,或者写在header中传递“Accept-Version: v2”

 @RequestMapping(headers = "Accept-Version=v2",value = "models",method = RequestMethod.GET)

 

 

用HTTP协议里的动词来实现资源的增删改查

GET 用来获取资源,
POST 用来新建资源(也可以用于更新资源)。
DELETE 用来删除资源。 
UPDATE http://api.chesxs.com/v1/fence 更新围栏信息 

用例

单个资源

http://mashibing.com/api/v1/Users/1 使用Get方法获取id是1的用户数据

         正确:GET /model/models/{id}        #获取单个资源
​
         正确:POST /model/models            #创建单个资源
​
         正确:PUT /model/models/{id}        #更新单个资源
​
         正确:DELETE /model/models/{id}   #删除单个资源
​
         正确:PATCH /model/models/{id}   #更新单个资源(只传差异)
​
         正确:GET /model/configRuleFile    #获取单个资源(如果仅有一个值时,应采用单数方式)

返回结果:

如果指定的资源并不存在,那么应该返回404 Not Found状态,否则应该返回200 OK状态码

资源集合

对于资源集合,支持以下URL

   正确: GET /model/models                             #获取资源列表
​
   正确: GET /model/models?ids={ids}             #批量获取资源列表
​
   正确: DELETE /model/models?ids={ids}       #批量删除资源列表
​
   返回结果:

如果列表为空,则应该空数组

 

响应结果

 响应状态码含义
成功200调用成功
 201创建成功
 204执行成功,但无返回值
失败400无效请求
 401没有登录
 403没有权限
 404请求的资源不存在
 500服务内部错误

swagger(丝袜哥)

Swagger是一个简单但功能强大的API表达工具。它具有地球上最大的API工具生态系统,数以千计的开发人员,使用几乎所有的现代编程语言,都在支持和使用Swagger。使用Swagger生成API,我们可以得到交互式文档,自动生成代码的SDK以及API的发现特性等。

OpenAPI

OpenAPI规范是Linux基金会的一个项目,试图通过定义一种用来描述API格式或API定义的语言,来规范RESTful服务开发过程。OpenAPI规范帮助我们描述一个API的基本信息

比如:

  • 有关该API的一般性描述

  • 可用路径(/资源)

  • 在每个路径上的可用操作(获取/提交...)

  • 每个操作的输入/输出格式

根据OpenAPI规范编写的二进制文本文件,能够像代码一样用任何VCS工具管理起来一旦编写完成,API文档可以作为:

  • 需求和系统特性描述的根据

  • 前后台查询、讨论、自测的基础

  • 部分或者全部代码自动生成的根据

  • 其他重要的作用,比如开放平台开发者的手册...

资源

官网

https://swagger.io/

在线编辑器

http://editor.swagger.io/

 

编写API文档

我们可以选择使用JSON或者YAML的语言格式来编写API文档

swagger: '2.0'
info:
  version: 1.0.0
  title: mashibing.com api
  description: 马老师的官网接口
  contact:
    name: yiming
    url: http://mashibing.com
    email: 888@qqq.com
  license:
    name: MIT
    url: http://opensource.org/licenses/MIT
schemes: 
  - http
  
host: mashibing.com
basePath: /api/v1
​
paths:
  /user/{userid}:
    get:
      summary: 获取一个用户
      description: 根据id获取用户信息
      parameters: 
        - name: userid
          in: path
          required: true
          description: 用户id
          type: string
      responses:
        200:
          description: OK
    
  /user:
    get:
      summary: 返回List 包含所有用户
      description: 返回List 包含所有用户
      parameters:
          - name: pageSize
            in: query
            description: 每页显示多少
            type: integer
          - name: pageNum
            in: query
            description: 当前第几页
            type: integer
      
      responses:
        200:
          description: OK
          
          schema:
            type: array
            items: 
              required:
                - username
              properties:
                username:
                  type: string
                password:
                  type: string    
 

整合SpringBoot

官方依赖

<dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <version>2.2.2</version>
</dependency>
<dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
        <version>2.2.2</version>
</dependency>
<dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-core-asl</artifactId>
        <version>1.9.13</version>
</dependency>

第三方

https://github.com/SpringForAll/spring-boot-starter-swagger

依赖引入

<dependency>
    <groupId>com.spring4all</groupId>
    <artifactId>swagger-spring-boot-starter</artifactId>
    <version>1.9.0.RELEASE</version>
</dependency>

启用注解

 

http://localhost:803//v2/api-docs

http://localhost:8080/swagger-ui.html

 

分组

 

swagger.docket.controller.title=group-controller
swagger.docket.controller.base-package=com.mashibing.springboot.controller
​
swagger.docket.restcontroller.title=group-restcontroller
swagger.docket.restcontroller.base-package=com.mashibing.springboot.controller.rest
​

实体模型

    @ApiModelProperty(value = "权限id", name = "id",dataType = "integer",required = true,example = "1")
    private Integer id;

接口方法

    @ApiOperation(value = "获取所有权限")
    @RequestMapping(value = "list",method = RequestMethod.GET)
    public List<Permission> list() {
        
        return permissionSrv.findAll();
    }
​
​
    @ApiOperation(value = "添加权限")
    @RequestMapping("update")
    public RespStat update(@ApiParam(name="permission",required = true, example = "{json}",value = "权限对象") @RequestBody Permission permission) {
        
        System.out.println("permission:" + ToStringBuilder.reflectionToString(permission));
        permissionSrv.update(permission);
        return RespStat.build(200);
    }

接口类描述

​
@Api(value = "用户权限管理",tags={"用户操作接口"})

Dubbo 04

服务化最佳实践

分包

建议将服务接口、服务模型、服务异常等均放在 API 包中,因为服务模型和异常也是 API 的一部分,这样做也符合分包原则:重用发布等价原则(REP),共同重用原则(CRP)。

如果需要,也可以考虑在 API 包中放置一份 Spring 的引用配置,这样使用方只需在 Spring 加载过程中引用此配置即可。配置建议放在模块的包目录下,以免冲突,如:com/alibaba/china/xxx/dubbo-reference.xml

Maven 聚合项目改造

公用的接口、工具类、实体类等抽取出API项目独立维护更新

每次更新后需要install

粒度

服务接口尽可能大粒度,每个服务方法应代表一个功能,而不是某功能的一个步骤,否则将面临分布式事务问题,Dubbo 暂未提供分布式事务支持。

服务接口建议以业务场景为单位划分,并对相近业务做抽象,防止接口数量爆炸。

不建议使用过于抽象的通用接口,如:Map query(Map),这样的接口没有明确语义,会给后期维护带来不便。

版本

每个接口都应定义版本号,为后续不兼容升级提供可能,如: <dubbo:service interface="com.xxx.XxxService" version="1.0" />

建议使用两位版本号,因为第三位版本号通常表示兼容升级,只有不兼容时才需要变更服务版本。

当不兼容时,先升级一半提供者为新版本,再将消费者全部升为新版本,然后将剩下的一半提供者升为新版本。

兼容性

服务接口增加方法,或服务模型增加字段,可向后兼容,删除方法或删除字段,将不兼容,枚举类型新增字段也不兼容,需通过变更版本号升级。

枚举值

如果是完备集,可以用 Enum,比如:ENABLE, DISABLE

如果是业务种类,以后明显会有类型增加,不建议用 Enum,可以用 String 代替。

如果是在返回值中用了 Enum,并新增了 Enum 值,建议先升级服务消费方,这样服务提供方不会返回新值。

如果是在传入参数中用了 Enum,并新增了 Enum 值,建议先升级服务提供方,这样服务消费方不会传入新值。

序列化

服务参数及返回值建议使用 POJO 对象,即通过 setter, getter 方法表示属性的对象。

服务参数及返回值不建议使用接口,因为数据模型抽象的意义不大,并且序列化需要接口实现类的元信息,并不能起到隐藏实现的意图。

服务参数及返回值都必须是传值调用,而不能是传引用调用,消费方和提供方的参数或返回值引用并不是同一个,只是值相同,Dubbo 不支持引用远程对象。

异常

建议使用异常汇报错误,而不是返回错误码,异常信息能携带更多信息,并且语义更友好。

如果担心性能问题,在必要时,可以通过 override 掉异常类的 fillInStackTrace() 方法为空方法,使其不拷贝栈信息。

查询方法不建议抛出 checked 异常,否则调用方在查询时将过多的 try...catch,并且不能进行有效处理。

服务提供方不应将 DAO 或 SQL 等异常抛给消费方,应在服务实现中对消费方不关心的异常进行包装,否则可能出现消费方无法反序列化相应异常。

调用

不要只是因为是 Dubbo 调用,而把调用 try...catch 起来。try...catch 应该加上合适的回滚边界上。

Provider 端需要对输入参数进行校验。如有性能上的考虑,服务实现者可以考虑在 API 包上加上服务 Stub 类来完成检验。

在 Provider 端尽量多配置 Consumer 端属性

原因如下:

  • 作服务的提供方,比服务消费方更清楚服务的性能参数,如调用的超时时间、合理的重试次数等

  • 在 Provider 端配置后,Consumer 端不配置则会使用 Provider 端的配置,即 Provider 端的配置可以作为 Consumer 的缺省值 [1]。否则,Consumer 会使用 Consumer 端的全局设置,这对于 Provider 是不可控的,并且往往是不合理的

Provider 端尽量多配置 Consumer 端的属性,让 Provider 的实现者一开始就思考 Provider 端的服务特点和服务质量等问题。

建议在 Provider 端配置的 Consumer 端属性

  1. timeout:方法调用的超时时间

  2. retries:失败重试次数,缺省是 2

  3. loadbalance:负载均衡算法,缺省是随机 random + 权重。还可以配置轮询 roundrobin、最不活跃优先 leastactive 和一致性哈希 consistenthash

  4. actives:消费者端的最大并发调用限制,即当 Consumer 对一个服务的并发调用到上限后,新调用会阻塞直到超时,在方法上配置 dubbo:method 则针对该方法进行并发限制,在接口上配置 dubbo:service,则针对该服务进行并发限制

  5. executes服务提供方可以使用的最大线程数

在 Provider 端配置合理的 Provider 端属性

建议在 Provider 端配置的 Provider 端属性有:

  1. threads:服务线程池大小

  2. executes:一个服务提供者并行执行请求上限,即当 Provider 对一个服务的并发调用达到上限后,新调用会阻塞,此时 Consumer 可能会超时。在方法上配置 dubbo:method 则针对该方法进行并发限制,在接口上配置 dubbo:service,则针对该服务进行并发限制

###

项目中多个模块间公共依赖的版本号、scope的控制

配置 Dubbo 缓存文件

提供者列表缓存文件:

<dubbo:registry file=”${user.home}/output/dubbo.cache” />
dubbo.registry.file=c:/output/dubbo.cache

 

注意:

  1. 可以根据需要调整缓存文件的路径,保证这个文件不会在发布过程中被清除;

  2. 如果有多个应用进程,请注意不要使用同一个文件,避免内容被覆盖;

该文件会缓存注册中心列表和服务提供者列表。配置缓存文件后,应用重启过程中,若注册中心不可用,应用会从该缓存文件读取服务提供者列表,进一步保证应用可靠性。

启动检查

Dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,以便上线时,能及早发现问题,默认 check="true"

可以通过 check="false" 关闭检查,比如,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动。

另外,如果你的 Spring 容器是懒加载的,或者通过 API 编程延迟引用服务,请关闭 check,否则服务临时不可用时,会抛出异常,拿到 null 引用,如果 check="false",总是会返回引用,当服务恢复时,能自动连上。

示例

通过 spring 配置文件

关闭某个服务的启动时检查 (没有提供者时报错):

<dubbo:reference interface="com.foo.BarService" check="false" />

关闭所有服务的启动时检查 (没有提供者时报错):

<dubbo:consumer check="false" />

关闭注册中心启动时检查 (注册订阅失败时报错):

<dubbo:registry check="false" />

通过 dubbo.properties

dubbo.reference.com.foo.BarService.check=false
dubbo.reference.check=false
dubbo.consumer.check=false
dubbo.registry.check=false

通过 -D 参数

java -Ddubbo.reference.com.foo.BarService.check=false
java -Ddubbo.reference.check=false
java -Ddubbo.consumer.check=false 
java -Ddubbo.registry.check=false

配置的含义

dubbo.reference.check=false,强制改变所有 reference 的 check 值,就算配置中有声明,也会被覆盖。

dubbo.consumer.check=false,是设置 check 的缺省值,如果配置中有显式的声明,如:<dubbo:reference check="true"/>,不会受影响。

dubbo.registry.check=false,前面两个都是指订阅成功,但提供者列表是否为空是否报错,如果注册订阅失败时,也允许启动,需使用此选项,将在后台定时重试。

 

 

 

 

metrics

当我们需要为某个系统某个服务做监控、做统计,就需要用到Metrics。

延迟暴露

@Service(version = "1.0.0" ,timeout = 10000, interfaceClass = IAccountService.class,delay = 1000000)

 

Telnet治理服务

显示服务

ls

  1. ls: 显示服务列表

  2. ls -l: 显示服务详细信息列表

  3. ls XxxService: 显示服务的方法列表

  4. ls -l XxxService: 显示服务的方法详细信息列表

 

ps

  1. ps: 显示服务端口列表

  2. ps -l: 显示服务地址列表

  3. ps 20880: 显示端口上的连接信息

  4. ps -l 20880: 显示端口上的连接详细信息

服务调用

引入fastjson依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.51</version>
</dependency>

 

invoke com.mashibing.springboot.service.IRoleService:1.0.0.findById(8)

Telnet命令扩展

http://dubbo.apache.org/zh-cn/docs/dev/impls/telnet-handler.html

QOS 模块手动上下线

相关参数说明

QoS提供了一些启动参数,来对启动进行配置,他们主要包括:

参数说明默认值
qosEnable是否启动QoStrue
qosPort启动QoS绑定的端口22222
qosAcceptForeignIp是否允许远程访问false

注意,从2.6.4/2.7.0开始,qosAcceptForeignIp默认配置改为false,如果qosAcceptForeignIp设置为true,有可能带来安全风险,请仔细评估后再打开。

新版本的 telnet 端口 与 dubbo 协议的端口是不同的端口,默认为 22222,可通过配置文件dubbo.properties修改:

dubbo.application.qos.port=33333

或者通过设置 JVM 参数:

-Ddubbo.application.qos.port=33333

默认情况下,dubbo 接收任何主机发起的命令,可通过配置文件dubbo.properties 修改:

dubbo.application.qos.accept.foreign.ip=false

或者通过设置 JVM 参数:

-Ddubbo.application.qos.accept.foreign.ip=false

##

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值