一个jstack/jmap等不能用的case

今天一个同学问我:”我排查问题时总是遇到,jmap -heap或-histo 不能用,是不是我们机器配置有啥问题哇? ” 分享下这个case的解决过程。

登上同学说的那台不能用的机器,执行jstack,报错:“get_thread_regs failed for a lwp”,这个问题以前碰到过,但忘了当时是什么原因了,执行其他的jmap -histo什么也卡着不动。

既然jstack没法弄,就pstack看看进程到底什么状况吧,于是pstack [pid]看,发现有一个线程的堆栈信息有点奇怪:
#0 0x00000038e720cd91 in sem_wait ()

对系统函数不太懂,但总觉得sem_wait这个有点奇怪,于是Google之,基本明白了这个是由于进程在等信号,这个时候通常会block住其他所有的线程,于是立刻ps看了下进程的状态,果然进程的状态变成了T,那上面碰到的所有现象都很容易解释了,于是执行:kill -CONT [pid],一切恢复正常。

继续查为什么进程状态会变成T,问问题的同学告诉了下我他在机器上执行过的一些命令,我看到其中一个很熟悉的命令:jmap -heap,看过我之前文章的同学估计会记得我很早以前分享过,在用cms gc的情况下,执行jmap -heap有些时候会导致进程变T,因此强烈建议别执行这个命令,如果想获取内存目前每个区域的使用状况,可通过jstat -gc或jstat -gccapacity来拿到。

到此为止,问题终于搞定,以后碰到jstack/jmap等不能用的时候,可以先看看进程的状态,因此还是那句话,执行任何一句命令都要清楚它带来的影响。

手头还有另外一个case,折腾了一个多星期了还是没太有头绪,case的现象是ygc越来越慢,但可以肯定不是由于cms gc碎片问题造成的,感兴趣的同学可以拿这个case去玩玩,如果能告诉我原因就更好了,:),执行下面的代码,启动参数可以为-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xms512m -Xmx512m -Xmn100m -XX:+UseConcMarkSweepGC:
[code]
import com.thoughtworks.xstream.XStream;

public class XStreamTest {

public static void main(String[] args) throws Exception {
while(true){
XStream xs = new XStream();
xs.toString();
xs = null;
}
}

}
[/code]

应该就可以看到ygc的速度从10+ms一直增长到100+ms之类的…

=============================
欢迎关注微信公众号:hellojavacases

关于此微信号:
分享Java问题排查的Case、Java业界的动态和新技术、Java的一些小知识点Test,以及和大家一起讨论一些Java问题或场景,这里只有Java细节的分享,没有大道理、大架构和大框架。

公众号上发布的消息都存放在http://hellojava.info上。

架构师画像

架构师,这个title就和总监之类的title一样,已经彻底被用烂了,但在一个软件产品的生命周期中,架构师是实实在在的一个极度重要的角色,这篇文章就来讲讲我觉得的架构师的画像,到底具备什么素质的同学是贴合架构师形象的,同时欢迎大家回复下在你心目中NB的架构师的画像是怎么样的呢。

业务理解和抽象能力
架构师的第一职责是理解业务,并转换为可被研发理解的实现方案,因此业务理解能力是架构师的必备技能,通常来说一个资深的业务架构师,对业务会有非常深的认识和积累,一个极好的业务架构师应该能大概预判业务未来的发展趋势,以便在系统的可扩展性上留好一定的空间,所以也会很自然的出现有些业务架构师做着做着就干脆转为PD类型的角色。
抽象能力是通过对业务的理解转换为系统实现的模型,这显然也是重要的能力,抽象很多时候也承担了分解清楚多个团队的职责,分工清晰化。

NB的代码能力
之所以现在很多的架构师都会被认为是大忽悠,就是有一堆顶着架构师头衔,又不干活的人(甚至会出现对技术几乎不太懂的人),光说不干,再加上说的不靠谱的话自然很容易被认为是大忽悠,就我自己而言,我一直认为架构师有个非常重要的职责是编写整个系统中核心部分的代码,这个部分并一定是技术挑战最高的,但对整个系统的质量/成败与否是具备非常关键的控制作用的,所以架构师必须是从写核心代码的人中诞生出来的。
在一个跨多领域的大型系统中,架构师不太可能什么都擅长,不可能写各个部分的核心代码,这种时候架构师一定要知道怎么判断非自己知识领域的部分实现是否OK,以确保各部分组合在一起的时候是符合架构设计预期的,通常这种确保各部分组织在一起work的机制部分的代码应该由架构师自己操刀。

全面
全面是一个架构师展现出来的最关键素质,全面会体现在三点上:
1. 在面对业务问题上,架构师脑海里是否会浮现出多种技术方案,这点其实挺重要的,否则可能就会出现明明有一个简单成熟的方案,但由于不知道而做了其他复杂不成熟的方案,所以广阔的技术视野是架构师的必备,另外架构师不可能全部擅长,在自己不擅长的点上,需要知道找哪个专业的人是靠谱的,这点也非常重要;

