回顾过去看IaaS的Next

IaaS层经历了多年的发展,这里也只能以我自己所经历的来进行回顾,之所以要回顾,是为了通过过去的发展,来看这个领域发展的动力,从而更好的创新,引领未来。

物理机->虚拟化阶段


阿里大概是在2010年开始用Xen来做虚拟化,推动这件事的是另外一位同学,问了下他,当时推进这件事最大的动力是两个,一是资源管理方式,在虚拟化前,都是直接用物理机,物理机的规格会不同,这会导致在LB上配置起来非常麻烦(我印象中记得以前我们在LB上开启权重,导致了一次严重故障,后来就不太敢用了),另一个是成本,站在外围,我看到的最主要是成本,不过说实话,以当年阿里的机器规模而言,尽管通过虚拟化把1台物理机虚拟成3个虚拟机,节省的机器比例看起来是非常高的,但由于盘子就这么大,所以这点成本在当时很难成为推进演进的关键因素,但资源管理方式那个确实是个推动的非常好的动力,因为那个是会影响稳定性的。

这件事我印象中当时的推进还是比较顺利的,主要的原因应该还是虚拟机和物理机还是非常像的,当时因为虚拟化这件事推进,我还写了淘宝当时比较统一的一版Java应用启动参数,后来在进展了可能两年后,阿里尝试把Xen换成KVM,但当时上线碰到了些问题,后来就没去尝试了,直到后来阿里云做虚拟化,阿里在虚拟化的技术掌控能力才真正的开始变得非常深入。

这个阶段的演进动力主要是为了更好的屏蔽机型不同,资源归一化,次要的是成本,现在的云用虚拟化最主要的还是为了提供多种类型的资源规格。

虚拟化->容器化阶段


2011年,我看了《Web容量规划的艺术》这本书后,觉得运行成本对于一家公司是非常重要的,从自己的技术角度来看,降低机器数是一个有效的方法,于是就去想有什么办法可以降低机器总数,找人拿了机器的一些数据后,看到机器的整体利用率是非常低的,于是想既然一虚三利用率还很低,那能不能在一台机器上跑更多呢,了解了下,如果用虚拟化的方法的话,内存超卖不好弄,所以就得找另外的办法。

和多隆说了这个想法后,多隆也很感兴趣,于是就来摸索有什么办法,最早的时候尝试了直接在物理机上跑多个业务进程,结果碰到了各种冲突的问题,例如典型的监听端口冲突,更麻烦的是运维,因为出问题了,不知道哪个应用,查起来特别麻烦,于是觉得直接跑进程不行,还得有一定的隔离性,这个时候尝试了各种黑科技,例如自己改sshd、各种命令行对应的背后的函数,确保可见的隔离性,但这个方法的最大问题是无法穷举,所以总是有各种问题。

突然有一天多隆和我说有个叫Linux Containers(LXC)的东西,好像可以很好的满足需求,于是开始试验,基于LXC包装了我们自己的代号叫T4的容器,我们把这个东西改造的和虚拟机特别像,对于用户来说登录到T4的容器,所有的感受和虚拟机几乎是一样的,这个方案从落地执行角度来说就比较好推进了,毕竟对用户来说几乎是无感的,并且到了2012年,机器资源的申请也变的比较紧张,T4可以用更少的物理机提供更多的“虚拟化”资源,比较受用户的欢迎,到了2013年,交易的核心业务开始切换到T4后,后面的推进就越来越快了,于是阿里就此迈进了IaaS层主体是容器化的时代。

这个阶段的演进动力主要是对规模化后成本控制诉求的预判。

容器化阶段->容器+Docker镜像阶段


2015年,Docker火爆,我们也开始尝试将Docker的镜像+T4的容器进行结合,在这个尝试的过程中,我们切实的感受到了容器+镜像化给运维带来的巨大改变和帮助,这里要多说几句,当时我们对Docker的镜像机制能带来多大帮助一直存有质疑,争论非常大,所以从这件事来看很多东西还是得试试才知道,对于应用而言,在没有把容器+镜像结合起来以前,部署方式通常都是先申请机器资源,然后在机器资源里部署应用,但应用由于有各种语言、架构,所以部署的方式通常会有很大的区别,这个时候对运维类型的系统就非常复杂了,但容器+镜像这种方式使得交付应用这个过程标准化,把交付的这个概念从分离的机器资源到应用部署这两个过程合并了,这对实际业务而言才是更加合理的,有了容器+镜像这种方式后,运维的变更就可以用一套统一的运维平台来标准化了,当然,这也不是Docker首创的,Google家很早前就是这样,但可惜Google当年没开源,导致镜像的标准化现在基本是Docker的格式。

容器+镜像这种站在交付的最终产物诉求的思想延伸到了后来接下去的一些产品的进一步创新中,例如Terraform、Helm等。

这个阶段的演进动力主要是更好的满足交付物的诉求,而这种的结果就是在下层的东西会越来越不可见。

容器+Docker镜像阶段->统一调度阶段


这几年阿里除了在继续推进容器+镜像化(这个产物已经开源:PouchContainer)外,另外一个很大的演进是推进统一调度,推进这个的诉求主要是成本,容器化后可以看到机器上就算能运行更多的容器,但成本下降的还是不够,因此继续进一步看,非常显然的问题还是资源利用率不够高,在做T4的阶段,就听说了Google的Borg,Borg最重要的是通过把资源都归拢在一个池里,并且通过在线任务和离线任务部署在同一台机器(混部)上来大幅提升资源利用率,统一调度可以用一个非常简单的指标去评估做的怎么样,就是平均的资源利用率,Google家大概应该在50%,阿里目前开启了混部的集群一个月下来的CPU平均利用率大概在40%上下,这个阶段的方向是非常清楚的,但要做到这样的程度,对基础设施、内核的改进、调度系统的建设都有很高的要求。

这个阶段的演进动力主要是成本的诉求。

IaaS的Next


以上的各个阶段的演进的具体技术细节在阿里系统软件的公众号里都有分享,感兴趣的同学们可以去找找看。

回顾上面几个阶段的发展,我们能够看到,IaaS的发展/创新主要有两个非常明显的点:

  1. 成本IaaS层随着规模的不断增大,成本的优化动力会越来越大,从目前的状况来看,怎么更好的优化资源利用率仍然是IaaS层技术创新的核心动力,这个对于云厂商而言,一方面是优化自己的利用率,另一方面是给用户更好的提升资源利用率的产品;软硬件结合也是目前看到的另外一条很好的路径。
  2. 被屏蔽从物理机->Xen/KVM->容器->K8S/Terraform/Helm,可以看到非常明显的趋势是IaaS越来越被标准化接口屏蔽,未来上层会越来越不关心IaaS的这个具体的运行单位是什么(但始终会需要安全、资源的隔离性,至少是可见的隔离,以及越来越强调的启动速度),从目前的状况来看呢,具体的运行单位在3-5年内应该还会是容器,但容器下面是什么就出现了非常大的优化机会,从硬件,到虚拟化,到操作系统,这两年无论是Google,还是AWS,都已经开始展现了下面这几层的优化创新(gVisor、Firecracker等),但现在并没有霸主出现,这种机会就像是虚拟化刚诞生的阶段,是多年才能一遇的。

