java学习一个月了,没有什么进展,期间又是复习Linux,又是看Android,瞻前顾后,感觉自己真的是贪得无厌,
学习的东西广而不精,所以写出的文章也就只能泛泛而谈。五一小长假,哪里都没有去,也不想去,刚刚无聊刷新了下
朋友圈,朋友们不是在玩,就是在吃,突然一下子感觉自己老了许多。岁月真是把杀猪刀,夺走了我们的青春,但却无
法夺走我们的激情。
好好复习了!
在老师引领下,算是把人生中的第一个Java项目敲完了,感觉对于学习OOP的朋友,应该有所帮助,先做个笔记吧
等后期有时间再添些自己的Feature。
import javax.swing.JFrame;
/**
* 游戏窗口
* @author Manue1
* @version 1.0
*
*/
public class GameFrame extends JFrame{
private static final long serialVersionUID = 1L;
private Tetris tetris;
public GameFrame(){
tetris =new Tetris();
add(tetris);
setSize(530,580);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
public static void main(String[] args){
GameFrame frame =new GameFrame();
frame.setVisible(true);
frame.tetris.action(); //创建4个格子
}
}
2
3 import java.awt.image.BufferedImage;
4
5 /**
6 * 定义格子
7 * @author Manue1
8 */
9 public class Cell extends Object{
10 private int row; int col;
11 private BufferedImage image;
12
13 public Cell(int row, int col, BufferedImage image) {
14 super();
15 this.row = row;
16 this.col = col;
17 this.image = image;
18 }
19
20 public int getRow() {
21 return row;
22 }
23
24 public void setRow(int row) {
25 this.row = row;
26 }
27
28 public int getCol() {
29 return col;
30 }
31
32 public void setCol(int col) {
33 this.col = col;
34 }
35
36 public BufferedImage getImage() {
37 return image;
38 }
39
40 public void setImage(BufferedImage image) {
41 this.image = image;
42 }
43
44 @Override
45 public String toString() {
46 return "Cell [col=" + col + ", image=" + image + ", row=" + row + "]";
47 }
48
49
50 public void moveLeft(){
51 col--;
52 }
53 public void moveRight(){
54 col++;
55 }
56 public QQ5.0左侧滑动显示效果 - 小破孩123 阅读原文»
前三篇为大家介绍了如何实现简单的类QQ5.0左侧的侧滑效果,本篇我将带领大家一起探讨一下如何真正实现QQ5.0左侧的侧滑效果,对于本篇的内容与之前的三篇关联性很强,如果前三篇你已经完全掌握,对于这一篇相信也没有什么难处,本篇的重点在于通过Android3.0以后提供的属性动画实现上述显示特效。
开始之前首先给大家说句抱歉,前三篇由于我自己的编码问题,导致如果你还是以之前的代码设计时,会出现Menu的背景图没有填充整个屏幕,这个怎么解决呢?
在left_menu.xml中,将background修改为android:background="#0000";
activity_main.xml代码:
xmlns:tools="http://schemas.android.com/tools"
xmlns:hyman="http://schemas.android.com/apk/res/com.example.android_qq_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<com.example.menu.SlidingMenu
android:id="@+id/slidingMenu"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/img_frame_background"
hyman:rightPadding="100dp" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal"
>
<include layout="@layout/left_menu"/>"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/qq"
>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="切换按钮"
/>
</LinearLayout>
</LinearLayout>
</com.example.menu.SlidingMenu>
</RelativeLayout>
将背景图片添加蓝色标注处。
其他部分无需改变,下面我们开始分析如何通过属性动画来实现上述效果:
* 实现抽屉式侧滑效果
*/
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {//l相当于getScrollX()表示Menu左侧的偏移量
super.onScrollChanged(l, t, oldl, oldt);
/**
* 区别1:内容区域1.0~0.7 缩放的效果 scale : 1.0~0.0 0.7 + 0.3 * scale
*
* 区别2:菜单的偏移量需要修改
*
* 区别3:菜单的显示时有缩放以及透明度变化 缩放:0.7 ~1.0 1.0 - scale * 0.3 透明度 0.6 ~ 1.0
* 0.6+ 0.4 * (1- scale) ;
*
*/
//设置Menu的显示OR隐藏动画
float scroll = l * 1.0f /mMenuWidth;//1~0
ViewHelper.setTranslationX(mMenu, mMenuWidth*scroll*0.7f);
//设置Menu的透明度变化
float leftScale = 0.6f+ 0.4f * (1- scroll);
ViewHelper.setScaleX(mMenu, leftScale);
ViewHelper.setScaleY(mMenu, leftScale);
//设置Menu的缩放比例
float leftAlpha = 1.0f - scroll * 0.3f;
ViewHelper.setAlpha(mMenu, leftAlpha);
//设置Content的缩放中心
ViewHelper.setPivotX(mContent, 0);
ViewHelper.setPivotY(mContent, mContent.getHeight()/2);
//设置Content的透明度变化
float rightScale = 0.7f + 0.3f * scroll;
ViewHelper.setScaleX(mContent, rightScale);
ViewHelper.setScaleY(mContent, rightScale);
}
需要提示的就是对于Android3.0以下的系统,不支持属性动画效果,在这里我导入了一个包,大家如果需要可以留言。好了,到这里我们的侧滑效果就完全为大家实现了,请欣赏效果图:
本文链接:QQ5.0左侧滑动显示效果,转载请注明。
关于企业邮箱服务器经常被spamhaus反垃圾邮件组织拦截的排错方法分享
其实在企业邮件平台管理过程中,企业邮箱管理员经常会被各种各样的邮箱问题所困扰,而困扰最大的除了服务器规划不当带来的后期服务器维护的困难外,还有最致命也是最让邮件管理员着急的事情,那就是企业邮箱经常被一些国际反垃圾邮件组织列为黑名单,也许,很多人会在想,如果是列为了黑名单,那么直接进行申诉,释放就可以了,这个回答其实也勉强可以算是对的,但是从申诉到释放,其实也是需要等待一个时间的,那么这时出现大批量的用户反映,我个人认为这其实也是邮件平台不稳定的一个体现,做为管理员,则必须要了解被列为黑名单的根本原因,当然最核心的还是需要在规划邮件平台架构时,就能够合理规划系统结构及网络结构才能有一个更为稳定的邮件平台结构,在下面呢,我就分享一个较为不常见的典型案例。
在之前一段时间,在处理一些邮件技术支持工作时,遇到了企业邮箱服务器频繁被国际反垃圾联盟列为黑名单的问题,而且频率极高,基本一天至少3次,这其实从3次的意义来看,这已经不是单纯的服务器故障,很有可能我们对外部提供的公网邮件地址已经被反垃圾联盟盯上啦,那么我们是每天3次,甚至是凌晨也在向反垃圾联盟申诉呢?还是自己想想哪里出现了问题?当然,我相信,偶尔出一次被列黑名单,申诉后问题解决,那还是正常的,毕竟有时反垃圾联盟也会有误判嘛。而这次出现的问题,则很明显不是误判哦,所以还是需要找到根本原因的。
在这次故障中,我用了一个最为简单的方式,也是之前处理这类问题时的一个经验性方法,反查telnet其它公司的邮件服务器时,返回值是多少?这个返回值当然指你去telnet对端邮件服务器IP时,对端回显你的发起连接的IP是多少?
其实在当时有人就提出了质疑,你去telnet对端邮件平台有意义吗?当然是有意义的,从排查思路来看,Exchange服务器各项服务正常,网络链路通,那么还有哪里会有问题,如果有实施Exchange经验的话,会知道,最后一步那是进行端口映射。所以我们不妨来看看端口映射情况,在向网络工程师查询映射前,你不妨像我一样做下面这样一件事情。
1.在办公网平台下,telnet其它支持telnet 回显的邮件组织,查看回显回来什么地址。
2.在邮件网关或Exchange 器服务器上telnet支持telnet回显的,邮件组织,查看回显回来是什么地址。
为什么要做这2步呢?如果两者回显是不同地址还好,但是如果两者回显均为邮件网关地址呢?这就是有问题的,毕竟我们发布25端口一般也只是对邮件平台,而如果办公网随意一台机器telnet其它邮件组织邮件服务器,都是邮件网关地址,那么意味着什么,相信我们邮件管理员都很清楚的。
最终也通过网络映射看到并验证了我的分析结果,当时网络层面为了简单,直接把整个办公网地址25端口映射为了邮件网关公网地址,为此,我要求重新做了映射,保证邮件公网IP仅用于邮件网关,不得做于其它映射使用,调整映射服务器范围后,观察了1个月,没有再出现被反垃圾联盟拦截的问题。
以上也只是我在分析这类被国际反垃圾邮件联盟列为黑名单时的个列处理方法,希望对有类似问题的博友看完能有一些帮助。
本文出自 "笨鸟先飞" 博客,请务必保留此出处http://tingdongwang.blog.51cto.com/1056852/1640227
最近公司来了一个陕北的实习妹子,据说家里是开矿的,人长得一般,但很有气质。开矿的,当然钱很多了。以前在大学有个同学,家里是开油田的,有节毛概课,老师说西安的房价都是陕北人轰起来的,西安人都怨陕北人。我这个同学听了不开心了,周末直接在东西南北各买一套。牛逼啊,让你老师多嘴。这几天周围的同事心思都在这个姑娘身上,装作喝咖啡过去瞄一眼,或者站起来瞅瞅背影。IT爷们真的是空虚,IT界无美女啊,还是吉日嘎啦说的好,公司有美女,可以提升爷们的战斗力。
OK,今天我们来看一下新闻审核界面,本来这节是要说ueditor上传图片到mongoDB,但是最近实在精力有限,先放放,稍后再上博客。我们先看一下界面,提提神。
这个界面上面部分是查询,采用响应式布局方式。当在手机或者pad的浏览器上的时候,依然能够正常显示并使用。
OK,我们今天主要看的不是界面,还是看功能的实现。
首先先看一下查询功能,查询有个新闻类别的下拉列表,后台Action代码如下
[HttpGet] public JsonResult GetNewsTypeList() { List<NewsTypesEntity> newsTypeEntityList = NewsMngBiz.GetInstance().GetNewsTypes(); newsTypeEntityList.Insert(0, new NewsTypesEntity() { TransactionNumber = null, NewsTypeName = CommonResouce.DefaultSelectText }); return Json(newsTypeEntityList, JsonRequestBehavior.AllowGet); }
OK,接下来我们就要看界面了
@{ Layout = null; } <div ng-app="newsAuditModule" ng-controller="newsAuditController" id="div_newsAudit" class="panel panel-primary"> <div class="panel-heading"> <h3 class="panel-title"> <img class="img-panel-title" src="~/Images/Base/audit.png" /> <b>新闻审核</b> </h3> </div> <div class="panel-body"> <div class="row" style="line-height:30px"> <label for="newsTitle" class="col-sm-2 control-label">新闻标题</label> <div class="col-sm-10"> <input type="text" maxlength="100" class="form-control" id="newsTitle" ng-model="newsTitle" placeholder="请输入新闻标题查询"> </div> </div> <div class="row" style="margin-top: 5px; margin-bottom: 5px; line-height: 30px"> <label for="newsTitle" class="col-sm-2 control-label">新闻类别</label> <div class="col-sm-10"> <select id="newsTitle" class="form-control" ng-model="newsType"> @*<option value="">---请选择---</option>*@ <option ng-repeat="type in NewsTypeList" value="{{type.TransactionNumber}}">{{type.NewsTypeName}}</option> </select> </div> </div> <div class="row" style="line-height:30px"> <label for="newsTitle" class="col-sm-2 control-label">审核状态</label> <div class="col-sm-10"> <select id="newsTitle" class="form-control" ng-model="newsState"> <option value="">---请选择---</option> <option value="-1">未审核</option> <option value="0">未通过</option> <option value="1">通过</option> </select> </div> </div> <div class="row" style="margin-top:10px"> <div class="col-sm-3"> <button type="button" class="btn btn-primary btn-form-width" ng-click="getDataList()">查询</button> </div> </div> <div class="pre-scroll" style="margin-top:10px"> <table class="table table-bordered table-striped table-hover" ng-init="load()"> <tr style="background-color: #428bca; color: white"> <th><input type="checkbox" ng-model="isCheckAll" ng-change="setCheckState()"></th> <th>新闻标题</th> <th>新闻类别</th> <th>创建日期</th> <th>审核状态</th> <th>审核人</th> <th>审核日期</th> <th>操作</th> </tr> <tr ng-repeat="newsEntity in NewsList"> <td><input id="chk_{{newsEntity.TransactionNumber}}" type="checkbox" ng-model="newsEntity.IsChecked" /></td> <td title="{{newsEntity.Title}}">{{newsEntity.SubTitle}}</td> <td>{{newsEntity.InforType}}</td> <td>{{newsEntity.InDate.slice(6,-2)|date:'yyyy-MM-dd'}}</td> <td style="color:{{ newsEntity.Color }}">{{newsEntity.AuditStatus}}</td> <td>{{newsEntity.AuditUserName}}</td> <td>{{newsEntity.AuditDate.slice(6,-2)|date:'yyyy-MM-dd'}}</td> <td> <span style="cursor:pointer;"> <a href="#"><img title="浏览" alt="" src="~/Images/Base/preview.png" class="img-table-column" /></a> <a href="#"><img title="审核" ng-click="auditModalShow(newsEntity)" alt="" src="~/Images/Base/key.png" class="img-table-column" /></a> </span> </td> </tr> </table> </div> <div class="btn-group dropup"> <button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-expanded="false"> 批量操作<span class="caret"></span> </button> <ul class="dropdown-menu" role="menu"> <li><a href="#" ng-click="batchOperation('A')">批量通过</a></li> <li class="divider"></li> <li><a href="#" ng-click="batchOperation('D')">批量删除</a></li> </ul> </div> </div> <div class="modal fade" id="newAuditModal" tabindex="-1" role="dialog" aria-labelledby="auditModalTitle" aria-hidden="true" data-backdrop="static"> <div class="modal-dialog"> <div class="modal-content" style="width:550px"> <div class="modal-header" style="background-color: #009966;height:45px;line-height:45px"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true"> × </button> <h5 class="modal-title" id="auditModalTitle" style="color:white"> 新闻审核 </h5> </div> <div class="modal-body"> <div class="form-horizontal"> <div class="form-group"> <label class="col-md-3" for="labTitle">新闻标题:</label> <div class="col-md-9"> <label id="labTitle"></label> </div> </div> <div class="form-group"> <label class="col-md-3">审核结果:</label> <div class="col-md-9"> <input type="radio" name="radAuditResult" ng-change="setAuditResaonEditable()" value="1" checked ng-model="AuditResult"> 通过 <input type="radio" name="radAuditResult" ng-change="setAuditResaonEditable()" value="0" ng-model="AuditResult" style="margin-left:10px"> 不通过 </div> </div> <div class="form-group"> <label class="col-md-3" for="div_reason">未通过原因:</label> <div class="col-md-9"> <div id="div_reason" style="border: 1px solid #003366; height: 90px; word-break: break-all;max-height:90px;overflow-y:scroll" contenteditable="true"></div> </div> </div> </div>
2015年4月28日星期二
高性能集群软件Keepalived之基础知识篇
一、Keepalived介绍
Keepalived是Linux下一个轻量级的高可用解决方案,它与HeartBeat、RoseHA实现的功能类似,都可以实现服务或者网络的高可用,但是又有差别:HeartBeat是一个专业的、功能完善的高可用软件,它提供了HA软件所需的基本功能,比如心跳检测和资源接管,监测集群中的系统服务,在群集节点间转移共享IP地址的所有者等,HeartBeat功能强大,但是部署和使用相对比较麻烦;与HeartBeat相比,Keepalived主要是通过虚拟路由冗余来实现高可用功能,虽然它没有HeartBeat功能强大,但Keepalived部署和使用非常简单,所有配置只需一个配置文件即可完成。这也是本章重点介绍Keepalived的原因。
二、Keepalived是什么
Keepalived起初是为LVS设计的,专门用来监控集群系统中各个服务节点的状态。它根据layer3, 4 & 5交换机制检测每个服务节点的状态,如果某个服务节点出现异常,或工作出现故障,Keepalived将检测到,并将出现故障的服务节点从集群系统中剔除,而在故障节点恢复正常后,Keepalived又可以自动将此服务节点重新加入到服务器集群中,这些工作全部自动完成,不需要人工干涉,需要人工完成的只是修复出现故障的服务节点。
Keepalived后来又加入了VRRP的功能,VRRP是Virtual Router Redundancy Protocol(虚拟路由器冗余协议)的缩写,它出现的目的是为了解决静态路由出现的单点故障问题,通过VRRP可以实现网络不间断地、稳定地运行。因此,Keepalived一方面具有服务器状态检测和故障隔离功能,另一方面也具有HA cluster功能.下面详细介绍下VRRP协议的实现过程。
三、 VRRP协议与工作原理
在现实的网络环境中,主机之间的通信都是通过配置静态路由(默认网关)完成的,而主机之间的路由器一旦出现故障,通信就会失败,因此,在这种通信模式中,路由器就成了一个单点瓶颈,为了解决这个问题,就引入了VRRP协议。
熟悉网络的读者对VRRP协议应该并不陌生。它是一种主备模式的协议,通过VRRP可以在网络发生故障时透明地进行设备切换而不影响主机间的数据通信,这其中涉及两个概念:物理路由器和虚拟路由器。
VRRP可以将两台或多台物理路由器设备虚拟成一个虚拟路由器,这个虚拟路由器通过虚拟IP(一个或多个)对外提供服务,而在虚拟路由器内部,是多个物理路由器协同工作,同一时间只有一台物理路由器对外提供服务,这台物理路由器被称为主路由器(处于MASTER角色)。一般情况下MASTER由选举算法产生,它拥有对外服务的虚拟IP,提供各种网络功能,如ARP请求、ICMP、数据转发等。而其他物理路由器不拥有对外的虚拟IP,也不提供对外网络功能,仅仅接收MASTER的VRRP状态通告信息,这些路由器被统称为备份路由器(处于BACKUP角色)。当主路由器失效时,处于BACKUP角色的备份路由器将重新进行选举,产生一个新的主路由器进入MASTER角色继续提供对外服务,整个切换过程对用户来说完全透明。
每个虚拟路由器都有一个唯一标识,称为VRID,一个VRID与一组IP地址构成了一个虚拟路由器。在VRRP协议中,所有的报文都是通过IP多播形式发送的,而在一个虚拟路由器中,只有处于MASTER角色的路由器会一直发送VRRP数据包,处于BACKUP角色的路由器只接收MASTER发过来的报文信息,用来监控MASTER运行状态,因此,不会发生BACKUP抢占的现象,除非它的优先级更高。而当MASTER不可用时,BACKUP也就无法收到MASTER发过来的报文信息,于是就认定MASTER出现故障,接着多台BACKUP就会进行选举,优先级最高的BACKUP将成为新的MASTER,这种选举并进行角色切换的过程非常快,因而也就保证了服务的持续可用性。
四、Keepalived工作原理
上节简单介绍了Keepalived通过VRRP实现高可用功能的工作原理,而Keepalived作为一个高性能集群软件,它还能实现对集群中服务器运行状态的监控及故障隔离。下面继续介绍下Keepalived对服务器运行状态监控和检测的工作原理。
Keepalived工作在TCP/IP参考模型的第三、第四和第五层,也就是网络层、传输层和应用层。根据TCP/IP参考模型各层所能实现的功能,Keepalived运行机制如下。
在网络层,运行着四个重要的协议:互连网协议IP、互连网控制报文协议ICMP、地址转换协议ARP以及反向地址转换协议RARP。Keepalived在网络层采用的最常见的工作方式是通过ICMP协议向服务器集群中的每个节点发送一个ICMP的数据包(类似于ping实现的功能),如果某个节点没有返回响应数据包,那么就认为此节点发生了故障,Keepalived将报告此节点失效,并从服务器集群中剔除故障节点。
在传输层,提供了两个主要的协议:传输控制协议TCP和用户数据协议UDP。传输控制协议TCP可以提供可靠的数据传输服务,IP地址和端口,代表一个TCP连接的一个连接端。要获得TCP服务,须在发送机的一个端口上和接收机的一个端口上建立连接,而Keepalived在传输层就是利用TCP协议的端口连接和扫描技术来判断集群节点是否正常的。比如,对于常见的Web服务默认的80端口、SSH服务默认的22端口等,Keepalived一旦在传输层探测到这些端口没有响应数据返回,就认为这些端口发生异常,然后强制将此端口对应的节点从服务器集群组中移除。
在应用层,可以运行FTP、TELNET、SMTP、DNS等各种不同类型的高层协议,Keepalived的运行方式也更加全面化和复杂化,用户可以通过自定义Keepalived的工作方式,例如用户可以通过编写程序来运行Keepalived,而Keepalived将根据用户的设定检测各种程序或服务是否允许正常,如果Keepalived的检测结果与用户设定不一致时,Keepalived将把对应的服务从服务器中移除。
五、Keepalived的体系结构
Keepalived是一个高度模块化的软件,结构简单,但扩展性很强,如有兴趣的读者,可以阅读下Keepalived的源码。下图是官方给出的Keepalived体系结构拓扑图。
从图中可以看出,Keepalived的体系结构从整体上分为两层,分别是用户空间层(User Space)和内核空间层(Kernel Space).下面介绍Keepalived两层结构的详细组成及实现的功能。
内核空间层处于最底层,它包括IPVS和NETLINK两个模块。IPVS模块是Keepalived引入的一个第三方模块,通过IPVS可以实现基于IP的负载均衡集群。IPVS默认包含在LVS集群软件中。而对于LVS集群软件,相信做运维的朋友并不陌生:在LVS集群中,IPVS安装在一个叫做Director Server的服务器上,同时在Director Server上虚拟出一个IP地址来对外提供服务,而用户必须通过这个虚拟IP地址才能访问服务。这个虚拟IP一般称为LVS的VIP,即Virtual IP。访问的请求首先经过VIP到达Director Server,然后由Director Server从服务器集群节点中选取一个服务节点响应用户的请求。
Keepalived最初就是为LVS提供服务的,由于Keepalived可以实现对集群节点的状态检测,而IPVS可以实现负载均衡功能,因此,Keepalived借助于第三方模块IPVS就可以很方便地搭建一套负载均衡系统。在这里有个误区,由于Keepalived可以和IPVS一起很好地工作,因此很多初学者都以为Keepalived就是一个负载均衡软件,这种理解是错误的。
在Keepalived中,IPVS模块是可配置的,如果需要负载均衡功能,可以在编译Keepalived时打开负载均衡功能,反正,也可以通过配置编译参数关闭。
NETLINK模块主要用于实现一些高级路由框架和一些相关的网络功能,完成用户空间层Netlink Reflector模块发来的各种网络请求。
用户空间层位于内核空间层之上,Keepalived的所有具体功能都在这里实现,下面介绍、几个重要部分所实现的功能。
在用户空间层,Keepalived又分为四个部分,分别是Scheduler I/O Multiplexer、Memory Management、Control Plane和Core components。其中,Scheduler I/O Multiplexer是一个I/O复用分发调度器,它负责安排Keepalived所有内部的任务请求。Memory Management是一个内存管理机制,这个框架提供了访问内存的一些通用方法。Control Plane是Keepalived的控制面板,可以实现对配置文件进行编译和解析,Keepalived的配置文件解析比较特殊,它并不是一次解析所有模块的配置,而是只有在用到某模块时才解析相应的配置。最后详细说一下Core components,这个部分是Keepalived的核心组件,包含了一些列功能模块,主要有WatchDog、Checkers、VRRP Stack、IPVS wrapper和Netlink Reflector,下面介绍每个模块所实现的功能如下。
(1)WatchDog
WatchDog是计算机可靠性领域中一个极为简单又非常有效的检测工具,它的工作原理是针对被监视的目标设置一个计数器和一个阈值,WatchDog会自己增加此计数值,然后等待被监视的目标周期性地重置该计数值。一旦被监控目标发生错误,就无法重置此计数值,WatchDog就会检测到,于是就采取对应的恢复措施,例如重启或关闭。
在Linux中很早就引入了WatchDog功能,而Keepalived正是通过WatchDog的运行机制来监控Checkers和VRRP进程的。
(2)Checkers
这是Keepalived最基础的功能,也是最主要的功能,可实现对服务器运行状态检测和故障隔离。
(3)VRRP Stack
这是Keepalived后来引入的VRRP功能,可以实现HA集群中失败切换(Failover)功能。Keepalived通过VRRP功能再结合LVS负载均衡软件即可部署一套高性能的负载均衡集群系统。
(4)IPVS wrapper
本文不打算解释AOP的相关专业名词和概念,仅通过几个代码示例来展示Aspectj(对AOP实现的)的基本使用,并且使用的Aspectj是目前最新版本。
1.搭建环境
本文使用Maven来构建工程,通过aspectj-maven-plugin插件来编译*.aj文件至.class。
Maven的具体配置:
< groupId >org.codehaus.mojo</ groupId > < artifactId >aspectj-maven-plugin</ artifactId > < version >1.7</ version > < complianceLevel >1.6</ complianceLevel > |
在上面的configuration节点下可以配置
< aspectDirectory ></ aspectDirectory > |
默认是src/main/aspect , 可以根据需要进行设置。
配置aspectj运行时环境依赖jar
< groupId >org.aspectj</ groupId > < artifactId >aspectjrt</ artifactId > < version >1.8.2</ version > |
2.创建一个普通的Java类(Simple.java),为接下来使用Aspectj来植入相应功能做准备
package com.rft.fdsi.server.aop; public class Simple{ System.out.println( "[src]staticinit" ); public Simple(){ System.out.println( "[src]construct" ); public Stringwelcome(Stringname){ System.out.println( "[src]===========start===========" ); System.out.println( "[src]welcomemethodexecute" ); System.out.println( "[src]welcomemethodexecute" ); System.out.println( "[src]===========end===========" ); //thrownewRuntimeException("runtimeexception"); return "welcome" +name; public static void main(String[]args){ Simplesimple= new Simple(); Stringgreeting=simple.welcome( "Jack" ); System.out.println(greeting); |
3.创建一个针对Simple类的静态代码块初始化,构造方法执行,方法调用进行植入功能的方面类(SimpleAspect.aj)。
package com.rft.fdsi.server.aop; public aspectSimpleAspect{ public pointcutstaticInit():staticinitialization(com.rft.fdsi.server.aop.Simple); before():staticInit(){ System.out.println( "" +thisJoinPointStaticPart.getSignature().getName()); after()returning():staticInit(){ System.out.println( "[afterreturning]" +thisJoinPointStaticPart.getSignature().getName()); before():call( public com.rft.fdsi.server.aop.*. new ()){ System.out.println( "" +thisJoinPoint.getSignature().getName()); after():call( public com.rft.fdsi.server.aop.*. new ()){ System.out.println( "[after]" +thisJoinPoint.getSignature().getName()); public pointcutwelcomeMethod(Stringname):call( public Stringcom.rft.fdsi.server..*.welcome(String))&&args(name); before(Stringname):welcomeMethod(name){ .println( "" +thisJoinPoint.getTarget().getClass()阅读更多内容
|