2. 在做系统设计时是否考虑到了足够多的方方面面:
例如很多系统设计容易遗漏上线环节的细节,导致在上线时发现漏掉了什么考虑,临时解决或只能重来,记得有一年我做的一个设计没有考虑到上线阶段的一个细节,导致上线的时候发现由于网段的问题完全不work,并且没有临时解决方案,只好重来,系统设计不仅仅指导研发同学怎么写代码,也包括指导其他所有相关技术同学的工作;
又例如我2008年在做服务框架设计的时候,集群和集群之间通过硬件负载均衡设备来访问的,连接的方式是单个长连接,这个设计导致了运行过程中如果要发布被调用的服务方,很容易出现压力都集中在前面重启的机器上,这也是典型的整个链路没有考虑清楚造成的设计问题;
再例如2013年我在做一个比较大范围的系统改造的设计时,由于对其中一部分的软件了解的不够,判断错误,导致后来这个改造在进行过程中才发现有些需要改造的关键软件的设计做的太粗糙,最后上线进度差不多推迟了一个多月,而且那些后来补的设计都是紧急做的,风险非常高;
回顾自己设计过的软件,发现在这个点上犯的错可以讲好几天,看来我应该整理另外一篇文档《我在系统设计上犯过的xxx个错误》,里面有些其实靠一份好的系统设计模板也许就能避免掉,一份好的系统设计模板是可以帮助架构师思考全面些的。

3. 在做系统设计时是否考虑到了未来的一些发展,尽可能不要出现未来的一点变化就导致现在白干或要花大量力气来改造的现象,想当年做服务框架的时候,后来就发现由于当年做设计的时候没有考虑到将来服务调用trace的问题,导致了后来为了弥补这点花了巨大的力气(不是技术上,而是实施上)。

全面需要架构师有足够广的技术领域知识和足够多的经验积累,从全面这点就可以看到架构师的工作绝不是画几个框,连几根线那么简单。

对架构师全面这点的挑战,会随着系统的范围越大(一个系统的设计,和100个系统组成的大系统的设计挑战是完全不同的)而变得越难,无论是知识的广度、考虑的点的覆盖度、还是未来趋势,更复杂的情况甚至会出现架构的调整对应着组织结构的调整,这种也要考虑到,例如服务化这种大的架构改造,就意味着专职的专业领域服务团队的成立。

全局
全局观通常是指在系统设计时是否考虑到了对上下游的系统的影响,毕竟通常所设计的系统不是一个孤立的系统,如果没有足够好的全局观,有可能会导致自己的系统做完上线,其他上下游系统(尤其有些连上下游是谁,怎么用的都不知道的情况下)出现问题,这种案例同样不少。

权衡
权衡同样也是架构师极度重要的能力,或者也可以认为是决策能力,技术方案的拍板是一个架构师最重要的职责。
上面说的全面是架构师在思考时开的过程,而权衡就是收的过程,收的过程结束基本就意味着技术方案的确定,同时也确定了节奏,权衡在两点上会体现的特别突出:
1. 技术方案决策原则
通常一个问题都会有多种可解决的技术方案,怎么来决策就至关重要了,而决策通常又和全面相关,大的来说通常决策的原则就是性价比和可持续发展。
性价比简单来说是方案的实现成本,这个成本要包括非常多的方面,例如有些场景可能会是用硬件解决看起来是花钱,但最终折算成本是最划算的,很多系统设计在决策性价比时都过于随意,例如一个另外常见的场景就是建设一套新系统替代旧系统,这个时候可能完全没考虑旧系统的迁移代价甚至超过了改造旧系统的代价;
可持续发展简单来说就是所选择的技术方案在公司是否可持续,例如简单的案例是公司主体的研发人员都是php,却搞一个其他语言,且只有极少人懂的(当然,这还是要看性价比,如果搞一个其他语言带来的效益超过了语言/人才体系的更换成本),又例如引入一个开源产品,有无专业团队维护这都是要考虑的关键因素。

2. 优先级和节奏控制
经常我会问做系统设计的同学一个问题:对于这个业务场景而言,在系统设计上最需要把握的一个点是什么;这是一个关键问题,全面意味着考虑到了很多地方的问题,但通常业务需求实现都是有很强的时间要求的,因此在这个时候必须考虑清楚不同点的优先级,同时也包括技术方案在决策时也要做出取舍,有可能选了一个不是那么好的技术方案,但通过留下一些可改造的空间,为以后的重构做好铺垫,那就是很不错的,尤其技术同学有些时候比较容易陷入解决技术问题的场景去,但那个问题其实有可能不是现阶段最重要的。

其实优先级和节奏控制是我认为一个最NB的架构师的最佳体现,优先级意味着把握住了重点,可以确保在所设计的架构指导下业务实现不会出现大问题,节奏控制则意味着全面,为将来做好了铺垫。

=============================
欢迎关注微信公众号:hellojavacases

关于此微信号:
分享Java问题排查的Case、Java业界的动态和新技术、Java的一些小知识点Test,以及和大家一起讨论一些Java问题或场景,这里只有Java细节的分享,没有大道理、大架构和大框架。

公众号上发布的消息都存放在http://hellojava.info上。

GC压垮了最后一根稻草

long time no see,:), 各种原因下导致了这么久没更新,准备再次捡起来了,先分享下最近碰到的一个case。

这个case的现象是:
整个集群fgc严重,导致无法为用户提供服务。

原因分析:
从现象来看,应该是个相当简单的类似内存泄露的问题,模式化的开始了OOM问题排查的过程。