按照这样的创新路线下去,技术门槛太高,未来IaaS这层大部分企业都没有能力自己做,不像以前弄个Xen或者KVM,大家差距就很小,以后还是直接用云就好了,毕竟人才也多数会被这些公司垄断掉,云的公司一定会在IaaS这层继续加速演进,并且由于动力大,我相信会比前面很多年IaaS层的技术演进速度快非常多,对云类型的公司而言,比拼对IaaS层方向的掌控力会至关重要,我的建议是围绕在优化资源利用率、软硬件结合、从成本/启动速度等角度思考彻底重写容器下的各层三大方向来进行IaaS的优化和创新,当然,其实方向很多人都能看到,但是否能坚定的在方向上走下去最终会成为分水岭,这也同样意味着方向的判断就非常重要了,毕竟技术的创新不像业务模式,它需要更长的时间。

最后用一张图总结上面所写的:


欢迎关注我的公众号hellojavacases,

聊聊编程能力的高级进阶,

聊聊系统设计,

聊聊技术方向,

聊聊职业生涯的发展。

开发者生态,未来云的胜负手?

过去一年云厂商在开发者生态上的争夺开始变得激烈,为什么会出现这样的现象呢,是不是开发者生态,已经成为了云这场战争的胜负手呢?这篇文章就来探讨下这个话题。

事件


我们先看看在过去一年发生的几起重要的开发者生态的事件:

  1. 微软75亿美金收购Github,Google领投1亿美金Gitlab,使得Gitlab估值突破10亿美金;
  2. Coding获腾讯云一亿元战略融资;
  3. 开源厂商 Vs 云厂商开源厂商和云厂商在2018年发生了非常多的状况,关系在开始变得微妙,有几种现象出现:1). MongoDB、Kafka、Redis纷纷修改开源协议,限制云厂商,Neo4j企业版不再提供免费下载;

      2). 微软在2018年非常明显的加大了在开源的投入,上面说到的收购github,还有例如加入OIN,开源的VS Code在2018年是github上吸引到最多contributor的项目;

       3). Pivotal、ElasticSearch上市,目前的市值都超过50亿美金,Confluent(主要产品Kafka)、Databricks(主要产品Spark)宣布完成新一轮融合,市值均突破25亿美金,国内的话主要是Pingcap完成的新一轮5kw美金的融资,致敬下,作为技术人员对在国内能创办出Pingcap这样的技术产品公司无比佩服;

        4). 阿里巴巴9kw欧元收购Flink母公司,微软收购开源公司 CitusData(PostgreSQL 商业化的Startup);

海外三家云厂商的观点


再来看看海外几家云厂商自己在开发者生态这块传达的信号:

  1. AWS”大概12年之前,我们深知云将给软件带来翻天覆地的变化,我们创造了AWS。一直以来AWS希望与软件开发者密切合作,打造出一个现代化的软件开发框架。而不是告诉客户,你们需要什么工具。在AWS的信念中,我们认为真正知道软件应该如何开发的只有一个人,就是客户本人。”这是AWS CTO在去年中国的AWS Summit上讲的,其实在其他很多场合,尤其是每年的AWS:reInvent上也都会不断的表达这个观点,就是AWS和软件开发者是在一起的,AWS的会议吸引了无数顶尖开发者参加和关注,毕竟里面讲的很多都是未来的软件发展趋势。尽管Amazon给人的感觉在开源上贡献不大,但在技术发展的引领上我觉得还是起到了不小的作用的,在开发者群体中的认可度也足够高。
  2. 微软
    微软作为一家操作系统起家的公司,在开发者生态上一直就非常重视,而随着云的发展,感觉更进一步了,除了上面的github收购外,微软也开始非常大力的加大在开源上的投入,可以说,微软对开源的贡献是非常有助于推进这个世界技术的发展的,微软之前的形象开始有了不少的扭转。
  3. Google

       Google早期通过发表论文,在开发者群体中得到了非常高的认可,同时也非常切实的影响了世界的技术发展,例如大数据领域。

       近几年Google通过各种开源,更是形成了不错的开发者生态,无论是K8S、TensorFlow,都对世界技术的发展起到了很大的推进作用。

       Google Cloud的CEO最近还公开的讲”谷歌云:我们对开源的态度与AWS不同“来怼AWS,讲的核心的一段是”一直以来,谷歌云采取与开源社区合作的方式,而不是在自己的云平台中使用并出售开源技术。“,结合上面的开源厂商 Vs 云厂商的一些事件来看这段就更明白了。

关于开发者生态,我的观点


从上面的这些内容可以看到的现象是,各家云厂商都在通过开源、收购等方式加强对开发者生态的投入,拥有众多开发者用户的开源软件厂商在资本市场得到了很好的认可,开源厂商和云厂商由于利益上的冲突,关系尚待理清。

开发者生态为什么会发展到今天的这个局面,必须说说云的发展趋势。

最早用户对云的使用基本是纯粹的使用机器资源,和以前的虚拟主机等其实没有太大的区别,而发展到今天,几个大的云厂商强大的资源集约形成的规模效应,更是让用云的机器资源这件事成为了不需要再纠结的点,尤其是对初创公司而言。

随着对云机器资源的使用后,慢慢的开始有了用户开始使用更多的云的软件服务,例如存储、数据库等,在美国这个趋势非常明显,越来越多的公司画的技术栈中有越来越多的云软件产品的出现,下面这张图是Next Platform上对于AWS中计算、存储、网络和软件收入的分析:

可以明显看到软件这块越来越高,意味着越来越多的用户除了使用云机器资源外,开始使用云软件服务。

从对客户的价值上来说,越多的使用云软件服务,也就意味着自己在这方面投入的人员可以大幅减少,更加专注在自己的业务上,这一点随着经济形势的变化会更加的重要,而站在云厂商角度呢,客户使用越来越多的产品当然是更好,所以从趋势上来说,越来越多的使用云软件服务会加速。

而从技术趋势上,看到非常明显的两点:

  1. 通过PaaS屏蔽IaaS,对客户价值而言这是非常有益的,同时对云厂商来说也意味着IaaS层拥有了巨大的创新机会,以及不透明后带来的利益机会;
  2. No Lock-in,由于越来越多的使用云软件服务,客户心里上会非常担心Lock-in的问题,尽管我认为不会有多少客户真的同时部署在多家云上,但一定会需要具备这个能力,就是可以很简单的进行切换。

从这些趋势来看,也就意味着云的竞争进入云软件竞争的时代,云软件的用户群体是开发者(当然,有另外一种观点是通过强有力的SaaS软件直接服务最终用户,但我认为那样覆盖的面始终是有限的,云厂商自己很难去做好各种SaaS,只能是构建好一个平台,让上面有更多的SaaS厂商),并且软件和其他很多产品不一样,尤其是那些渗透到代码中的API,通常来说切换的代价很高,例如开发框架用了Spring,要想切换成别的很复杂,所以这层的竞争非常重要的一点就是谁能拥有对应最核心的非标准化领域的最多的开发者用户,也就是开发者生态。

