- 浏览: 1700583 次
- 性别:
- 来自: 杭州699号
文章分类
最新评论
-
莫莫摸:
为什么不用dubbo
RCP数据传输模型回顾 -
大胡子爸爸:
String, Class 都实现了Serializable接 ...
RPC框架几行代码就够了 -
lss598018587:
谢谢大神分享,比起新手看复杂的dubbo框架还不如看大神的这一 ...
RPC框架几行代码就够了 -
15606915740:
你好,请问一下。<dubbo:consumer filt ...
Dubbo文档 -
joqk12345:
...
一些设计上的基本常识
转于自己在公司的Blog:
http://pt.alibaba-inc.com/wp/experience_1014/design-for-dummy.html
最近有点痴呆,因为解决了太多的痴呆问题,
服务框架实施面超来超广,已有50多个项目在使用,
每天都要去帮应用查问题,来来回回,
发现大部分都是配置错误,或者重复的文件或类,或者网络不通等,
所以准备在新版本中加入防痴呆设计,估且这么叫吧,
可能很简单,但对排错速度还是有点帮助,
希望能抛砖引玉,也希望大家多给力,想出更多的防范措施共享出来。
(1) 检查重复的jar包
最痴呆的问题,就是有多个版本的相同jar包,
会出现新版本的A类,调用了旧版本的B类,
而且和JVM加载顺序有关,问题带有偶然性,误导性,
遇到这种莫名其妙的问题,最头疼,
所以,第一条,先把它防住,
在每个jar包中挑一个一定会加载的类,加上重复类检查,
给个示例:
检查重复工具类:
(2) 检查重复的配置文件
配置文件加载错,也是经常碰到的问题,
用户通常会和你说:“我配置的很正确啊,不信我发给你看下,但就是报错”,
然后查一圈下来,原来他发过来的配置根本没加载,
平台很多产品都会在classpath下放一个约定的配置,
如果项目中有多个,通常会取JVM加载的第一个,
为了不被这么低级的问题折腾,
和上面的重复jar包一样,在配置加载的地方,加上:
(3) 检查所有可选配置
必填配置估计大家都会检查,因为没有的话,根本没法运行,
但对一些可选参数,也应该做一些检查,
比如:服务框架允许通过注册中心关联服务消费者和服务提供者,
也允许直接配置服务提供者地址点对点直连,
这时候,注册中心地址是可选的,
但如果没有配点对点直连配置,注册中心地址就一定要配,
这时候也要做相应检查。
(4) 异常信息给出解决方案
在给应用排错时,最怕的就是那种只有简单的一句错误描述,啥信息都没有的异常信息,
比如上次碰到一个Failed to get session异常,
就这几个单词,啥都没有,哪个session出错? 什么原因Failed?
看了都快疯掉,因是线上环境不好调试,而且有些场景不是每次都能重现,
异常最基本要带有上下文信息,包括操作者,操作目标,原因等,
最好的异常信息,应给出解决方案,比如上面可以给出:
"从10.20.16.3到10.20.130.20:20880之间的网络不通,
请在10.20.16.3使用telnet 10.20.130.20 20880测试一下网络,
如果是跨机房调用,可能是防火墙阻挡,请联系SA开通访问权限"
等等,上面甚至可以根据IP段判断是不是跨机房。
另外一个例子,是spring-web的context加载,
如果在getBean时spring没有被启动,
spring会报一个错,错误信息写着:
请在web.xml中加入:<listener>...<init-param>...
多好的同学,看到错误的人复制一下就完事了,我们该学学,
可以把常见的错误故意犯一遍,看看错误信息能否自我搞定问题,
或者把平时支持应用时遇到的问题及解决办法都写到异常信息里。
(5) 日志信息包含环境信息
每次应用一出错,应用的开发或测试就会把出错信息发过来,询问原因,
这时候我都会问一大堆套话,
用的哪个版本呀?
是生产环境还是开发测试环境?
哪个注册中心呀?
哪个项目中的?
哪台机器呀?
哪个服务?
。。。
累啊,最主要的是,有些开发或测试人员根本分不清,
没办法,只好提供上门服务,浪费的时间可不是浮云,
所以,日志中最好把需要的环境信息一并打进去,
最好给日志输出做个包装,统一处理掉,免得忘了。
包装Logger接口如:
获取版本号工具类:
(6) kill之前先dump
每次线上环境一出问题,大家就慌了,
通常最直接的办法回滚重启,以减少故障时间,
这样现场就被破坏了,要想事后查问题就麻烦了,
有些问题必须在线上的大压力下才会发生,
线下测试环境很难重现,
不太可能让开发或Appops在重启前,
先手工将出错现场所有数据备份一下,
所以最好在kill脚本之前调用dump,
进行自动备份,这样就不会有人为疏忽。
dump脚本示例:
------------------------
Dubbo设计分享系列:
负载均衡扩展接口重构
一些设计上的基本常识
谈谈泛化式扩展与组合式扩展
防痴呆设计 比 容错处理设计 更形象,另外 容错处理设计 个人感觉往往和是指服务端运行时容错,大家已经有这样潜在认知了。
http://pt.alibaba-inc.com/wp/experience_1014/design-for-dummy.html
最近有点痴呆,因为解决了太多的痴呆问题,
服务框架实施面超来超广,已有50多个项目在使用,
每天都要去帮应用查问题,来来回回,
发现大部分都是配置错误,或者重复的文件或类,或者网络不通等,
所以准备在新版本中加入防痴呆设计,估且这么叫吧,
可能很简单,但对排错速度还是有点帮助,
希望能抛砖引玉,也希望大家多给力,想出更多的防范措施共享出来。
(1) 检查重复的jar包
最痴呆的问题,就是有多个版本的相同jar包,
会出现新版本的A类,调用了旧版本的B类,
而且和JVM加载顺序有关,问题带有偶然性,误导性,
遇到这种莫名其妙的问题,最头疼,
所以,第一条,先把它防住,
在每个jar包中挑一个一定会加载的类,加上重复类检查,
给个示例:
static { Duplicate.checkDuplicate(Xxx.class); }
检查重复工具类:
public final class Duplicate { private Duplicate() {} public static void checkDuplicate(Class cls) { checkDuplicate(cls.getName().replace('.', '/') + ".class"); } public static void checkDuplicate(String path) { try { // 在ClassPath搜文件 Enumeration urls = Thread.currentThread().getContextClassLoader().getResources(path); Set files = new HashSet(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); if (url != null) { String file = url.getFile(); if (file != null && file.length() > 0) { files.add(file); } } } // 如果有多个,就表示重复 if (files.size() > 1) { logger.error("Duplicate class " + path + " in " + files.size() + " jar " + files); } } catch (Throwable e) { // 防御性容错 logger.error(e.getMessage(), e); } } }
(2) 检查重复的配置文件
配置文件加载错,也是经常碰到的问题,
用户通常会和你说:“我配置的很正确啊,不信我发给你看下,但就是报错”,
然后查一圈下来,原来他发过来的配置根本没加载,
平台很多产品都会在classpath下放一个约定的配置,
如果项目中有多个,通常会取JVM加载的第一个,
为了不被这么低级的问题折腾,
和上面的重复jar包一样,在配置加载的地方,加上:
Duplicate.checkDuplicate("xxx.properties");
(3) 检查所有可选配置
必填配置估计大家都会检查,因为没有的话,根本没法运行,
但对一些可选参数,也应该做一些检查,
比如:服务框架允许通过注册中心关联服务消费者和服务提供者,
也允许直接配置服务提供者地址点对点直连,
这时候,注册中心地址是可选的,
但如果没有配点对点直连配置,注册中心地址就一定要配,
这时候也要做相应检查。
(4) 异常信息给出解决方案
在给应用排错时,最怕的就是那种只有简单的一句错误描述,啥信息都没有的异常信息,
比如上次碰到一个Failed to get session异常,
就这几个单词,啥都没有,哪个session出错? 什么原因Failed?
看了都快疯掉,因是线上环境不好调试,而且有些场景不是每次都能重现,
异常最基本要带有上下文信息,包括操作者,操作目标,原因等,
最好的异常信息,应给出解决方案,比如上面可以给出:
"从10.20.16.3到10.20.130.20:20880之间的网络不通,
请在10.20.16.3使用telnet 10.20.130.20 20880测试一下网络,
如果是跨机房调用,可能是防火墙阻挡,请联系SA开通访问权限"
等等,上面甚至可以根据IP段判断是不是跨机房。
另外一个例子,是spring-web的context加载,
如果在getBean时spring没有被启动,
spring会报一个错,错误信息写着:
请在web.xml中加入:<listener>...<init-param>...
多好的同学,看到错误的人复制一下就完事了,我们该学学,
可以把常见的错误故意犯一遍,看看错误信息能否自我搞定问题,
或者把平时支持应用时遇到的问题及解决办法都写到异常信息里。
(5) 日志信息包含环境信息
每次应用一出错,应用的开发或测试就会把出错信息发过来,询问原因,
这时候我都会问一大堆套话,
用的哪个版本呀?
是生产环境还是开发测试环境?
哪个注册中心呀?
哪个项目中的?
哪台机器呀?
哪个服务?
。。。
累啊,最主要的是,有些开发或测试人员根本分不清,
没办法,只好提供上门服务,浪费的时间可不是浮云,
所以,日志中最好把需要的环境信息一并打进去,
最好给日志输出做个包装,统一处理掉,免得忘了。
包装Logger接口如:
public void error(String msg, Throwable e) { delegate.error(msg + " on server " + InetAddress.getLocalHost() + " using version " + Version.getVersion(), e); }
获取版本号工具类:
public final class Version { private Version() {} private static final Logger logger = LoggerFactory.getLogger(Version.class); private static final Pattern VERSION_PATTERN = Pattern.compile("([0-9][0-9\\.\\-]*)\\.jar"); private static final String VERSION = getVersion(Version.class, "2.0.0"); public static String getVersion(){ return VERSION; } public static String getVersion(Class cls, String defaultVersion) { try { // 首先查找MANIFEST.MF规范中的版本号 String version = cls.getPackage().getImplementationVersion(); if (version == null || version.length() == 0) { version = cls.getPackage().getSpecificationVersion(); } if (version == null || version.length() == 0) { // 如果MANIFEST.MF规范中没有版本号,基于jar包名获取版本号 String file = cls.getProtectionDomain().getCodeSource().getLocation().getFile(); if (file != null && file.length() > 0 && file.endsWith(".jar")) { Matcher matcher = VERSION_PATTERN.matcher(file); while (matcher.find() && matcher.groupCount() > 0) { version = matcher.group(1); } } } // 返回版本号,如果为空返回缺省版本号 return version == null || version.length() == 0 ? defaultVersion : version; } catch (Throwable e) { // 防御性容错 // 忽略异常,返回缺省版本号 logger.error(e.getMessage(), e); return defaultVersion; } } }
(6) kill之前先dump
每次线上环境一出问题,大家就慌了,
通常最直接的办法回滚重启,以减少故障时间,
这样现场就被破坏了,要想事后查问题就麻烦了,
有些问题必须在线上的大压力下才会发生,
线下测试环境很难重现,
不太可能让开发或Appops在重启前,
先手工将出错现场所有数据备份一下,
所以最好在kill脚本之前调用dump,
进行自动备份,这样就不会有人为疏忽。
dump脚本示例:
JAVA_HOME=/usr/java OUTPUT_HOME=~/output DEPLOY_HOME=`dirname $0` HOST_NAME=`hostname` DUMP_PIDS=`ps --no-heading -C java -f --width 1000 | grep "$DEPLOY_HOME" |awk '{print $2}'` if [ -z "$DUMP_PIDS" ]; then echo "The server $HOST_NAME is not started!" exit 1; fi DUMP_ROOT=$OUTPUT_HOME/dump if [ ! -d $DUMP_ROOT ]; then mkdir $DUMP_ROOT fi DUMP_DATE=`date +%Y%m%d%H%M%S` DUMP_DIR=$DUMP_ROOT/dump-$DUMP_DATE if [ ! -d $DUMP_DIR ]; then mkdir $DUMP_DIR fi echo -e "Dumping the server $HOST_NAME ...\c" for PID in $DUMP_PIDS ; do $JAVA_HOME/bin/jstack $PID > $DUMP_DIR/jstack-$PID.dump 2>&1 echo -e ".\c" $JAVA_HOME/bin/jinfo $PID > $DUMP_DIR/jinfo-$PID.dump 2>&1 echo -e ".\c" $JAVA_HOME/bin/jstat -gcutil $PID > $DUMP_DIR/jstat-gcutil-$PID.dump 2>&1 echo -e ".\c" $JAVA_HOME/bin/jstat -gccapacity $PID > $DUMP_DIR/jstat-gccapacity-$PID.dump 2>&1 echo -e ".\c" $JAVA_HOME/bin/jmap $PID > $DUMP_DIR/jmap-$PID.dump 2>&1 echo -e ".\c" $JAVA_HOME/bin/jmap -heap $PID > $DUMP_DIR/jmap-heap-$PID.dump 2>&1 echo -e ".\c" $JAVA_HOME/bin/jmap -histo $PID > $DUMP_DIR/jmap-histo-$PID.dump 2>&1 echo -e ".\c" if [ -r /usr/sbin/lsof ]; then /usr/sbin/lsof -p $PID > $DUMP_DIR/lsof-$PID.dump echo -e ".\c" fi done if [ -r /usr/bin/sar ]; then /usr/bin/sar > $DUMP_DIR/sar.dump echo -e ".\c" fi if [ -r /usr/bin/uptime ]; then /usr/bin/uptime > $DUMP_DIR/uptime.dump echo -e ".\c" fi if [ -r /usr/bin/free ]; then /usr/bin/free -t > $DUMP_DIR/free.dump echo -e ".\c" fi if [ -r /usr/bin/vmstat ]; then /usr/bin/vmstat > $DUMP_DIR/vmstat.dump echo -e ".\c" fi if [ -r /usr/bin/mpstat ]; then /usr/bin/mpstat > $DUMP_DIR/mpstat.dump echo -e ".\c" fi if [ -r /usr/bin/iostat ]; then /usr/bin/iostat > $DUMP_DIR/iostat.dump echo -e ".\c" fi if [ -r /bin/netstat ]; then /bin/netstat > $DUMP_DIR/netstat.dump echo -e ".\c" fi echo "OK!"
------------------------
Dubbo设计分享系列:
负载均衡扩展接口重构
一些设计上的基本常识
谈谈泛化式扩展与组合式扩展
评论
6 楼
zxf2342
2015-12-09
最近正在学习Dubbo,对于开发过程中遇到的很多错误有很大的帮助意义!
5 楼
oldrat
2015-02-26
bojiang 写道
很不错,框架层面设计的共性问题,不过我更倾向与叫做“容错处理设计”,错误不仅仅是系统运行的错误,当然也包括人为因素,毕竟不能要求所有的框架使用者和设计者一样了解系统:)
防痴呆设计 比 容错处理设计 更形象,另外 容错处理设计 个人感觉往往和是指服务端运行时容错,大家已经有这样潜在认知了。
4 楼
bojiang
2011-11-28
很不错,框架层面设计的共性问题,不过我更倾向与叫做“容错处理设计”,错误不仅仅是系统运行的错误,当然也包括人为因素,毕竟不能要求所有的框架使用者和设计者一样了解系统:)
3 楼
cn-done
2011-06-07
有些都是项目中的共性,值得参考。
2 楼
lingqi1818
2011-02-15
很可惜,dump的时候,很多工具服务端并没有安装。
1 楼
agapple
2010-11-30
想法都很不错,记下了。
的确现在的dubbo使用越来越多以后,很多易用性,问题易排查性上要想一些办法
的确现在的dubbo使用越来越多以后,很多易用性,问题易排查性上要想一些办法
发表评论
-
能力成长模型
2012-05-09 00:28 22939最近看了温伯格1986年出版的《技术领导之路》, 很老的书,讲 ... -
以HTTL为例讲讲模块分包&领域模型&扩展框架
2011-10-09 20:08 16750注:该博客内容已加入 ... -
使用Map参数的Webx3扩展
2011-08-28 02:10 5917因Webx3是开源的,所以把这个简单的Webx3扩展发在博客上 ... -
Netty内存泄露
2011-08-02 20:09 24967转于自己在公司的Blog: ... -
Grizzly和Netty以及Mina简单性能对比
2011-07-17 02:48 29745转于自己在公司的Blog: http://pt.alibaba ... -
RPC框架几行代码就够了
2011-07-14 00:34 90195转于自己在公司的Blog: http://pt.alibaba ... -
魔鬼在细节中
2011-05-24 14:50 32255转于自己在公司的Blog: ... -
Dubbo扩展点重构
2011-05-12 22:09 38897转于自己在公司的Blog: http://pt.alibaba ... -
配置设计
2011-03-09 23:41 23586转于自己在公司的Blog: ... -
[转]HTML5设计原理
2011-03-09 22:57 7805Jeremy Keith在 Fronteers 2010 ... -
Hessian序列化不设SerializerFactory性能问题
2010-12-27 11:38 6474转于自己在公司的Blog: http://pt.alibaba ... -
动态代理方案性能对比
2010-11-17 21:38 46202转于自己在公司的Blog: http://pt.alibaba ... -
负载均衡扩展接口重构
2010-11-05 18:53 8757转于自己在公司的Blog: ... -
分布式服务框架常被质疑的价值
2010-11-05 18:52 5734转于自己在公司的Blog: http://pt.alibaba ... -
Hessian3.2.1在序列化32.5k字符串时的问题
2010-11-05 18:49 7255转于自己在公司的Blog: http://pt.alibaba ... -
一些设计上的基本常识
2010-07-05 19:28 27736转于自己在公司的Blog: ... -
谈谈扩充式扩展与增量式扩展
2010-06-12 19:46 19385转于自己在公司的Blog: http://pt.alibaba ... -
Scaling Architecture
2010-02-25 10:31 4118Scaling Second Life: http://p ... -
EBay SOA
2010-02-23 18:23 4800EBay SOA PPT -
服务化基础设施
2009-11-15 23:11 6282服务化,也可以叫SOA, ...
相关推荐
- 设计时应考虑到防痴呆设计,即减少出错的可能性。 - 版本管理、贡献指南、检查列表和坏味道等规范性文档,有助于团队成员协作和代码质量控制。 ### 技术兼容性测试 - Dubbo重视技术兼容性测试,确保在不同环境下...
设计原则部分讨论了魔鬼在细节,设计上的基本常识,扩充式扩展与增量式扩展的区别,配置设计,设计实现的健壮性,防痴呆设计以及扩展点重构等要点。这些原则有助于开发者更加深入地理解框架的设计哲学和实践标准。 ...
在研究设计上,本研究收集并分析了1986至1996年间我国10个地区的调查数据,采用了以性别为分组因素、年龄为连续自变量的Logistic回归模型。通过贝叶斯框架,研究人员能够更全面地评估模型参数的不确定性,从而得到更...
2. **实验设计**:实验采用遗传工程改造的老鼠,这些老鼠携带阿尔茨海默病的基因,通过模拟人类长期接触手机电磁波的情况,对老鼠进行高频电磁波照射,观察其对认知功能的影响。 3. **淀粉样β蛋白**:阿尔茨海默病...
"keep-leetcode"项目就是一个专为IT从业者设计的学习平台,旨在通过每日一题的方式,帮助大家巩固算法知识,提高编程能力。这个项目的核心理念是“一日一算法,共同进步”,其目标不仅是提升个人技能,也是为了防止...
研究表明,玩数独游戏能够提高记忆力和头脑清晰度,甚至可以治疗和预防老年痴呆症等大脑疾病!因此,一些科学家和研究人员建议将数独游戏作为日常活动的一部分。本研究项目基于Java语言和Android平台,开发一款在线...
2. Monbaby智能纽扣:这是一个专为婴儿设计的智能设备,可以追踪和分析宝宝的睡眠模式。通过内置的MEMS加速计,它能记录宝宝的运动、睡姿、活动量和呼吸,实时发送到父母的智能手机app上。这种技术不仅帮助父母了解...
实验设计将小鼠分为四组,对比了天麻全药对痴呆小鼠学习记忆能力的影响。结果表明,未给予天麻的模型组(C组)小鼠在Morris水迷宫测试中表现出显著的学习记忆能力下降。而给予天麻全药的模型组(D组)小鼠则显示出...
基于C51单片机的智能鞋设计与实现的研究,是一项结合了现代技术与日常生活用品的创新项目。该研究关注儿童和老年痴呆患者走失的社会问题,以及行走姿势不标准引发的健康问题。通过开发具有定位功能和健康监测功能的...
研究表明,玩数独游戏能够提高记忆力和头脑清晰度,甚至可以治疗和预防老年痴呆症等大脑疾病!因此,一些科学家和研究人员建议将数独游戏作为日常活动的一部分。本研究项目基于Java语言和Android平台,开发一款在线...
2. 智能定位系统:例如,带有GPS功能的智能皮鞋,可以追踪老年痴呆症患者的行动,帮助家人或监护人迅速找到走失的老人。 3. 智能家居健康监测系统:如“智能衣柜”,可以追踪物品放置位置,同时监测老人的血压、...
【研究方法与设计】 该研究选取了34例SIVD患者和26例健康老年人作为对照,通过聚合酶链反应(PCR)、基因测序等技术检测ApoE基因序列,结合MRI检查(包括DTI和MTI),运用神经心理学测试(如MMSE)进行评估。通过对...
设计制作了一款基于LT1083/LT1033系列大功率低压差三端稳压芯片的高稳定度低纹波直流电源,介绍了降压、整流滤波、线性稳压、LC低通滤波等主要构成模块。测试结果表明,本电源具有输出电压稳定度高、输出电流大、低...
【基于GPS/GSM技术的防丢失个人定位系统的设计】是一种智能解决方案,专为寻找和保护失踪的儿童或老年痴呆者而设计。该系统结合了全球定位系统(GPS)和全球移动通信系统(GSM)的技术,实现了高效、实时的位置追踪...
豆浆中,钙的含量尤其高,比其他任何乳类都丰富,是防治高血脂、高血压、动脉硬化等疾病的理想食品,多喝鲜豆浆可预防老年痴呆症,防治气喘病。 防治疾病方面,报告指出,豆浆对于贫血病人的调养,比牛奶作用要强,...
研究表明,玩数独游戏能够提高记忆力和头脑清晰度,甚至可以治疗和预防老年痴呆症等大脑疾病!因此,一些科学家和研究人员建议将数独游戏作为日常活动的一部分。本研究项目基于Java语言和Android平台,开发一款在线...
该备忘录系统源码采用Shell与C#混合编程语言开发,包含101个文件,涵盖了77个Markdown文件、3个配置文件、3个C#源文件、3个Shell脚本...系统旨在为用户提供便捷的日常记录与查询功能,有助于记忆维护和预防老年痴呆。
文章指出,市场上现有的老人防走丢定位系统价格较高,而本系统力求实用、便携且经济,以便更多的普通家庭能够负担得起,并享受科技带来的便利。系统采用基站定位而非卫星定位,一方面因为基站定位已经由运营商实现,...