拿到fgc严重时的heap dump进行分析,heap dump显示确实java heap基本被用满了,继续看Dominator tree,惊讶的发现排第一的才占了7%的内存;
切换到leakage的视图看,发现有一类型的类占据了超过40%的内存,用GC root跟是什么地方在引用这些类,看到的是很多的http线程在持有这些类的引用;
为什么这么多的http线程持有这些类的引用又不释放呢,需要看下这些线程都在做什么,于是切换到thread视图,发现这些http线程中除了一个在run,其他的都在等一把锁,run的那个线程持有了这把锁,继续看run的那个线程那行代码在做什么,发现那是个极为简单的动作,完全不可能运行很久,这样的现象说明是由于某些原因导致这个run的线程一直获取不到cpu资源;
翻查当时机器的状况,系统的状况是正常的,但Java应用一直在fgc,连续频繁的fgc导致了上面的那些线程压根就没有执行的机会,在这种情况下这个应用其实已经不可能恢复了。

上面分析了那么多,唯一能得到的结论就是应用本身没有内存泄露,但到底是什么原因触发了应用频繁fgc呢,继续翻查应用的gc log,发现有个现象是在频繁fgc之前cms gc的频率越来越近,并且每次回收后存活的空间占用的越来越大,造成这样的现象是应用的qps增高了太多,或者reponse time(rt)慢了很多造成的,查看应用的qps没什么变化,但应用的rt在cms gc频率变短前有些许的增长,这样基本能解释通:
应用rt增高,导致在cms gc执行的周期内存活的对象增多,于是cms gc频率开始缩短;
而cms gc频率缩短,又进一步导致了rt增高,开始形成了恶性循环。
因此说明这个应用在目前的机器数和qps下其实已经到达瓶颈了,稍微的rt或qps的波动都有可能导致整集群崩盘。

在这个结的情况下问题是没法解决的,要解决这个问题只能是提升应用的性能或扩容机器。

case带来的思考:
这种case其实挺折腾的,在以前讲线程池大小的帖子里也写过一次,就是线程池的最大值开的太大的话,看起来是能接更多的请求(如果cpu处理不是瓶颈的话),但不幸的是通常也会导致存活的对象增多,有可能触发gc,而gc的频繁介入很容易导致恶化的现象。

要预防这种case的另外一个更好的做法还是保持一定频率压测获得应用的单机qps能力,并做相应的限流,确保整体qps达到一定的水位后就扩容。

=============================
欢迎关注微信公众号:hellojavacases

关于此微信号:
分享Java问题排查的Case、Java业界的动态和新技术、Java的一些小知识点Test,以及和大家一起讨论一些Java问题或场景,这里只有Java细节的分享,没有大道理、大架构和大框架。

公众号上发布的消息都存放在http://hellojava.info上。

运维工具真的很容易做吗

在从研发转到运维之前,我一直就觉得运维工具这东西,应该是相当简单的,但在我自己带领一个运维工具团队一年多后,完全颠覆了我自己以前对运维工具的认知,才真正明白了运维工具这东西要做好,对技术的要求其实是极高的。

之前之所以觉得运维工具简单,是因为从在线业务系统角度来看,运维工具访问量低,数据量也很小,完全看不到什么技术难点。

在带领一个运维工具团队一年多后,看到的是运维工具系统对技术的要求其实和在线业务系统只是角度不同而已,先看看运维工具系统主要承担的职责:
1. 运维操作的自动化;
2. 线上故障出现时救命操作的执行;

这两个职责决定了在运维工具系统设计时除了功能实现外需要考虑一些非功能特性:
1. 运维操作的自动化
自动化要真正做到,有一个核心的关键指标:成功率,可以想象下,如果一个自动化的运维操作的成功率只能做到60%,那对用的人来说体现出来就是10次操作失败4次,这种情况下多数会造成的结果就是用户就不用了,因为用户会觉得还不如手工操作来得快,因此运维操作要真正做到自动化,必须确保成功率,这点和在线业务系统更不一样,在线业务系统对单次操作的成功率的要求会远比运维工具系统低,而且在线业务为了确保操作的响应时间等,fail-fast是在线高可用系统的基本策略。
一个复杂的运维操作,例如应用扩容机器,和在线业务系统其实很像,也是要操作N个其他的系统,业务逻辑也很复杂,是一次巨复杂的分布式操作,要保障好成功率,就意味着在A调用B出现异常的时候,得决定后续的动作,有可能需要做重试、跳过(有些可能还需要在完成后再异步操作什么的)再等动作,因此运维工具系统在依赖出异常时的处理策略必须做的非常清楚,尽可能确保成功率。
从这点可以看到,设计运维工具系统时需要更加趋向保障单次操作的成功率上,在各种异常出现时需要有各种处理策略,这和设计大多数在线业务系统是完全不一样的。

2. 线上故障出现时救命操作的执行
线上故障出现后,通常会非常依赖运维工具系统来处理故障,例如监控、发布、切流量等等,而如果在故障出现的时候这些运维工具也出问题,那就悲剧了,记得我们在很早以前讨论系统的一个救命招怎么实现时,一开始谈到了好几个高大上的方案,但最后选择了一个极为土的方案,原因就是因为这是救命招,基本就是能不依赖就不要依赖任何其他东西。
按照这样的要求,运维工具系统中如果是对于线上故障出现时属于救命型的操作,必须确保绝对的稳定,不论是小的故障,还是大到机房的故障,救命操作的系统都得保证绝对的稳定。
而且通常来说,一个救命操作看似一个简单按钮,但背后对应的多数都是N套系统的联动,怎么保障这个看似简单的按钮完全的可信赖,背后是有大量的事情需要做的。