要想获得开发者用户,和2C的很多产品竞争完全不同,这个领域基本不是靠砸钱就能获得用户的,很重要的三点是:

  1. 开源触达通过开源,让更多的开发者用户能即使不使用云软件服务的时候也能接触到,从而培养大量会用的开发者。同时借助开源,也可以更好的吸收各行各业的需求,使得产品更加的具备通用化的能力,覆盖更大的规模和更广的场景。怎么做好开源,对中国的公司是很大的挑战,这里面的套路非常的深。成功的开源软件因为在相应领域覆盖了大量的开发者用户,当在云上推出相应的商业服务时也会自然的收获用户,但由于目前这些利益基本都被云厂商拿走,这让相对应的开源厂商的努力得不到回报,导致产生矛盾。关于云厂商和开源厂商的关系,我觉得在2019应该会进一步明晰,一方面云厂商自己会加强在核心领域的开源,触达更多的开发者用户,另一方面会通过收购去补强核心领域的能力,很多人可能觉得这样不好,但我还是坚定的认为正因为有商业利益的诉求,这样的开源反而才能更为持续、健康快速的发展,对这个社会的发展而言是更有利的。开源对这个世界的技术发展、业务创新是起到了很大的帮助的,真心希望这个世界越来越多的开源,而不是越来越封闭。
  2. 技术领先在开源界中,同技术领域同质的产品基本只会留下一个,必须保持持续的技术领先,否则就算一个阶段领先,也很容易在下一轮技术迭代中格局被改变。
  3. 工具触达

       触达开发者用户的另一个很好的方法是工具,开发者用户群体最大公约数的工具是IDE,这大家就很容易看懂为什么微软开源vs code,并且那么重视,另外一个方面的工具就是开发流程方面的,代码是整个开发流程流转的核心产物,这也是Github巨大的价值。

综合来说,我认为开发者生态是未来云的胜负手的关键,从上面也可以看出,要做好开发者生态并不简单的是一件运营的事,而是产品规划、技术创新、社区建设、工具建设、运营等一起的事,这也是为什么我们看到海外的几家云公司是把这个上升到非常高的高度的原因。

最后,对于中国做这块的创业公司而言,我认为以下的两个方向是非常好的时机点:

  1. 社区一个优秀的开发者社区对形成繁荣的开发者生态是至关重要的,无论是问题、讨论、线下活动等,国内现在好像已经基本没有优质的开发者社区了,前几年还是有几个的,可惜当年做社区的同学都太难获得利润,导致很难运转下去,但到了今天这个局面下,我觉得会很有机会,不过要做起一个社区必须有长时间投入的打算。
  2. 开源技术产品技术领域需要的产品其实是非常多的,即使是云厂商自己,也很难去全部覆盖,因此这个方向的机会空间还是不错的,首先需要的是对相应有一定规模的技术领域的洞察,影响力,同时需要长时间的投入和经营。

衷心希望看到国内在为程序员这个行业群体服务的创业越来越繁荣,那样一定会让中国在IT技术层面逐渐对世界产生越来越大的影响力,更好的推进世界技术的发展。


欢迎关注我的公众号hellojavacases,

聊聊编程能力的高级进阶,

聊聊系统设计,

聊聊技术方向,

聊聊职业生涯的发展。

来测试下你的Java编程能力

上篇整理了下后面准备更系统化写的Java编程进阶的思路,如果仅看里面的词,很多同学会觉得都懂,但我真心觉得没有多少人是真懂的,所以简单的想了一些题目,感兴趣的同学们可以来做做看,看看自己的Java编程水平怎么样。

懒得去做小程序了,所以大家就直接回复你的答案吧,我会来一一点评下,友情提醒下,有些题目有点坑。

  1. 基于BIO实现的Server端,当建立了100个连接时,会有多少个线程?如果基于NIO,又会是多少个线程? 为什么?
  2. 通常来说基于NIO实现的Server端,会用多少个线程去处理IO事件,为什么?
  3. 一个典型的客户端集群->LB->服务端集群这样的结构中,如客户端采用连接池,长连接的方式,这种设计你觉得可能会出现什么问题?如果客户端采用的是单个长连接的方式呢?如果有问题,你觉得应该怎么解决?
  4. cglib和Java的动态代理相比,具体有什么不同?
  5. 在基于Netty实现FrameDecoder时,下面两种代码的表现会有什么不同?第一种
  6. private void callDecode(…) {       List<Object> results = new ArrayList<Object>();       while (cumulation.readable()) {             int oldReaderIndex = cumulation.readerIndex();             Object frame = decode(context, channel, cumulation);             if (frame == null) {                  if (oldReaderIndex == cumulation.readerIndex())                        break;                  else                       continue;            }           else if (oldReaderIndex == cumulation.readerIndex()) {                  throw new IllegalStateException( “…..”);            }            results.add(frame);     }     if(results.size() > 0)         fireMessageReceived(context, remoteAddress, results);}第二种private void callDecode(…) {
           int oldReaderIndex = cumulation.readerIndex();       Object frame = decode(context, channel, cumulation);       if (frame != null)              fireMessageReceived(context, remoteAddress, frame);}
  7. 用Executors.newCachedThreadPool创建的线程池,在运行的过程中有可能产生的风险是?
  8. new ThreadPoolExecutor(10,100,10,TimeUnit.MILLISECONDS,new LinkedBlockingQueue(10));一个这样创建的线程池,当已经有10个任务在运行时,第11个任务提交到此线程池执行的时候会发生什么,为什么?
  9. 实现一个自定义的ThreadFactory的作用通常是?
  10. 除了用Object.wait和Object.notifyAll来实现线程间的交互外,你还会常用哪些来实现?
  11. 为什么ConcurrentHashMap可以在高并发的情况下比HashMap更为高效?
  12. AtomicInteger、AtomicBoolean这些类之所以在高并发时高效,共同的原因是?
  13. 请合理的使用Queue来实现一个高并发的生产/消费的场景,给些核心的代码片段。
  14. 请实现让10个任务同时并发启动,给些代码片段。
  15. 在Java程序运行阶段,可以用什么命令行工具来查看当前Java程序的一些启动参数值,例如Heap Size等。
  16. 用什么命令行工具可以查看运行的Java程序的GC状况,请具体写出命令行格式。
  17. 用什么工具,可以在Java程序运行的情况下跟踪某个方法的执行时间,请求参数信息等,并请解释下工具实现的原理。
  18. 当一个Java程序接收请求,很长时间都没响应的话,通常你会怎么去排查这种问题?
  19. Java进程突然消失了,你会怎么去排查这种问题?
  20. 以下这段代码思路,你觉得在运行时可能会产生的风险是,应该如何改进?public List<User> getUsers(String[] userIds){       // 从数据库查找符合userIds的user记录      //  将返回的记录组装为User对象,放入List并返回
    }
  21. 以下两种代码,在运行时有什么不同?为什么?第一种private static final boolean isLoggerDebugEnabled = log.isDebugEnabled();
    public void xx(User user){     if(isLoggerDebugEnabled){          log.debug(“enter xx method, user id is: ” + user.getId());     }}第二种public void xx(User user){
         log.debug(“enter xx method, user id is: ” + user.getId());}
  22. Java程序为什么通常在刚启动的时候会执行的比较慢,而处理了一些请求后会变快,AOT能带来什么帮助?
  23. Parallel GC、CMS GC、ZGC、Azul Pauseless GC最主要的不同是?背后的原理也请简单描述下?
  24. 请写一段程序,让其运行时的表现为触发5次ygc,然后3次fgc,然后3次ygc,然后1次fgc,请给出代码以及启动参数。
  25. Go的Coroutine和Java的线程机制最主要的不同是?如果Java语言要透明的实现Coroutine,你觉得主要的难点是?

