集群模式下,调用服务失败时的容错机制
1、默认是failover,重试机制,默认是两次。通常可用于读操作
2、failfast,快速失败模式,当调用失败时候就报错,通常用于写操作
3、failsafe,失败安全模式,当调用失败时直接忽略。通常用于写入日志等操作。
默认情况下,是failover模式,这时候可以只配retries="0"或者“2”等,来实现是重试几次还是重试0次(这个时候就是failfast模式)
1、随机策略。根据权重设置随机概率,这是默认策略
2、轮询策略。这会导致机子慢的服务器积累请求的问题
3、最小活跃调用数,使慢的机子收到更少的请求
4、hash一致性,相同的请求总是会调用同一台机子的服务器。一般默认是第一个参数的hash值
##线程模型
如果事件处理的逻辑能够在io线程中迅速处理完,就在io线程中处理,否则放到线程池中。
dispatcher:
all :所有的消息都派发到线程池,包括请求、响应,连上事件、断开事件,心跳等;
direct:直接在io线程上处理;
message:请求响应消息派发到线程池,其他的断开连接事件,心跳等在io上处理;
execution:只有请求消息派发到线程池
connection:在io线程上,将连接断开事件放入队列,有序逐个执行,其他的消息派发到线程池
threadpool:
fixed: 固定大小线程池,启动时建立线程,不关闭,一直持有,通过threads设置数量
cached:缓存线程池,空闲一分钟自动删除;
limited:可伸缩线程池,值增加不收缩
如果使用了direct,而发现一个请求长时间等待,其他的请求也因此阻塞时,应该考虑在消费端设置connections的数量或者服务端的accepts的数量。io线程的大小默认是cpu数量+1。大概就是这三个原因
inux 用户线程数限制导致的 java.lang.OutOfMemoryError: unable to create new native thread异常
系统默认最大的线程数为1024个
[root@edu-provider-01 ~]# cat /etc/security/limits.d/90-nproc.conf
Default limit for number of user’s processes to prevent
accidental fork bombs.
See rhbz #432903 for reasoning.
soft nproc 1024
root soft nproc unlimited
[root@edu-provider-01 ~]# vi /etc/security/limits.d/90-nproc.conf
调整时要注意:
1、 尽量不要使用 root 用户来部署应用程序,避免资源耗尽后无法登录操作系统。
因为root用户默认没有限制线程数,如果线程过多,会使资源占用很多,导致不能关机,只能硬关机
2、 普通用户的线程数限制值要看可用物理内存容量来配置
[root@edu-provider-01 ~]# cat /proc/meminfo |grep MemTotal
MemTotal: 2941144 kB
[root@edu-provider-01 ~]# echo “2941144/128”|bc
22977
[root@edu-provider-01 ~]# ulimit -u
1024
[1]+ Stopped vi /etc/security/limits.d/90-nproc.conf
[root@edu-provider-01 ~]# vi /etc/security/limits.d/90-nproc.conf
[root@edu-provider-01 ~]# cat /etc/security/limits.d/90-nproc.conf
Default limit for number of user’s processes to prevent
accidental fork bombs.
See rhbz #432903 for reasoning.
soft nproc 12000
root soft nproc unlimited
[root@edu-provider-01 ~]#
计算方式:
default_nproc = total_memory/128K;
$ cat /proc/meminfo |grep MemTotal
$ echo “2941144/128”|bc
$ ulimit -u
ulimit -a # 显示目前资源限制的设定
ulimit -u # 用户最多可开启的程序数目
重启,使之生效:# reboot
在消费端
客户端调用服务端的摸个方法A,然后在服务端的方法中又反过来调用客户端的某个方法B,对于客户端来说,这个B就叫回调函数。这样,服务端就有机会调用客户端的方法,以便可以实现客户端的定制逻辑。比如我们的按钮事件,我们在按钮事件的回调方法里实现我们定制的逻辑(按钮事件触发后需要完成什么工作),然后按钮事件触发后,就会实现我们的定制逻辑。
步骤:
1、定义接口,作为服务端的一个变量存在。(或者这个接口将作为参数传递到服务端的方法中)
public interface EcgViewInterface {
void onError(Exception e);
void onShowMessage(String t,int i);
}
```
2、在服务端定义接口参数(或者方法中的参数),在服务端方法中调用此接口的方法。
```
public void AutoResize()
{
if (n_aStep == 1)
{
//波形的幅度小于画布高度,并且波形幅度的2倍大于画布高度,说明波形幅度合适,此时只要调整基线
if ((y_max - y_min) * 2 >= by && (y_max - y_min) <= by)
n_aStep = 2;
else
{
if (y_max - y_min >= by) //表示波形范围超过画布高度
{
change_nV = change_nV*2;
listener.onShowMessage(change_nV+"",1); //在这里进行接口回调
}
else if ((y_max - y_min) * 2 <= by) //如果波形幅度的两倍都小于画布高度,说明波形幅度过小,需要波形像素调整放大
{
change_nV = change_nV/2;
listener.onShowMessage(change_nV+"",1);
}
y_max = -3*by;
y_min =3*by;
return;
}
}
if (n_aStep == 2)
{
n_top = (by - (y_max + y_min)) / 2;
this.change_y += n_top * change_nV/ change_50n;
}
b_autoResize = false;
}
3、在客户端实现回调接口的实现,并将此接口传入服务端
private EcgViewInterface ecgViewListener=new EcgViewInterface() {
@Override
public void onError(Exception e) {
}
@Override
public void onShowMessage(String t, int i) {
Log.i("tag", "心电接口回调--》" + t);
if (i==0){
tv_ecg_cell_time.setText("时间:"+t+"ms/格");
}else if (i==1){
tv_ecg_cell_voltage.setText("电压:"+t+"mv/格");
}
}
};
然后传给服务器端
ecgWaveView1.setListener(ecgViewListener);
dubbo的参数回调,只需在在spring的配置文件中声明哪个参数是callback类型的即可。
1、先定义回调的接口
/**
* @author sks
*这个listener就是回调的接口。里面的方法就是客户端来实现的。
*/
public interface CallbackListener2 {
void onShowMessage(String t, int i);
}
2、定义服务端和客户端公用的接口,在接口中定义如何传入回调接口。
public interface CallbackService2 {
//在这里考虑如何传入listener。作为方法传入或者作为一个参数传入
//先考虑作为方法的参数传入
void addListener(CallbackListener2 listener2);
}
3、服务端实现CallbackService2接口。同时定义一个会调用回调接口的方法。这里为了简单,直接在构造方法中,定义一个每过5s都会调用回调接口的逻辑。
@Service
public class CallbackService2Impl implements CallbackService2 {
/**
*
*/
public CallbackService2Impl() {
super();
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
while (true) {
if (listener2!=null) {
listener2.onShowMessage("服务端回调客户端的方法", 0);
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
}
private CallbackListener2 listener2;
//在服务端某个方法中会用到回调接口。这里为了简单,直接在构造方法中实现
/* (non-Javadoc)
* @see cn.andy.dubbo.CallbackService2#addListener(cn.andy.dubbo.CallbackListener2)
* 服务端提供方法用户客户端传入回调接口
*/
@Override
public void addListener(CallbackListener2 listener2) {
// TODO Auto-generated method stub
this.listener2=listener2;
}
}
4、在xml配置文件中,对有回调接口参数的方法进行配置
5、在客户端的工程中,在java代码中
/*
* 客户端传递回调接口给服务端
*/
@RequestMapping("/user/getData4")
@ResponseBody
private String getData4(HttpServletRequest request){
callbackService2.addListener(new CallbackListener2() {
@Override
public void onShowMessage(String t, int i) {
// TODO Auto-generated method stub
System.out.println(t);
}
});
return "success2-->";
}
}
6、客户端的dubboxml文件正常配置callbackService2
7、结果
服务端回调客户端的方法
服务端回调客户端的方法
服务端回调客户端的方法
服务端回调客户端的方法
dubbo的事件通知:在调用之前、之后或者异常时会触发 oninvoke、onreturn和onthrow三个时间。这个和spring的aop功能比较类似。
在消费端:定义通知接口和实现类
public interface Notify {
public void onthrow(Throwable e,Object... args);
/**
* @param res
* @param args
*/
void onreturn(Object res, Object[] args);
}
@Component
public class NotifyImpl implements Notify {
/* (non-Javadoc)
* @see cn.andy.callback.Notify#onreturn()
*/
@Override
public void onreturn(Object res, Object... args) {
// TODO Auto-generated method stub
System.out.println("返回值:"+res);
for (Object object : args) {
System.out.println("参数:"+object);
}
}
/* (non-Javadoc)
* @see cn.andy.callback.Notify#onthrow(java.lang.Throwable)
*/
@Override
public void onthrow(Throwable e,Object... args) {
// TODO Auto-generated method stub
System.out.println("异常:"+e.getMessage());
for (Object object : args) {
System.out.println("异常参数:"+object);
}
}
}
在配置文件中进行配置
事件通知有一个注意点是:通知类必须在xml文件中手动实例化,而自动扫描的方式会报找不到notify’这个类实例的错误。
dubbo本地伪装用于当服务down之后,客户端不抛出异常,而是转而调用mock实现的逻辑。其中,mock类的实现要和接口放在一起!
public interface DataService {
int dubboTest(String id);
int dubboTest2(String id);
String getStringData();
}
然后是基于DataService实现的mock类,其命名是接口+Mock
public class DataServiceMock implements DataService{
/* (non-Javadoc)
* @see cn.andy.dubbo.DataService#dubboTest(java.lang.String)
*/
@Override
public int dubboTest(String id) {
// TODO Auto-generated method stub
return 10086;
}
/* (non-Javadoc)
* @see cn.andy.dubbo.DataService#dubboTest2(java.lang.String)
*/
@Override
public int dubboTest2(String id) {
// TODO Auto-generated method stub
return 10086;
}
/* (non-Javadoc)
* @see cn.andy.dubbo.DataService#getStringData()
*/
@Override
public String getStringData() {
// TODO Auto-generated method stub
return "mock result";
}
}
在服务端的dubbo的xml中进行mock配置
当服务端程序down了之后,客户端调用
@RequestMapping("/user/getStringData")
@ResponseBody
private String getStringData(HttpServletRequest request){
String data = dataservice.getStringData();
return "success2-->"+data;
}
结果是success2–>mock result。说明没有抛出异常,转而调用其mock的逻辑。
令牌验证是用来放在消费端避开注册中心通过直连方式连接消费端。通过在服务端设置token,如果消费程序没有通过token验证,就不能直连服务端。
1、在服务端,设置token。
2、在dubbo管控台,将此服务禁用。
3、在消费端调用服务端的程序前,先通过隐式传参,将token的值传进去,完成调用
RpcContext.getContext().setAttachment("token", "1234567");
String data = dataservice.getStringData();
如果没有 RpcContext.getContext().setAttachment(“token”, “1234567”);,那么会报错。显示invalied token。
https://my.oschina.net/lenglingx/blog/889662