因此从对运维工具系统需要承担的职责分析来看,在技术上运维工具系统其实也是有相当高的要求的,怎么样能保障好成功率、救命操作简单按钮的绝对稳定可靠,是运维工具系统必须做到的。

顺带再说下规模的事,简单举一个例子是可能很多小一些的业务场景里很难碰到发布量本身会变得很大的状况,而在我们的场景里曾经多次碰到过发布系统本身支撑能力不够导致的各种临时找办法的状况,因此对于运维工具系统来说,同样也必须做到知道当前系统能够承受的压力范围,以及怎么水平扩展。

所以,小看了运维工具系统的同学们,包括从前的自己,请正视运维工具系统面临的技术挑战,有兴趣的同学欢迎一起加盟来挑战!

最后,再次推荐下6年前黄易山讲在FB时的工程管理心得中很重要的一句话:Tools Are Top Priority,文章请Tools Are Top Priority

=============================
欢迎关注微信公众号:hellojavacases

关于此微信号:
分享Java问题排查的Case、Java业界的动态和新技术、Java的一些小知识点Test,以及和大家一起讨论一些Java问题或场景,这里只有Java细节的分享,没有大道理、大架构和大框架。

公众号上发布的消息都存放在http://hellojava.info上。

打造高可用的系统

两年前曾经写过一篇《构建高可用系统的常用招数》,主要是从软件设计的角度来阐述,而自从自己从研发转到运维后,这两年来看到了更多的故障,同时更深刻的感受是要打造一个高可用的系统,不是仅仅在软件设计、研发、测试阶段保障质量就ok的,但基本事实是随着业务的发展,系统的复杂度、新加入人员的冲击都会对质量带来极大的影响,因此故障基本是不可避免的,这个时候故障的恢复能力就非常重要,而故障的恢复能力不仅仅是一个简单的操作,其涵盖的一整套体系,从系统的架构到变更到故障出现后的响应机制。

在故障应对这个领域,很容易犯的一个错误就是在故障的根源定位上投入非常大的精力,这个领域投入固然是有价值的,但更多的情况会发现这个领域投入产出比很低,因为真心太难做了,之所以很容易投入更大的精力在故障的根源定位上,是因为在传统的思维上,我们都认为只有定位到了故障的根源才能制定相应的策略来修复故障,但事实上随着系统架构的演变,完全可以有更好的办法。

首先我们看看故障发生时影响的范围大小,通常来说是以下几种:
1. 单实例
单台机器出问题,可能是各种原因,例如硬件故障,或应用出了个偶发故障。
2. 单应用集群
系统里的单个应用集群全体出现故障,出现的故障的原因同样可能多种多样,网络、应用软件bug等,都有可能。
3. 多应用集群
系统里的多个应用集群都出现故障,不过话说其实单应用集群出故障也很容易导致这种现象。
4. 单机房
单个机房整体出现故障,这种通常来说是网络或机房(例如雷击,:))出现故障。
5. 单地域
单个地域出现问题,可能大家觉得很罕见,但事实上有多种因素可能会造成,例如运营商在某片的故障等。
6. 全局
所有应用集群都出故障了,对于没有多个机房、多个地域的而言,单机房的就算全局故障了。

上面的几种故障范围出现后,是否一定要先查出原因才能恢复故障呢,那是不一定的,恢复故障和修复故障完全是两个概念,就上面几种故障范围而言,在恢复故障上可以采用这样的方法:
1. 单实例
对于单实例故障的快速恢复,可以通过改造为集群方式,对于无状态的比较容易搞定,集群+七层健康检查基本就非常有效了,可以做到在出问题时自动应对;
对于有状态的,比较复杂一点,通常需要做主备,或类似paxos的一主多备等结构来做到单个实例出问题时的自动应对。
因此通常来说,单实例的故障是完全不应该影响到业务的。
2. 单应用集群
对于单应用集群整体故障的现象,如果是非关键路径的应用,可通过自动降级或手工降级来快速恢复故障;
如为关键路径的应用,应用部署在多个机房,并且只有一个机房的有问题,那么可以通过快速的切掉这个机房的流量来恢复故障。
3. 多应用集群
和单应用集群采用同样的方法。
4. 单机房
对于单个机房出故障,如系统是多个机房部署的,那么可以采用切掉这个机房的流量来快速恢复故障,这要求系统部署在多个机房,并且具备快速切换能力。
5. 单地域
对于单地域出故障的情况,如系统能做到异地多点部署,那么同样可以采用切掉机房流量来快速恢复故障。
6. 全局
如为全局出故障,那基本上只能靠定位故障,然后来看看怎么快速恢复。

从上面这个简单的阐述可以看到,除了全局故障外,其他类型的故障在系统架构演变到一定阶段后,基本都可以做到在不定位故障的情况下快速恢复,当然要做到影响面越大的故障快速恢复,系统架构的复杂度和难度也会自然的要求更高,同时要确保不同影响范围情况下的故障快速恢复按钮能100%生效,则需要靠不断的演练来确保。