欢迎关注我的公众号hellojavacases,
聊聊编程能力的高级进阶,
聊聊系统设计,
聊聊技术方向,
聊聊职业生涯的发展。

大部分公司并不需要微服务

本来之前标题的名字是不要被技术buzzword误导,觉得还是得标题党一些,:),请大家谅解,技术圈时长会不断的产生一些新的buzzword,很容易被误导,最可怕的是一些技术团队在没搞明白的情况下,就按buzzword去做或者去靠拢,好像生怕如果自己做的技术和buzzword不相关或者不一样,就很low一样,感觉这现象在技术圈太常见了,有些看的不太爽,写篇文章来讲讲自己的观点。

作为技术圈的我们大家,对各种buzzword一定要慎重,了解它产生的背景,可执行的各种前提和条件,技术始终是为公司的战略而服务的,buzzword是不是真的给你的场景带来了帮助,要想清楚,拿时下比较流行的微服务、AI、AR/VR来说说吧。

说到微服务这个buzzword,必须承认到现在为止我都没搞明白和服务化的区别,我都搞不太清楚淘宝在2008年做的服务化改造后形成的SOA体系到底是不是和现在的这个buzzword就是一回事,在各种文章里,微服务简直就被宣传的像是技术界一些场景的救世主,直接误导了很多同学上来就必搞微服务体系,但不知道有多少同学仔细想过有没有必要,对业务发展来说采用微服务到底是帮助还是变成了阻碍,在互联网类型快速迭代的业务中,业务的迭代效率是核心问题,以我自己的认知,对服务化我的观点一直是如果能不进这个坑,最好不进,一个单一应用的复杂度远比N个应用组成的分布式系统简单、快速多了,一旦进入分布式的坑,在技术上就不得不有比较大的投入,而对于一些还处于中小规模的公司而言,我觉得完全没有必要,Google的Jeff Dean在一次分享时讲到他对于Google做服务化的观点:让Google具备了千人并行协作开发的能力,在看到这观点以前,我一直觉得服务化重点解的是水平伸缩能力的问题,其次是并行协作的问题,但我现在基本更加赞同服务化重点是让一家公司具备了百人以上的并行协作开发能力,我认为在几十个研发同学的情况下,并行协作开发不会成为太大问题,这个时候的并行协作上的一些投入会远比进入服务化后的投入小很多,所以以前有一些朋友问我公司到底要不要改变为服务化时,我都问两问题:1. 公司研发团队现在总共多少人? 2. 目前的水平伸缩瓶颈是? 如果在这两个问题上服务化并不是核心的瓶颈,或者只需要付出少量的人或机器代价就可以解决,我会强烈建议不要做服务化,所以拜托受微服务这个buzzword诱惑的同学们,请大家在采用这样的架构前一定,千万要慎重思考,策略应该是以尽量不采用去推导会产生的代价和问题,如果这个代价和问题并不是那么大,就不要用,除非真的万不得已,那就请做好组织、团队人员方面的布局,以真正的做好服务化,不要让这个东西最后变成业务发展的障碍。

说说AI这个buzzword,我拿运维这个领域来举例说吧,AI实在是太火了,同样导致了运维界很多的工作也恨不得赶紧和AI绑上关系,当然不可否认的是,在运维这个领域,AI绝对是可以产生巨大帮助的,但首先要想明白的是你的整个环境真的为AI做好了准备吗?没想清楚这个问题,很容易最后出现一个状况是,各种算法,智能动作等等都准备好了,结果是基础的技术层面或环境层面压根就不具备这个能力,一切白扯,例如在运维这个领域,我认为要引入AI让其发挥作用,前提是要先把数据化、自动化、无人化做好,如果连这些都没做好,千万别先跳进AI的坑,AI通常依赖大量的数据去智能化的执行动作,这种情况下没有数据,不能自动执行,自动执行过程中需要人介入,那都意味着没法玩,很典型的在运维领域的一个case,容量的弹性伸缩,如果连判断一个应用容量够不够的数据都不充分,连应用能自动部署和启动都做不到,那先做了一个弹性伸缩的系统又有什么用呢?所以我更赞同的是AI确实是前景,但首先要把AI需要的一些前提给做好了,然后再进坑,千万别走反了。

最后说说同样极度火爆的AR/VR,AR/VR是个非常复杂的话题,同样很多的业务一冲动就决定投入大量资源去玩这两个方向,觉得不玩就挂了,但在玩这两个方向前,同样要想清楚的核心问题是,对于你的业务场景而言,AR/VR的一些技术普及的条件是不是都具备了,例如你生产了AR/VR内容,但现在的AR/VR的用户数,AR/VR设备的情况是不是真的到了值得你投入大量资源去做,君不见很多创业公司在做app的时候都先只做ios版本。

所以总的来说,就是技术圈的各种流行buzzword呢,当然会有它一定的道理,但是不是真的要去采用,千万别纯粹跟风,或者纯粹从技术角度判断,仔细的思考如果要采用buzzword,会发生什么,要做好什么样的准备,能获得什么样的收益(这和每家公司的战略地位,业务发展情况直接相关),毕竟一家公司的资源都是有限的,进了一个坑就意味着另一个坑可投入的资源少了。

系统设计的核心:设计原则

各种系统设计文档中,都会有专门的设计原则这个篇章,我记得我在几年前写系统设计文档时,都会觉得这个部分没什么可写的,通常会随便写上几条类似松耦合的原则,并且在之后的概要、详细设计中也不会有什么和设计原则这个部分太相关的部分,这种情况下就会越来越觉得设计原则这个小章节可写可不写,随着近几年从做单一系统到更广的多团队协作的大系统设计后,对设计原则这个章节需要传达的信息有了更多的理解,这篇文章就来谈谈自己的一些感受。

设计原则并不是什么空话,我认为设计原则表述的是架构师对整个系统的核心设计思想,并且要求把这个设计思想贯穿到所有子系统的概要/详细设计中,所以在这些子系统的概要/详细设计中要充分体现出对设计原则的考虑。