故障发生主要的一个因素是变更(对线上做的任何影响行为的动作都可以认为是变更),即使是在有强大的系统架构情况下,也需要通过靠控制变更范围来发挥出系统架构具备的故障恢复能力,例如系统已经做到了多机房部署和切换的能力,但变更时同时操作了所有机房(例如最典型的是推配置信息),那么这个时候如果出故障,就完全没办法,最多能依靠的是快速回滚等,因此在系统架构具备较强的故障快速恢复能力的情况下,也要相应的改变变更操作的流程,以控制每次的影响范围。

要发挥出这种大杀器级的故障快速恢复的能力,还有最后一点重要的就是在故障发生后要立刻尝试上面的恢复招数,而不是去分析和定位故障的原因,这需要改变习惯。

所以总的来说,要做到故障的快速恢复,其实是一个体系化的工作,非常不容易,而一旦能做到,那对系统的高可用可以起到极大的帮助,我的团队为阿里制定了一个这样的故障恢复体系的标准,感兴趣的同学可以看看QCon北京上的《分钟级故障恢复的高可用保障》的ppt。

=============================
欢迎关注微信公众号:hellojavacases

关于此微信号:
分享Java问题排查的Case、Java业界的动态和新技术、Java的一些小知识点Test,以及和大家一起讨论一些Java问题或场景,这里只有Java细节的分享,没有大道理、大架构和大框架。

公众号上发布的消息都存放在http://hellojava.info上。

Borg论文读后感

Borg之前号称是G家内部和PageRanking可以相提并论的同等重量级的东西,在之前终于是对外发论文了,这篇论文一出就引起了很多人的关注,我的团队在这个方面也做了几年,尽管之前从各种渠道也对Borg有一定了解,但论文揭露的很多内容还是我以前都完全不知道的,个人觉得这篇论文还算挺实在的,G家把自己的很多数据、经验都公开出来了,所以确实值得做资源管理和调度的同学看看。

G家内部所有要放到生产环境运行的东西都称为任务,任务到底放到哪台机器执行由Borg来调度和管理,因此Borg掌握了所有生产环境资源的管理,管理的高效就可以极大程度的节省成本,而这也是Borg出名的原因。

论文里讲到的以下一些内容是我自己印象比较深刻的,同样也是我认为一套优秀的资源管理平台很需要学习的:

1. Prod & Non-Prod Tasks
很早以前就知道Borg是把离线的任务和在线的任务放在一起跑的,当时有点好奇的就是那borg是怎么区分像Gmail之类在线应用的,论文里的Prod(Production)和Non-Prod的划分就直接回答了这个问题。

2. Jobs and tasks
每个Job的描述里可以有很多约束性的一些描述,例如操作系统版本,处理器的架构等,这个真心比我们现在内部的资源分配系统强不少,通用能力自然也就好很多,job通过优先级来做资源抢占,级别划分为:monitoring,production,batch and best effort(also known as testing or free),prod jobs也就是monitoring and production级别。
每个task对应的就是一台机器上的一个container(linux container),task描述所需的资源,不过这个资源信息竟然还包括了tcp端口什么的。

3. Utilization
这是我最关心的部分,在这个部分前论文里还讲了不少关于Borg的架构,以及它是如何保障自己的可用性的等等,这块我就不在这讲了。
Borg最主要的一个目的就是通过一个全局的资源管理系统来提升资源的使用率,在这个部分中论文阐述了Borg通过哪些方法来提升使用率。
第一个方法是离线在线任务混部,论文里有讲到大部分其他的公司都是将离线集群和在线集群分开,G家的一个研究分析表明如果G家把它的离线任务和在线任务集群分开,那么G家会大概需要增加20%-30%的机器,G家的机器数应该在500w+,20%就是100w台机器,这这算到成本的话是非常非常夸张的,所以可以看到离线在线混部是节省资源的一个关键手段,当然每家公司这么做带来的成本节省会不一样,论文里写到之所以离线在线混部能达到这么好的效果,主要原因是prod任务通常是为高峰负载来申请的机器数,而事实上高峰时间通常都是非常短的,就意味着prod任务申请的资源大部分时候其实是空闲的,所以Borg的做法是利用prod任务空闲的资源来跑non-prod任务,从而大幅减少机器数,我自己觉得这是Borg区别于目前大部分其他类似东西的最主要的地方,而且也是最本质的地方。

在给任务分配资源时,Borg采用的方法是prod任务直接占用资源,prod任务互相之间不共享资源,Borg会预估这些prod任务能空闲出的资源,分配给non-prod任务使用,之所以很多公司都不这么做,是担心non-prod任务的执行影响到了prod任务。