对于系统而言,什么才是设计思想呢,每个架构师在做系统的设计之前一般是会有思考的,思考的内容基本就会是要实现需求核心的几个点是什么,这些核心的点就是设计思想,举两个我自己做的设计的例子来说下,会更容易理解一些。

1. 当年在做T4(基于LXC的“虚拟化”产品)时,T4相对以前的Xen,是一个全新的替代产品,在思考T4的设计时,除了一些技术选型外,很重要的一点我判断是对用户透明,对用户而言要做到用的是T4,还是Xen,都感受不到区别,这一点必须贯穿到T4所有部分的设计中,因此这一点就是我当时列入设计原则的。

2. 前几年在做异地多活的设计时,异地多活中最重要的特色是多个异地的机房的数据库都是可写的,在这种情况下在设计的时候要考虑的重点我认为是数据正确性的问题,怎么保证用户数据不会写错乱是关键,所以在设计原则上我写入了数据正确性这条,这样确保了后续在整个跨多个技术领域的子系统的设计中都能仔细考虑数据正确性如何去做到。

3. 还有在做某些系统的设计时,平滑迁移我认为是项目能成功的关键因素,所以在设计原则上我也会写上平滑迁移,确保各个子系统在设计时会把如何从现有迁移到新的结构上放入关键。

从上面的几个例子可以看到,设计原则不仅仅需要表达设计中的一些非常技术层面的共同点(例如关键路径/非关键路径的划分、非关键路径的异步化等),更重要的是表达风险控制要素和优先级,确保在多人合作时整个项目的技术、时间风险的可控,对于一个架构师而言,如何控制好项目在设计、实现时的技术/时间风险,是我一直认为的最为关键的能力,也是我在观察很多架构师时最为看重的。

对于一个大型的项目而言,由于是多团队合作,设计思想的有效传达是非常重要的,设计思想传达的是架构师对整个系统设计的核心思考(不仅仅是结果,更是思考过程),这个思考的表达会非常有助于确保在多个架构师合作的情况下整个系统设计的一致性,以及项目核心目标的完成(之前另外一篇文章的多个团队技术方案冲突的决策原则对系统设计也是非常关键的,相同的是都是把架构师做决定的背后的原因讲清楚,以便多人协作,仅传达结果没有过程的那种是很难真正达成一致和留下深刻印象的),不过即使是小的单一系统的设计,就算架构师是同一个人,设计原则这块也需要陈述清楚,以确保在做各子模块设计时能遵守,同时也是让实现各部分代码的同学能更容易理解设计。

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

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

多个团队的技术方案冲突,怎么决策

作为一个架构师或技术Leader而言,技术方案的决策是常见的要做的事,毕竟很多时候并不会只有一条路能走到目的地,这个时候到底怎么决策很容易成为一个巨大的纠结点,在涉及多团队合作的情况下,甚至有可能会成为block整件事进展的关键因素,这篇文章就来聊聊这个。

自从我开始做一些比较大的跨多团队的基础技术项目后,就会经常面临一些技术方案的决策的事,从一开始的不知所措,痛苦无比,到现在,也算是积累了一些经验和方法,技术方案的决策上,最难的其实就在于可能多个技术方案都是可以走到目的地的,这个时候怎么选择,尤其是多个团队产生冲突的时候,怎么去选择就更加复杂化了。

对于一个由多个技术团队共同完成的大的技术方案而已,会出现两种情况。

一种情况比较简单,就是每个团队各尽其职,分工清晰,这个时候大的技术方案通常不会产生太多的冲突,可能会产生的就是A团队对B团队所负责的部分的技术方案有质疑,这种情况下通常其实不会太难办,大的技术方案是需要一个大架构师的,这个架构师需要定义出整个技术方案的设计原则(之后准备写一篇什么是看起来很虚但其实是核心的设计原则),只要在遵循了设计原则的情况下,我认为B团队所负责的部分的技术方案其他团队就不需要去质疑,谁负责哪块谁决定哪块的技术方案。

另外一种情况就会比较复杂,就是这个大的技术方案中,有所做的部分重叠的不同团队,这个时候就非常容易产生技术冲突,不同团队很有可能会给出不同的方案,这个时候作为整个大技术方案的owner或架构师,怎么去决策就是巨大挑战了,毕竟就算大技术方案的架构师是独裁的,但独裁的还是要有些道理的,不能完全靠行政手段,在这样的情况下,我的观点是这个时候的选择可以基于以下几点考虑去做:
1. 设计原则
多年前在写设计文档中的设计原则时,总是会觉得没什么值得写的,松耦合等等经常会成为常用词,但貌似然并卵,近几年才越来越明白其实设计原则是设计文档中的精髓所在,看起来通常设计原则会很短的几条,但好的架构师会通过这几条控制好整个项目的技术风险,确保各团队的技术方案不偏离关键航道,设计原则里写的点要在每部分的技术方案中贯穿,否则就和没写没什么区别,更形象一点说就是设计原则是在排技术方案细节中关注的重点的优先级,例如有些项目中平滑切换是最高优先级,有些项目中技术创新是最高优先级,设计原则这个部分很值得专门写篇文章,因此这里就不再展开了。
在多个冲突的技术方案选择时,设计原则是其中关键的衡量因素。

2. 团队分工、核心价值和定位
对于产生冲突的团队,需要站在公司角度来做一个判断,产生冲突的部分的技术要做成,核心成功的关键技术点到底掌握在哪个团队手里,还有是对于哪个团队而言是更为核心的价值,只有是那个团队的核心价值才能在人力投入,未来持续发展上有保障,每个团队在一个大的组织里都是有分工的,分工也对应到了其核心价值,在多个冲突的技术方案选择时,一定要考虑这个关键的衡量因素,显然在考虑这个因素的时候要非常中立,站在公司层面而不是小团队层面来考虑,以便确保最后的决策是符合组织对每个团队分工的期望的。
举我自己经历过的两个case来说说。
Case I: 在某个大的技术方案里,有两个团队在某个技术点上都有自己的实现方案,但我最后的决策是选择了当时相对而言反而更不成熟的一方,原因就是我的判断是这个技术点要做成,核心技术其实在这个当时还不是那么成熟的团队手里,
Case II: 在某个大的技术方案里,同样也是几个团队在同一个技术点上都有自己的方案,我最后选择的那个团队基于的判断是:我相信对于公司而言,那个团队才是应该掌控这项技术的组织。

3. 团队能力状况
除了团队分工外,团队的能力状况也是关键,有可能会出现一种状况是从组织层面考虑而言,是应该在B团队做最合适,但B团队的能力在当前可能不具备,反而是另外一个团队更具备,这个时候需要做的决策会是由另外一个团队承担起来,但同时逐步的操作组织层面的变化,确保在整个大的技术方案落地后,以后有持续发展的保障。