Borg在资源的隔离上采用的做法为:
Borg按照两种方法来控制overload和overcommitment,overload通过将任务分为Latency-sensitive(LS)和batch两种来控制资源;overcommitment则通过任务对资源的占用划分为compressible(例如cpu、I/O带宽)和non-compressible(例如内存、磁盘空间)。
如果机器上non-compressible的资源不够用了,那么Borglet会立刻按照优先级杀掉本机上优先级低的任务释放出资源;如compressible的资源不够用,那么Borglet会先尝试控制batch任务对cpu的使用来度过高峰,如果还不行,就会由borgmaster拿掉机器上的一个或更多的低优先级任务。
Borglet里面还有一个用户态的程序来控制分配给prod和non-prod任务的内存,如内存超过了task的限制,或本机的内存不够用了,内核中处理OOM事件的部分将按照优先级来kill task。
在CPU方面,在资源的分配上,对于LS tasks允许占用整个cpu核,而batch tasks则可以在任何核上运行,但batch tasks会在较低优先级上,Borg修改了内核的CPU调度器,允许根据每个container的load状况来动态决定是否要kill batch tasks,同时避免多个LS tasks在一个cpu上争抢,目前Borg仍然在尝试的是在cpu调度时更好的考虑线程亲和、NUMA亲和之类的。

可以看到Borg为了能实现离线在线混部,在资源的分配、隔离上还是做了很多改进的,如果这些patch能公开出来就好了,否则的话其实多数公司做的话也只能是重新尝试,靠不断摔跤来绕过这些问题。

论文的最后有总结下Borg的好和不好的地方,其中竟然也提到了一台物理机一个ip所有container共享的问题,从我们实际对container的使用来看,运维更友好的话其实还是每个container一个ip比较好。

尽管论文中有提到其他很多相似的系统,例如mesos,yarn,facebook’s tupperware,ms autopilot,甚至还提到了alibaba的fuxi,但我始终觉得这些和Borg的巨大区别就是Borg是用来管理所有资源,并且离线在线混部的,而上面这些相似的基本都只是某一款软件的资源管理,这在资源的利用率上相比的话会完全不是一个档次。

据之前的信息,Borg在G家内部应该在2005年左右就相当成熟了,而我们看到论文的时候已经是2015年了,这个差距…

国内腾讯、百度也都尝试过类似Borg的方向,目前腾讯基本是不玩了,百度的Matrix则成功了,同样是离线在线混部,由于给百度节省了巨多的成本,所以这个团队之前得到过百度的100w大奖,不过百度的Matrix其实和Borg实现上的话还是不太一样的,从Borg论文可以看出Borg的话是所有的调度器,这样实现的话有一个坏处是会比较重,百度的Matrix选择了一条更轻量的改造路线,对于一个有不少历史包袱的公司来说是不错的选择,对Matrix感兴趣的同学可以看看这篇文章

我自己这边的话其实是在去年下半年才想明白我们原来所做的提升资源利用率的方向一定程度是错误的,现在我是比较坚信在线离线混部,区分好prod、non-prod,内核改造是比较好的提升资源利用率的方向,我的团队今年在这块需要重点突破,欢迎有兴趣的同学加盟,:)

=============================
欢迎关注微信公众号:hellojavacases
题目来源:http://www.wired.com/wiredenterprise/wp-content/uploads/2013/03/borg.gif

关于此微信号:
分享Java问题排查的Case、Java业界的动态和新技术、Java的一些小知识点Test,以及和大家一起讨论一些Java问题或场景,这里只有Java细节的分享,没有大道理、大架构和大框架。

公众号上发布的消息都存放在http://hellojava.info上。

加机器、切流量真的那么low吗

每当说到应对活动高峰流量的策略时,加机器这招总是会被认为很low,而同样,在另外一个场景中,当系统出现问题,通过切流量来快速恢复时,也会被认为很low,但这两个大招真的很low吗?

第一个点:加机器
首先说说加机器这回事,通常系统最早都是由一台应用机器再加一台或两台数据库机器组成,访问量高的情况下,自然最希望的就是靠加机器来解决。

简单分开看看,应用机器直接从一台变成两个,在技术上会有一些问题是要解掉的:
1. 应用的状态问题
例如最常见的会有用户的登录信息,也许还会有一些其他的状态信息,而如果不解决这些状态数据的问题,就会导致用户访问两台机器时不一致的现象;
2. 一台到两台组集群的问题
这里也将涉及到一堆的问题,例如负载均衡、健康检查等。

如果是数据库加机器呢,就更加复杂了,在技术上通常要解决分库分表的问题,如果不做分库,那么即使加数据库机器也分摊不了压力,分库通常是物理上的拆分,而如果是同一张表的压力,那么通常还需要做分表。

而随着应用机器数的增长,到数据库的连接池很容易成为瓶颈,这个时候通常会碰到有钱买机器,但不能加机器的致命现象,因此也是必须去解决掉的。

仅仅从上面这个最简单的过程就可以看到,系统要纯粹做到靠加机器就能支撑流量其实并不容易,是需要相当多的技术支撑的,就更不用说,当系统复杂到演变为下面的场景时:
当系统演变为由几百、几千个应用组成的时候,要做一次活动,请问到底要加多少机器,每个应用又加多少台呢;
加的机器一个机房都装不下的时候,那该怎么办呢;

很多时候架构演变要解决的主要问题就是怎么让系统能做到仅靠加机器就能支撑增长的流量,规模问题随着规模的数量级的变化,遇到的挑战会更加的大,从而也会导致系统的架构更加复杂。