从上面这三个衡量因素可以看出,一个大技术方案的owner或架构师,光有技术是远远不够的,在多个冲突的技术方案选择时,更主要的不是评判技术方案的优劣,一旦陷入纯粹技术方案的优劣之争,其实是很难有结果的,越大的项目越是如此,通常来说其实方案可能没有优劣之分(当然,少数冲突的情况下是有明显的优劣之分的),而是哪个更适合的问题,甚至有些时候不同方案在最终多次迭代后走向的是同一方案,只是路径不同,和语言之争类似,所以作为大技术方案的决策者,首先要做的不是去评判技术方案的优劣,而是大家先一起对齐目标、设计原则,然后清晰阐述自己做选择的因素,最后做出决策,当然因为因素毕竟有主观性,要完全得到认可仍然是不容易的,但至少让参与大项目的大伙们清楚的知道你决策的原因,这样大家才能更好的理解整个技术方案,确保最终项目的实现和落地。

大家也来聊聊你碰到过的冲突?作为非决策者的感受?又或是作为决策者你最终的选择和感受?

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

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

分布式领域架构师要掌握的技术

分布式系统无疑是持久的热门话题,但其实如果不是一定有必要,强烈建议不要进入分布式领域,在集中式的情况下很多问题都会简单不少,技术人员千万不要因为外界火热的例如微服务,就把自己的产品的也去做改造,一定要仔细判断是否有必要,不要为了技术而技术,那么在必须分布式的情况下(访问量、存储量或开发人数),一个分布式领域的合格的架构师要掌握哪些技术呢,这篇文章就聊聊这个话题。

简单重复下我对架构师的标准,一个架构师最重要的不是画几个框,连几条线(这是基本要求),而是控制技术风险,要控制技术风险显然不是看几个结构性的ppt就能学会的。

通信
既然是分布式系统,系统间通信的技术就不可避免的要掌握。
首先要掌握一些基础知识,例如网络通信协议(诸如TCP/UDP等等)、网络IO(Blocking-IO,NonBlocking-IO、Asyn-IO)、网卡(多队列等);更偏应用的层面,需要了解例如连接复用、序列化/反序列化、RPC、负载均衡等。
学了这些基本知识后,基本上可以写一个简单的分布式系统里的通信模块,但这其实远远不够,既然进入了分布式领域,对规模其实就已经有了不低的要求,通常也就意味着需要的是能支持大量连接、高并发、低资源消耗的通信程序。

大量的连接通常会有两种方式:
1. 大量client连一个server
在现如今NonBlocking-IO这么成熟的情况下,一个支持大量client的server已经不那么难写了,但在大规模,并且通常长连接的情况下,有一个点要特别注意,就是当server挂掉的时候,不能出现所有client都在一个时间点发起重连,那样基本就是灾难,在没有经验的情况下我看过好几起类似的case,到client规模上去后,server一重启基本就直接被冲进来的大量建连冲垮了(当然,server的backlog队列首先应该稍微设置大一些),通常可以采用的方法是client重连前都做随机时间的sleep,另外就是重连的间隔采取避让算法。

2. 一个client连大量的server
有些场景也会出现需要连大量server的现象,在这种情况下,同样要注意的也是不要并发同时去建所有的连接,而是在能力范围内分批去建。
除了建连接外,另外还要注意的地方是并发发送请求也同样,一定要做好限流,否则很容易会因为一些点慢导致内存爆掉。

这些问题在技术风险上得考虑进去,并在设计和代码实现上体现,否则一旦随着规模上去了,问题一时半会还真不太好解。

高并发这个点需要掌握CAS、常见的lock-free算法、读写锁、线程相关知识(例如线程交互、线程池)等,通信层面的高并发在NonBlocking-IO的情况下,最重要的是要注意在整体设计和代码实现上尽量减少对io线程池的时间占用。

低资源消耗这点的话NonBlocking-IO本身基本已经做到。

伸缩性
分布式系统基本就意味着规模不小了,对于这类系统在设计的时候必须考虑伸缩性问题,架构图上画的任何一个点,如果请求量或者是数据量不断增大,怎么做到可以通过加机器的方式来解决,当然,这个过程也不用考虑无限大的场景,如果经历过从比较小到非常大规模的架构师,显然优势是不小的,同样也会是越来越稀缺的。

伸缩性的问题围绕着以下两种场景在解决:
1. 无状态场景
对于无状态场景,要实现随量增长而加机器支撑会比较简单,这种情况下只用解决节点发现的问题,通常只要基于负载均衡就可以搞定,硬件或软件方式都有;
无状态场景通常会把很多状态放在db,当量到一定阶段后会需要引入服务化,去缓解对db连接数太多的情况。
2. 有状态场景
所谓状态其实就是数据,通常采用Sharding来实现伸缩性,Sharding有多种的实现方式,常见的有这么一些:
2.1 规则Sharding
基于一定规则把状态数据进行Sharding,例如分库分表很多时候采用的就是这样的,这种方式支持了伸缩性,但通常也带来了很复杂的管理、状态数据搬迁,甚至业务功能很难实现的问题,例如全局join,跨表事务等。
2.2 一致性Hash
一致性Hash方案会使得加机器代价更低一些,另外就是压力可以更为均衡,例如分布式cache经常采用,和规则Sharding带来的问题基本一样。
2.3 Auto Sharding
Auto Sharding的好处是基本上不用管数据搬迁,而且随着量上涨加机器就OK,但通常Auto Sharding的情况下对如何使用会有比较高的要求,而这个通常也就会造成一些限制,这种方案例如HBase。
2.4 Copy
Copy这种常见于读远多于写的情况,实现起来又会有最终一致的方案和全局一致的方案,最终一致的多数可通过消息机制等,全局一致的例如zookeeper/etcd之类的,既要全局一致又要做到很高的写支撑能力就很难实现了。

即使发展到今天,Sharding方式下的伸缩性问题仍然是很大的挑战,非常不好做。

上面所写的基本都还只是解决的方向,到细节点基本就很容易判断是一个解决过多大规模场景问题的架构师,:)

稳定性
作为分布式系统,必须要考虑清楚整个系统中任何一个点挂掉应该怎么处理(到了一定机器规模,每天挂掉一些机器很正常),同样主要还是分成了无状态和有状态:
1. 无状态场景
对于无状态场景,通常好办,只用节点发现的机制上具备心跳等检测机制就OK,经验上来说无非就是纯粹靠4层的检测对业务不太够,通常得做成7层的,当然,做成7层的就得处理好规模大了后的问题。
2. 有状态场景
对于有状态场景,就比较麻烦了,对数据一致性要求不高的还OK,主备类型的方案基本也可以用,当然,主备方案要做的很好也非常不容易,有各种各样的方案,对于主备方案又觉得不太爽的情况下,例如HBase这样的,就意味着挂掉一台,另外一台接管的话是需要一定时间的,这个对可用性还是有一定影响的;
全局一致类型的场景中,如果一台挂了,就通常意味着得有选举机制来决定其他机器哪台成为主,常见的例如基于paxos的实现。

可维护性
维护性是很容易被遗漏的部分,但对分布式系统来说其实是很重要的部分,例如整个系统环境应该怎么搭建,部署,配套的维护工具、监控点、报警点、问题定位、问题处理策略等等。