这里还没有说加的机器实在太多了,成本该怎么控制住的问题,所以要做到加机器其实真心不low,一个极强的架构师,需要能根据人力的投入、规模增长的预期来权衡在一个架构版本中需要支撑到的规模级别,合理设计架构,从而确保在一个周期内可以仅靠加机器就解决,并同时又确保了在下一个周期到来前已经做好了各方面的技术积累和准备。

第二个点:切流量
有些人看到阿里这边碰到系统出问题的时候切流量这招,会觉得很low,但事实上我们简单来看下,切流量通常指的是把一个机房的流量切到另外一个机房,初级的版本是切流量到同城的另一个机房,这里要解决掉一些技术问题才能做到:
1. 数据库等的地址切换,当做流量切换时,通常是一个机房内出了不确定的故障,因此通常数据库也需要做好主备的切换,除了数据库外,可能还会有其他的一些指定的地址,这个时候都应该做到在不需要重启应用的情况下完成地址切换,这说实话如果在一开始系统简单的时候没有管理好这些地址类型的信息的话,等到系统复杂了再来做这个还是挺花时间的;
2. DNS disable vip,这里就是一个很容易被说到的点,DNS是没有健康检查的,因此当要拿掉一个机房的vip时,就必须等待dns生效,但其实这个是有一招可以来解掉的。

如果是异地的机房的流量切换,就更加复杂了,由于异地的情况下网络的延时会是一个大型分布式应用没法接受的,这个时候通常会启用异地多点写,而要做到这一点就已经非常不容易了,只有在做到这一点的情况下,才有得说异地机房切流量这一说,而在做到的情况下,怎么保障异地机房切流量时的数据的正确性是非常关键的点,感兴趣的可以看下我在这片文章里讲的关于异地多活的技术点。

所以和加机器一样,我们可以看到切流量这招的背后也是需要有强大的技术支持的,我自己是认为切流量是提升系统可用性的极为有效的大招,在多个机房且可以快速切流量(要做到快其实也非常的难)的情况下,单个机房内无论出现任何故障,都可以仅仅靠切流量来应对,这对提升系统的可用时间是非常有帮助的。

欢迎大家讨论这里面讲的一些点,:)

=============================
欢迎关注微信公众号:hellojavacases
题目来源:http://www.bhmpics.com/wallpapers/low_battery_logo-1680×1050.jpg

关于此微信号:
分享Java问题排查的Case、Java业界的动态和新技术、Java的一些小知识点Test,以及和大家一起讨论一些Java问题或场景,这里只有Java细节的分享,没有大道理、大架构和大框架。

公众号上发布的消息都存放在http://hellojava.info上。

我所关注的Java问题(Cont.)

上篇遗漏了两个关心的问题忘了写,继续补充下。

第一个是类隔离的问题,相信多数的Java开发同学都被类冲突的问题折磨过,maven为避免类冲突起到了一定的作用,但对于groupId、artifactId不一致,但又有同样full classname的类冲突,maven也无能为力,很不幸的是这种无节操的行为在Java应用中相当的多,即使是开源的项目中也一堆这种,因此类冲突带来的问题经常会是大家已知的一个不定时炸弹,但又不想去解决,等着看看Java 9中最重要的模块化的功能会实现的怎么样,话说模块化这功能推了真心够多年的。

第二个是Java应用对硬件资源消耗的分析工具,例如在目前的情况下,如果想知道一个Java应用的CPU消耗是哪些代码造成的,还真的是相当的折腾,perf和JVM的结合不是很好,本来perf应该是足够了,内存如果想知道主要是哪些代码造成的消耗,也同样非常折腾,尽管有Flight Recorder会起到一定的帮助作用,不过这块真心没看到官方有什么想法,估计只能靠自己。

关注的Java问题这篇没得到什么回应,或者换个问法,大家对Java有什么期望吗,你会期望Java支持一些什么特性,原因是什么。

Oracle官方的JDK 7又停止更新了,让大多数人估计都一定程度陷入了尴尬,尤其是对于用6的同学,稍微调查下大家现在用的JDK是什么版本呢?

=============================
欢迎关注微信公众号:hellojavacases

关于此微信号:
分享Java问题排查的Case、Java业界的动态和新技术、Java的一些小知识点Test,以及和大家一起讨论一些Java问题或场景,这里只有Java细节的分享,没有大道理、大架构和大框架。

公众号上发布的消息都存放在http://hellojava.info上。

我所关注的Java问题

Java作为一个发展了多年的语言,由于历史包袱等原因,自然会有不少问题,这里讲的是Oracle Hotspot(其他的JVM会有些不同),我最关注的主要是以下几个:

1. 对大内存的支持
内存容量发展越来越大,而自然Java应用也会越多的面对大内存的场景,目前Java在大内存的情况下,有两个主要的问题:
* GC问题,CMS GC最大的问题是碎片,碎片所导致的不可预知的Full GC的行为是非常可怕的,我们都有好几个应用开始要在每天低峰的时候强制执行full gc来避免碎片问题,G1GC也仍然是有碎片问题的…
* 排查问题,大内存的情况下dump、分析目前的Hotspot支持的都非常糟糕。

2. 启动瞬间慢的问题
Hotspot在刚启动时是解释模式,逐步才编译为native代码,因此一定会出现启动瞬间慢的现象,这个问题很容易导致有些访问量很高的应用在启动瞬间会出现非常多的请求失败的现象,尽管目前Hotspot也做了很多的努力,例如TieredCompilation等。

3. coroutine
很多的Java应用在处理请求时都会有大量的访问后端的行为,例如访问数据库、调用其他应用等,由于是线程模式,会导致在支撑很高的并发时会比较容易达到瓶颈,而coroutine对于类似这样的场景,会有不小的帮助。
而更进一步,对于分布式的Java应用来说,在一次请求中可能会有大量的并行的后端调用,这种时候如果是线程模式也不是很好做。

4. 序列化/反序列化
这个算比较特殊的一个点,在一次请求要访问非常多后端的情况下,序列化/反序列化通常会成为很重要的一个CPU的消耗点,而根据我们以往的排查我们能看到主要的原因还是在序列化/反序列化中从对象到流,以及从流到对象的过程,所以如果能在这里有突破的话,会对分布式的Java应用有很大的帮助。

5. 字符串append
之前我们在分析Java应用的内存消耗时,会看到StringBuilder/StringBuffer.append造成的char[]数组的扩充造成了主要的内存消耗,而其实这个如果有改进是可以大幅减少内存消耗的压力的(在我们的很多应用上,我们可以看到在很高并发量时GC占据的CPU还是不少的)。

这里还有一个牛人写的JVM implementation challenges的pdf,感兴趣的也可以看看。

你有什么特别关心的Java问题呢,也可以回复我说说看。

=============================
欢迎关注微信公众号:hellojavacases

关于此微信号:
分享Java问题排查的Case、Java业界的动态和新技术、Java的一些小知识点Test,以及和大家一起讨论一些Java问题或场景,这里只有Java细节的分享,没有大道理、大架构和大框架。

公众号上发布的消息都存放在http://hellojava.info上。

说说高大上的职业规划 for “码农”

职业规划,这个词说起来总感觉很虚,还有点高大上,不过对于几十年的职业生涯而言,职业规划确实还是挺重要的(尤其是工作了几年以后),说说我对“码农”的职业规划的看法(适合往管理方向发展的就不在这里说了),求轻拍。

“码农”主要分业务研发和基础研发,业务研发包括了各种编码实现业务的研发和架构师;基础研发包括了各种更偏基础技术产品的研发和架构师,例如内核、JVM等。

业务研发适合的发展方向我认为是业务PD、业务研发架构师和基础研发,业务研发要做好我觉得除了基本技术外,最重要的是商业敏感性,商业敏感性决定了在实现业务的时候能否为业务将来的发展模式做好铺垫,避免业务变化导致结构推翻,如果商业敏感性不错,可以考虑往业务PD或业务研发架构师的方向发展,更喜欢偏技术一点的话就选业务架构师,更喜欢偏纯业务的话就选业务PD,如果商业敏感性不是很够或没兴趣,并且对基础技术更感兴趣的话,我觉得更适合的发展方向会是朝基础研发方向发展。

基础研发适合的发展方向我认为是基础研发专家、平台架构师和业务研发。

如果优势更偏向于商业敏感性,适合的是转向业务研发方向发展。

基础研发专家和平台架构师这两个发展方向主要取决于个人对专和广的爱好,例如像JVM、内核就是非常专的方向,如果个人的兴趣和优势主要是做这类专的方向,我觉得整个职业规划是最好做的,就是在某个领域不断深挖就行,这类方向在大规模的公司中需求会比较强烈;另外一个方向是平台架构师,平台架构师适合喜欢在广度上发展的同学(或者没能力在专业领域做深),平台架构师最需要的是技术的广度、视野、眼光和平衡的能力,技术的广度是指技术的全栈掌握,软件不仅仅是编码实现,还得考虑实现后运行起来需要投入的成本、持续维护的能力,视野是指掌握业界在相应技术领域更前进一步的做法,眼光是指能够看到技术领域的发展方向,并且能够看到业务将来发展会带来的基础技术的挑战,平衡是指能根据现状(团队、目前的结构、时间)来权衡架构的发展节奏,这个是最难做到的。

所有的发展方向其实都不存在哪个能NB,哪个更low的问题,只有哪个更适合自己的问题,这主要取决于个人的优势和兴趣,另外还需要考虑的一个因素是长期的职业规划,例如以后是想创业做CEO,想加盟创业公司做CTO等,这也会很大程度影响到在一家公司的职位的选择。

最后例行的夹带点私货,:),我的团队很适合往基础研发专家、平台架构师方向发展的同学,在基础研发专家方向上提供了专业的性能、成本和可用性的三个方向,这三个方向的团队成员将专注于相应领域的技术,并且向全局业务负责;在平台架构师方向上我的团队所在的部门是一个全栈技术的部门,涉及到软件架构、服务器、网络、IDC等,对拓宽技术广度会有很大的帮助,这对成为一个平台架构师非常重要,另外我的团队也同样提供了专职做架构的职位,去考虑规模和业务多元化发展带来的架构挑战的问题,感兴趣的同学可以微信回复来联系我,非常期待!

=============================
欢迎关注微信公众号:hellojavacases

关于此微信号:
分享Java问题排查的Case、Java业界的动态和新技术、Java的一些小知识点Test,以及和大家一起讨论一些Java问题或场景,这里只有Java细节的分享,没有大道理、大架构和大框架。

公众号上发布的消息都存放在http://hellojava.info上。