从上面要掌握的这些技术,就可以知道为什么要找到一个合格的分布式领域的架构师那么的难,何况上面这些提到的还只是通用的分布式领域的技术点,但通常其实需要的都是特定分布式领域的架构师,例如分布式文件系统、分布式cache等,特定领域的架构师需要在具备上面的这些技术点的基础上还具备特定领域的知识技能,这就更不容易了。

随着互联网的发展,分布式领域的很多技术都在成熟化,想想在8年或9年前,一个大规模的网站的伸缩性是怎么设计的还是很热门的探讨话题,但是到了今天基本的结构大家其实都清楚,并且还有很多不错的系统开源出来,使得很多需要经验的东西也被沉淀下去了,在有了各种不错的开源产品的支撑下以后要做一个分布式系统的难度一定会越来越大幅降低,云更是会加速这个过程。

ps: 在写这篇文章的过程中,发现要判断一个技术人的功底有多厚,其实还真不难,就是请TA写或者讲自己觉得懂的所有技术,看看能写多厚或讲多久…要写厚或讲很久其实都不容易,尽管我也不否认要很简洁的写明白或讲清楚也不容易,但一定是先厚然后薄。

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

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

Java问题排查工具箱

问题排查除了最重要的解决思路和逻辑推导能力外,工具也是不可缺少的一部分,一个好用的工具可以事半功倍,甚至在某些情况下会因为没有相应的工具而压根就没法继续进行下去,这篇文章就来讲讲在排查Java问题时通常要用到的一些工具(ps:这种文章值得收藏,看一遍其实很容易忘)。

日志相关工具
查问题的时候会非常依赖日志,因此看日志的相关工具非常重要,通常的话掌握好tail,find,fgrep,awk这几个常用工具的方法就可以,说到这个就必须说关键的异常和信息日志输出是多么的重要(看过太多异常的随意处理,例如很典型的是应用自己的ServletContextListener实现,很多的Listener实现都会变成往外抛RuntimeException,然后直接导致tomcat退出,而tomcat这个时候也不会输出这个异常信息,这种时候要查原因真的是让人很郁闷,尽管也有办法)。
日志的标准化也非常重要,日志的标准化一方面方便像我这种要查各种系统问题的人,不标准的话连日志在哪都找不到;另一方面对于分布式系统而言,如果标准化的话是很容易做日志tracing的,对问题定位会有很大帮助。

CPU相关工具
碰到一些CPU相关的问题时,通常需要用到的工具:
top (-H)
top可以实时的观察cpu的指标状况,尤其是每个core的指标状况,可以更有效的来帮助解决问题,-H则有助于看是什么线程造成的CPU消耗,这对解决一些简单的耗CPU的问题会有很大帮助。
sar
sar有助于查看历史指标数据,除了CPU外,其他内存,磁盘,网络等等各种指标都可以查看,毕竟大部分时候问题都发生在过去,所以翻历史记录非常重要。
jstack
jstack可以用来查看Java进程里的线程都在干什么,这通常对于应用没反应,非常慢等等场景都有不小的帮助,jstack默认只能看到Java栈,而jstack -m则可以看到线程的Java栈和native栈,但如果Java方法被编译过,则看不到(然而大部分经常访问的Java方法其实都被编译过)。
pstack
pstack可以用来看Java进程的native栈。
perf
一些简单的CPU消耗的问题靠着top -H + jstack通常能解决,复杂的话就需要借助perf这种超级利器了。
cat /proc/interrupts
之所以提这个是因为对于分布式应用而言,频繁的网络访问造成的网络中断处理消耗也是一个关键,而这个时候网卡的多队列以及均衡就非常重要了,所以如果观察到cpu的si指标不低,那么看看interrupts就有必要了。

内存相关工具
碰到一些内存相关的问题时,通常需要用到的工具:
jstat
jstat -gcutil或-gc等等有助于实时看gc的状况,不过我还是比较习惯看gc log。
jmap
在需要dump内存看看内存里都是什么的时候,jmap -dump可以帮助你;在需要强制执行fgc的时候(在CMS GC这种一定会产生碎片化的GC中,总是会找到这样的理由的),jmap -histo:live可以帮助你(显然,不要随便执行)。
gcore
相比jmap -dump,其实我更喜欢gcore,因为感觉就是更快,不过由于某些jdk版本貌似和gcore配合的不是那么好,所以那种时候还是要用jmap -dump的。
mat
有了内存dump后,没有分析工具的话然并卵,mat是个非常赞的工具,好用的没什么可说的。
btrace
少数的问题可以mat后直接看出,而多数会需要再用btrace去动态跟踪,btrace绝对是Java中的超级神器,举个简单例子,如果要你去查下一个运行的Java应用,哪里在创建一个数组大小>1000的ArrayList,你要怎么办呢,在有btrace的情况下,那就是秒秒钟搞定的事,:)
gperf
Java堆内的内存消耗用上面的一些工具基本能搞定,但堆外就悲催了,目前看起来还是只有gperf还算是比较好用的一个,或者从经验上来说Direct ByteBuffer、Deflater/Inflater这些是常见问题。
除了上面的工具外,同样内存信息的记录也非常重要,就如日志一样,所以像GC日志是一定要打开的,确保在出问题后可以翻查GC日志来对照是否GC有问题,所以像-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc: 这样的参数必须是启动参数的标配。

ClassLoader相关工具
作为Java程序员,不碰到ClassLoader问题那基本是不可能的,在排查此类问题时,最好办的还是-XX:+TraceClassLoading,或者如果知道是什么类的话,我的建议就是把所有会装载的lib目录里的jar用jar -tvf *.jar这样的方式来直接查看冲突的class,再不行的话就要呼唤btrace神器去跟踪Classloader.defineClass之类的了。

其他工具
jinfo
Java有N多的启动参数,N多的默认值,而任何文档都不一定准确,只有用jinfo -flags看到的才靠谱,甚至你还可以看看jinfo -flag,你会发现更好玩的。
dmesg
你的java进程突然不见了? 也许可以试试dmesg先看看。
systemtap
有些问题排查到java层面是不够的,当需要trace更底层的os层面的函数调用的时候,systemtap神器就可以派上用场了。
gdb
更高级的玩家们,拿着core dump可以用gdb来排查更诡异的一些问题。

io类型的问题我排查的很少,所以尽管知道一些工具,还是不在这里写了。

暂时就写这些,尽管工具的使用多数都可以临时学,但首先知道有哪些工具是最重要的,然后呢还是建议大家可以玩一玩这些工具,这样以后真的要用的时候也不至于一点印象都没有。

ps: 发现我的微信公众号还是写Java的文章阅读量高一些呀,本来我一直天真的认为像Borg这种文章应该阅读量也不低才对….

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

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

YGC越来越慢,为什么

近来被这个case折腾的很,现象是有个应用在压测时qps表现不太稳定,好和不好的时候差别还挺大的,对比好和不好的时候,看到的现象就是好的时候ygc时间会比较短,而不好的时候ygc时间比较长,然后看正常运行的时候,也看到一个现象就是ygc时间会越来越长,直到cms gc触发后才能降回到一个比较小的值,于是开始查为什么ygc会越来越慢。

YGC越来越慢,还真没什么太多信息可入手的,于是求助JVM团队的寒泉子(微信公众号:lovestblog,强烈推荐)帮忙输出一些ygc分阶段的耗时信息,以便来推测到底是哪部分造成的ygc慢,例如我有点怀疑的是oldgen碎片的问题造成的,但通常碎片问题呢cms gc后也很难有太大程度的缓解,所以和这个现象不太一样。

拿到有更多trace信息的JDK版本后,更新上线,根据ygc不断变慢的trace信息对比发现问题出在了StringTable部分,这是ygc速度正常的情况下StringTable部分的速度:
[StringTable::possibly_parallel_oops_do_21030, 0.0010919 secs]
而ygc越来越慢后,StringTable部分:
[StringTable::possibly_parallel_oops_do_11152162, 0.1101763 secs]
从输出信息来看,可以看到在ygc速度还正常的时候,StringTable去扫的一个桶里的item数才21030个,而到了ygc速度很慢的时候,item数增长到了11152162个,这样的数量增长StringTable处理的速度变慢也是正常的。

那就要查查为什么StringTable增长那么快了,StringTable增长基本都是String.intern搞的(关于StringTable和String.intern推荐看看这篇文章:http://java-performance.info/string-intern-in-java-6-7-8/),不过这个方法在native,btrace跟不了,所以寒泉子继续改了个JDK版本,采样的输出String.intern的栈信息,这个版本放上去跑后,很快看到这样的堆栈信息:
at java.lang.String.intern(Native Method)
at com.fasterxml.jackson.core.util.InternCache.intern(InternCache.java:45)
跟着这个栈信息翻对应的代码(话说不知道大家都用什么去查代码呢,我一般都用www.grepcode.com,觉得挺好用的),很容易明白问题所在,例如InternCache.intern部分的代码如下:
if (result == null) {
result = input.intern();
put(result, result);
}

jackson之所以用intern去处理,本来是想节省点cache的内存,没想到业务场景是每次都不一样的字符串,这样直接就导致了String.intern后StringTable的大小暴涨,所以在这种场景中,这样做反而得不偿失,还好jackson代码支持通过接口来把调用intern的部分关掉。

话说用String.intern不当造成的StringTable大,从而导致ygc速度慢这问题我好像碰过好几次了,而且到现在我都觉得StringTable这东西的设计不咋样,建议大家能不用String.intern还是别用好了,除非真的是重复量非常大的相同字符串处理。

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

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

Borg:G家最重要的基础设施

即使是在Borg论文发表前,从各种渠道了解也都能知道G家有一个挺神秘,非常重要的系统叫Borg,在Borg论文发表后,更是让人可以确信,再加上近两年和G家的朋友们的接触,更加可以知道对于G家的研发人员而言,说Borg是G家最重要的基础设施应该不为过,如果有看过《Google SRE》书的同学,可以看出有一点是在G家对Borg的认识是深入各研发同学的,Google SRE书里讲到G家的编译打包这种临时性任务,其实都是提交一个临时性的任务到borg来完成,而我想在传统或者说目前多数的做法里都会采用固定的机器资源来做这些事。

对Borg带来的收益,我想只用摘取Borg论文里这一小段就足以说明:
“Since many other organizations run user-facing and batch jobs in separate clusters, we examined what would happen if we did the same. Figure 5 shows that segregating prod and non-prod work would need 20–30% more machines in the median cell to run our workload.”
G家的服务器数量是百万数量级,20-30%这数量级的节省简直了…

既然Borg这么的好,为什么现在在其他互联网公司还没看到采用一样的方式去做呢(要知道Borg差不多是2003年就开始做了),从我的接触来看,我了解到的原因主要是这两个:
1.技术难度,有一些声音是觉得Borg这条路线太难走了,里面要解决的技术问题太多;
2.离线任务的规模量还不够大,这个时候Borg采用的user-facing and batch jobs混合在一台机器上运行的方式的优势就不存在了。
从上面这两个原因可以看到,要去打造一套Borg这样的系统,基本上只有机器到达一定规模,以及大数据也发展到比较大规模的公司才能有足够的收益比,当然,以现在大数据、AI的火热程度,排行前十甚至前几十的互联网公司其实都已具备这样的前提条件。

那么要打造Borg这样的系统,要突破哪些技术难度呢?

1.容器化
Borg把所有的task都放在cgroup里运行,这种方式相比Docker基于的LXC的差别在于没有namespace的隔离,简单来说就是当你登录到机器上,看到的是整个物理机的状况,这对于运维来说其实是相当痛苦的,从Borg论文也可以看到Borg为了方便对task进行运维,做了很多辅助工具和系统,所以在容器化这个方面我会更加倾向于LXC,具备namespace的隔离,对运维来说就会友好非常多。
为什么一定要容器化呢,原因在于如果对资源的需求都是物理机,那资源的调度的灵活性将会大幅下降,所以容器化是非常重要的一个基础前提,容器化的难题一方面是对LXC的掌握,另一方面则是任何类型的软件都要放在LXC中跑,会碰到各种问题,无论是性能还是namespace隔离不完整带来的支持问题。

2.复杂的调度器
当一家大规模的公司的所有业务都要通过同一个调度层来分配资源时,这个调度层所要面临的业务复杂性是非常可怕的,再加上batch jobs的调度,各种调度需求混合在一起,以及要管理巨大的机器规模,如何在保证业务需求满足的同时的规模、效率、稳定,绝对不是一件容易的事,现在业界有的其他的例如swarm、k8s、mesos、yarn等等,离borg这种级别的调度器是有巨大差距的。

3.资源隔离
Borg需要把不同优先级的任务跑在同一台机器上,non-prod优先级的任务会share prod优先级任务的资源,这个时候如何保障好non-prod任务不影响到prod任务的性能等就非常非常重要了,而这个目前业界并没有什么很成熟的方案,无论是cpu、内存、IO(磁盘/网络),离要成熟的支撑这样的资源隔离都还有非常大的差距。

4.历史包袱
Borg在2003年开始做的话,我想那个时候G家的历史包袱应该是不大的,但现在其他的大的互联网公司要做的话,显然都有不小的历史包袱,例如通常都会需要面临多种不同的基础设施、运维模式等,怎么在背着巨大的历史包袱走到期望的那步,其实是一件非常不容易的事。

可以说,这四点技术难度都是世界级的,因为碰到这样的技术难度的机会其实本来就很少,显然只有巨大的收益才能产生这样的驱动力,所以说这种类型的系统只有大规模的公司才会投入力量去做,而现在阿里就在投入力量打造这样的系统,如果你正好对这些领域有兴趣,并且在这些领域有一定的积累,我想这样的好的难得的机会(就像一直说,只有少数几家公司有做这样的系统的动力)不容错过,应该毫不犹豫的来加入我们,直接发送消息来联系我吧,期待你的加盟!

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

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