——分布式任务协作, 数量老是不正确的问题! 每次都不对, 谁来救救我哦!!
前情回顾
前面几回都是在烙饼, 一开始烙饼给关羽累坏了, 原因是关羽不会循环语句, 把循环用顺序结构写, 造成400张饼的锦囊要写很久, 累坏了关羽。 关羽学会了循环语句, 但是立刻把张飞累死了, 原来关羽的循环语句没有退出语句,因此张飞永远干不完(这个类型的循环是死循环), 只有关羽改进了循环,在循环中添加了判断语句若是满足了数量的要求, 就退出循环,这样张飞就不那么累了。可是问题是张飞烙饼的速度还是慢, 因此恰巧天神哪咤经过传送张飞三头六臂的办法(其实就是开多线程),这样张飞就可以在单位时间内生产出3倍数量的饼来, 可以加快时间。
出名的张飞
俗话说, 人怕出名猪怕壮, 张飞自从有三头六臂的烙饼神功后, 烙饼速度和手艺大进, 全军都已经尽人皆知了。一日,训练归来, 大家训练的很累, 大家也都知道三爷(张飞), 有烙饼的神艺, 因此纷纷说要品尝一下三爷的烙饼。张飞心想, 俺老张有神艺在身, 正好显示一下。
三爷数了数, 这些人吃饼 , 正正好5000张饼。心想看来我要大显身手了!
狭小的厨房
张飞心里算计了一下, 上次5头10臂2个小时烙饼200张, 那么1小时1个人(1个头)20张饼。
那么5000张饼, 按照这个速度烙下去就需要250个小时, … 阅读全文
spring 2.5.6用的已经很少了, 相关例子已经很少也不好找, 完整的能好用的就更少了, 下面是两个相对完整的, 并且有源代码的
另外, 下面项目最好在 jdk1.6的环境运行, 高版本的jdk可能有些问题, 例如jdk1.8 会报异常
Spring MVC hello world annotation example
spring mvc hello world 基于注解的例子
spring 版本2.5.6 这个2.x系列最后的版本的, 现在一般都是使用 3.x或者4.x了, 更高的是 5.x了。
This tutorial is based on Spring 2.5.6, quite outdated. Try
…
阅读全文
分布式跟踪系统(二)Zipkin的Span模型:本文将详细介绍Zipkin的Span模型,以及其他“另类”Span模型的设计。
这里多一句嘴,其实专业点的叫法应该是分布式追踪系统——Distributed TracingSystem,跟踪比较适合用于人的场景,比如某人被跟踪了,而追踪更适合用于计算机领域。然并卵?本文将继续使用“跟踪”。
Zipkin的Span模型几乎完全仿造了Dapper中Span模型的设计,我们知道,Span用来描述一次RPC调用,所以一个RPC调用只应该关联一个spanId(不算父spanId),Zipkin中的Span主要包含三个数据部分:
基础数据:用于跟踪树中节点的关联和界面展示,包括traceId、spanId、parentId、name、timestamp和duration,其中parentId为null的Span将成为跟踪树的根节点来展示,当然它也是调用链的起点,为了节省一次spanId的创建开销,让顶级Span变得更明显,顶级Span中spanId将会和traceId相同。timestamp用于记录调用的起始时间,而duration表示此次调用的总耗时,所以timestamp+duration将表示成调用的结束时间,而duration在跟踪树中将表示成该Span的时间条的长度。
需要注意的是,这里的name用于在跟踪树节点的时间条上展示。Annotation数据:用来记录关键事件,只有四种,cs(Client Send)、sr(Server Receive)、ss(Server Send)、cr(Client Receive),所以在Span模型中,Annotation是一个列表,长度最多为4。每种关键事件包含value、timestamp和endpoint,value就是cs、sr、ss和cr中的一种,timestamp表示发生的时间,endpoint用于记录发生的机器(ip)和服务名称(serviceName)。可以很自然的想到,cs和cr、sr和ss的机器名称是相同的,为了简单起见,cs和cr的服务名称可以一样,sr和ss的服务名称可以一样。
Annotation数据主要用于用户点击一个Span节点时展示具体的Span信息。BinaryAnnotation数据:我们并不满足在跟踪树上只展示调用链的时间信息,如果需要绑定一些业务数据(日志)的话,可以将数据写入BinaryAnnotation中,它的结构和Annotation数据一模一样,在Span中也是一个列表,这里就不再阐述,但BinaryAnnotation中不宜放太多数据,不然将导致性能和体验的下降。
现在我们已经了解了一个Span的内部结构,但这是Span的最终形态,也就是说这是Zipkin在收集完数据并展现给用户锁看到的最终形态。Span的产生是“不完整”的,Zipkin服务端需要将搜集的有同一个traceId和spanId的Span组装成最终完整的Span,也就是上面说到的Span。可能这样说不太直观,我们沿用下图来举例说明:

zipkin数据收集(图1)
上图在我的第一篇Zipkin博文中已经用到过,这里不再详细阐述,我们直接看该图对应的内部Span细节图:

span数据流转(图2)
注意,上图并没有显示Span的所有细节(比如name和binaryAnnotation等),但这并不影响我们分析问题。上图的①和⑥是一次完整的RPC调用,它发生在服务器0和服务器1之间,显而易见的是,用于描述该RPC调用的Span的spanId是1000,所以,这是同一个Span的,只是它的数据来源于两台不同的服务器(应用):服务器0和服务器1。往低层说,该Span由两条跟踪日志表示,一条在服务器0上被采集,另一条在服务器1上被采集,他们的Span的traceId、spanId和parentSpanId都是一样的!而且该Span将成为跟踪树中的顶节点,因为他们的parentSpanId为null。对于步骤①来说,服务器1上的sr减去服务器0上的cs的时间就是约等于网络耗时(这里忽略不同服务器时钟的差异),同理,对于其他步骤,sr-cs和cr-ss得到的都是网络耗时。我们接着看请求步骤②和④,从跟踪树的层次来说他们属于①下的子调用,所以它们的parentSpanId就是①的1000。步骤②和④都会分别产生一个spanId(上面的1001和1002),所以如上图,看似一次简单的RPC过程,其实共产生了6条Span日志,它们将在Zipkin服务端组装成3个Span。
那么,问题来了,此次调用在服务器1上出现了3个spanId:1000、1001和1002,如果我想记录服务器1上和此次调用的业务数据(通过BinaryAnnotation来记录),是将这些数据绑定到哪个Span上呢?如果让我们选择,我们肯定选择1000,因为服务器1上此次请求中调用下游的服务是不确定的(虽然图中只画了服务器2和服务器3),有可能它会调用下游的十几个服务,产生十几个spanId,相对而将业务数据言绑定到这些Span的父Span(1000)上似乎更合理。并且在产生业务日志时,有可能还没开始进行下游调用,所以也只能绑定在1000上。
我们先来看看图2中的Span在Zipkin的跟踪树中大概会显示成什么样子,如下图:

Zipkin跟踪树(图3)
当然,部分数据会和图2中的不一样(比如timestamp和duration),但并不影响我们分析问题。可以看出,在Zipkin中最小的时间单位是微秒(千分之一毫秒),所以图3中展现的此次RPC总耗时为96.2ms,有人刚开始看肯定会疑问,为啥经历过四个服务器的RPC调用在图中的跟踪树中只有三个节点?因为在跟踪树中, 一个Span(准确的说是一个spanId)只会展现成一个树节点,比如树节点Service1表示了Gateway(服务器0)调用Service1(服务器1)的过程,树节点Service2表示Service1(服务器1)调用Service2(服务器2)的过程。有人肯定会问,对于树节点Service1,我们记录了cs、sr、ss和cr四个时间,但时间条的显示只用到了cs和cr(耗时duration=cr-cs),那么sr和ss去哪了(别忘了我们可以通过sr-cs和cr-ss计算网络耗时)?我们可以单击Serice1节点,于是打开了Span的详细信息(Span的annotation和binaryAnnotation数据),如下图:

Span详细信息(图4)
Relative Time 是相对时间,表示此事件(cs、sr、ss、cr)已经发生了多久(相对起始时间点),因为Service1是顶级节点,所以第一行的RelativeTime是空的,于是乎,该请求的网络耗时(Gateway请求Service1)为10ms,应答的网络耗时(Service1应答Gateway)为96.3-94.3=2ms,所以,从Zipkin目前的页面设计来看,网络耗时只能通过点树节点的详细信息页面来看,而且还需要做简单的计算,并不直观。淘宝的鹰眼系统通过在时间条上分为两种颜色来显示,使用了cs、sr、ss和cr四个时间戳,更加直观。
可能大多数人觉得对于跨四个系统的RPC调用却只显示三个节点,有些别扭。对于图1的调用,我们更希望是Gateway的节点下挂着一个Service1节点,表示Gateway调用了Service1,而Service1节点下挂着Service2和Service3两个节点,表示Service1调用了Service2和Service3,这样更容易理解。于是我们想到了在RPC链路中经过某个节点(服务器应用),那么这个节点就产生几个spanId,这样的话,在图中RPC经过Gateway、Service1、Service2和Service3各一次,所以一共将产生4个spanId(Zipkin在图2中只产生3个spanId),这样就变成了spanId和节点个数一致(前提是RPC链路中只经过每个节点各一次,也就是节点之间没有相互依赖)。这样设计Span数据的流转如下图:

修改过的Span数据流转(图5)
图5中可以很明显的看出,还是6条Span的日志,每个服务器节点上会产生一个spanId(1000、1001、1002和1003),而不是像原有图2一样只有3个spanId。这样还有一个好处,就是RPC调用时只需要传递traceId和spanId,而不是像Zipkin的设计那样,需要传递traceId、spanId还有parentSpanId。但立马我们就发现了问题,在图5的服务器1的节点上,1001的spanId记录了两套cs和cr,则也导致了无法区分哪个对应的是调用服务器2,哪个对应的是调用服务器3,所以,这种设计方案直接被否决了。
于是我们换一种思路,不采用spanId和parentSpanId,换成spanId和childSpanId,childSpanId由父亲节点生成并传递给子节点,如下图:

新的Span数据流转(图6)
从图6可以看到明显的变化,不再有parentSpanId,而使用了childSpanId,这样RPC之间传递的就是traceId和childSpanId,这也直接解决了图5中所遇到的问题。虽然图5和图6的设计违背了一次RPC调用由一个spanId的数据来进行维护的设计理念,但确实在跟踪树的界面展示上更容易让人接受和理解(树节点和服务器节点对应),而且还减少了RCP间的数据传送,何乐而不为?
来源: https://www.2cto.com/kf/201701/582724.html… 阅读全文
一般画上见到的兰花是蕙而不是兰,兰与蕙的区别主要在于一茎一花与一茎多花。

兰: 一根花茎只开一朵花

蕙:一根花茎开多朵花
兰有梅瓣、荷瓣和尖瓣之分。梅瓣,是说它的花片形圆近似于梅,点法上起笔也同于点梅瓣,行笔至末端向里出锋收笔;荷瓣,其形短肥而头尖近似荷花瓣,点法是用露锋笔尖朝上,先朝左点再向右折笔,后拖然后出锋;尖瓣,其形瘦长而尖,点法是露锋点入然后下按,再轻轻提笔至末端收笔出锋。
第一部分 画叶

画兰以叶为先,起首一笔,有钉头、鼠尾、螳螂肚之法。二笔交凤眼,三笔破凤眼,四笔、五笔宜间折叶。

成丛多叶,宜俯仰生动、交加而不重叠。

画兰叶切忌叶叶相匀、随意涂抹,每一笔都要蕴含着轻重缓急、起伏转折、浓淡虚实。要有“笔断意连”、“意到笔不到”之笔。

提笔与按笔的方向不同,叶子走势也不一样。

画丛兰要注意不要三笔交于一点。

画叶有顺笔、逆笔,由左至右为顺,由右至左为逆。初学宜先顺后逆,最后顺逆兼备。

画兰叶根部宜聚不宜散。

倒垂式应体会用笔变化。
第二部分 画花
写意兰花多使用水墨,墨色不宜过深、过重。一般兰叶深一些,兰花浅一些。要掌握花的正侧、向背、偃仰、含放、呼应以及在风、晴、雨、露条件下的变化。

画丛兰要注意不要三笔交于一点。花苞一般由一笔或两笔画成,半开的花由两到三笔组成,全放的花朵用五笔画出,用笔应由外向内一气呵成。

画叶有顺笔、逆笔,由左至右为顺,由右至左为逆。初学宜先顺后逆,最后顺逆兼备。点兰花苞要注意用笔的顿挫和连贯性。

画兰叶根部宜聚不宜散。
写意兰花花心要以重墨点出,一般为三点,下笔要干脆利落,犹如写草书的“心”、“山”、“上”、“下”字。古人云:“兰之点心,犹美人之有目。”

倒垂式应体会用笔变化。

是用草书的画法点兰花。

以楷书的笔法点兰;上两幅用笔虽不同,但道理是相通的。

花头的姿态变化。
兰花双钩法


双钩兰花法大致分为上两幅工笔、意笔两种,意笔双钩较之工笔轻重起伏变化大一些。然此法又较之工笔画法难度要大,需要具备一定的书法功底和写意画的能力。
本篇幅就兰花的叶和花的画法作了阐述,下篇针对花、叶组合来讲解。谢谢。
以下是兰花作品欣赏:


… 阅读全文
基础知识储备
分布式跟踪的目标
一个分布式系统由若干分布式服务构成,每一个请求会经过多个业务系统并留下足迹,但是这些分散的数据对于问题排查,或是流程优化都很有限,要能做到追踪每个请求的完整链路调用,收集链路调用上每个服务的性能数据,计算性能数据和比对性能指标(SLA),甚至能够再反馈到服务治理中,那么这就是分布式跟踪的目标。
分布式跟踪的目的
zipkin分布式跟踪系统的目的:
- zipkin为分布式链路调用监控系统,聚合各业务系统调用延迟数据,达到链路调用监控跟踪;
- zipkin通过采集跟踪数据可以帮助开发者深入了解在分布式系统中某一个特定的请求时如何执行的;
- 假如我们现在有一个用户请求超时,我们就可以将这个超时的请求调用链展示在UI当中;我们可以很快度的定位到导致响应很慢的服务究竟是什么。如果对这个服务细节也很很清晰,那么我们还可以定位是服务中的哪个问题导致超时;
- zipkin系统让开发者可通过一个Web前端轻松的收集和分析数据,例如用户每次请求服务的处理时间等,可方便的监测系统中存在的瓶颈。
ZipKin介绍
- Zipkin是一个致力于收集分布式服务的时间数据的分布式跟踪系统。
brave 介绍
Brave 是用来装备 Java 程序的类库,提供了面向标准Servlet、Spring MVC、Http Client、JAX RS、Jersey、Resteasy 和 MySQL 等接口的装备能力,可以通过编写简单的配置和代码,让基于这些框架构建的应用可以向 Zipkin 报告数据。同时 Brave 也提供了非常简单且标准化的接口,在以上封装无法满足要求的时候可以方便扩展与定制。
本文主要介绍springmvc+dubbo下的brave使用。
dubbo项目下快速搭建zipkin、brave追踪系统
1、zipkin安装使用
此处主要介绍linux下的安装使用,zipkin官网地址 http://zipkin.io/pages/quickstart.html
wget
…
阅读全文
1. 背景介绍许多公司的平台每天会产生大量的日志(一般为流式数据,如,搜索引擎的pv,查询等),处理这些日志需要特定的日志系统,一般而言,这些系统需要具有以下特征:(1) 构建应用系统和分析系统的桥梁,并将它们之间的关联解耦;(2) 支持近实时的在线分析系统和类似于Hadoop之类的离线分析系统;(3) 具有高可扩展性。即:当数据量增加时,可以通过增加节点进行水平扩展。
本文从设计架构,负载均衡,可扩展性和容错性等方面对比了当今开源的日志系统,包括facebook的scribe,apache的chukwa,linkedin的kafka和cloudera的flume等。
2. FaceBook的Scribe
Scribe是facebook开源的日志收集系统,在facebook内部已经得到大量的应用。它能够从各种日志源上收集日志,存储到一个中央存储系统 (可以是NFS,分布式文件系统等)上,以便于进行集中统计分析处理。它为日志的“分布式收集,统一处理”提供了一个可扩展的,高容错的方案。
它最重要的特点是容错性好。当后端的存储系统crash时,scribe会将数据写到本地磁盘上,当存储系统恢复正常后,scribe将日志重新加载到存储系统中。

架构:
scribe的架构比较简单,主要包括三部分,分别为scribe agent, scribe和存储系统。
(1) scribe agent
scribe agent实际上是一个thrift client。 向scribe发送数据的唯一方法是使用thrift client, scribe内部定义了一个thrift接口,用户使用该接口将数据发送给server。
(2) scribe
scribe接收到thrift client发送过来的数据,根据配置文件,将不同topic的数据发送给不同的对象。scribe提供了各种各样的store,如 file, HDFS等,scribe可将数据加载到这些store中。
(3) 存储系统
存储系统实际上就是scribe中的store,当前scribe支持非常多的store,包括file(文件),buffer(双层存储,一个主储存, 一个副存储),network(另一个scribe服务器),bucket(包含多个 store,通过hash的将数据存到不同store中),null(忽略数据),thriftfile(写到一个Thrift TFileTransport文件中)和multi(把数据同时存放到不同store中)。
3. Apache的Chukwa
chukwa是一个非常新的开源项目,由于其属于hadoop系列产品,因而使用了很多hadoop的组件(用HDFS存储,用mapreduce处理数据),它提供了很多模块以支持hadoop集群日志分析。… 阅读全文
前面几个, 我们都先回顾了很多内容才开始讲东西, 我们今天变化一下形式, 先讲个故事在说明事情。
着急的关羽
话说关羽写 完 烙饼的锦囊, 然后就同众兄弟一边喝酒, 一边等 张飞 烙好的 大饼, 等呀等, 这四百张饼, 都两个小时也没烙好。
关羽等等 肚子咕咕叫了, 心想 我这个三弟 是个 急脾气, 这次 干事情怎么这么慢, 关羽实在 等地不耐烦了, 迈步不厨房而来。
关羽同学一边走, 一边 大声说着, 三弟,三弟, 这饼烙的 如何这么时间长呀!
张飞听到了, 哭着脸说, 我就一个人, 两双手,已经忙的 不可开交了, 才烙了100张饼

… 阅读全文
前言
现在在Android上实现视频播放已不是什么难事,这方面的轮子已经很多,不管是Google的 ExoPlayer、B站的 ijkplayer,还是一些其他的,基本上都能满足我们的需求。
但现在视频播放我们追求的是更好的用户体验:播放流畅,没有卡顿,不跳帧。因此,如何优化体验是一件十分重要的事情。
另外,做过视频播放的小伙伴都知道:在CDN的情况下,实现视频边缓冲边播是不可能的。而只有在P2P下才能实现视频边下边播。如果,产品经理让你实现边下边播的功能,你心里肯定一万只草泥马奔腾而过~,然后,还得耐心给她介绍:这功能实现不了,因为xxx实现不了,云云……
上面的问题真的就解决不了吗?在CDN下就真的不能边下边播吗?
其实,不然,AndroidVideoCache就能满足你的需求,解决上述问题
AndroidVideoCache是国外大神Alexey Danilov写的一个android开源库。一个视频/音频缓存库,利用本地代理实现了边下边播,支VideoView/MediaPlayer, ExoPlayer ,IJK等播放器的边下载边播放。集成简单,与业务无关。
代码的架构写的也很不错,很值得研究阅读和学习借鉴。网络用httpurlconnect,实现了文件缓存处理,文件最大限度策略,回调监听处理,断点续传,代理服务等功能。
目前 1.9k star,491个fork,最新版本2.7.0
AndroidVideoCache是一个音视频边下边播缓存库,按照github列出支持的特性如下:
1、支持边下边播
2、流媒体磁盘缓存
音视频播放的时候会将多媒体数据存储于磁盘上面
3、资源离线缓存
如果播放的数据已经缓存,支持离线播放
4、局部加载
支持部分加载
5、缓存限制
可以设置缓存配置,如缓存的大小,允许最大的缓存文件数量
6、支持多客户端
对于同一个url地址请求源,允许有多个请求客户端链接
7、封装简单,容易集成到自己的项目,与业务无关
8.、采用本地代理模式实现边下边播
注意,AndroidVideoCache只对媒体文件使用直接url,它不支持任何流技术,如DASH,平滑流,HLS。
项目的原理其实就是将url链接转化为本地链接 h t
…
阅读全文
知识回顾
1. 分支结构
前面我们已经了解了 分支的情况, 分支做啥? 就是某些不确定的事情,若是甲事情发生,就做同甲相关的事情, 若是乙发生就做同乙相关的事情。
造成不确定的原因是, 在写锦囊的时候 没办法确定“将来” 执行锦囊(指令)的人(计算机)遇到到底啥情况, 因此 做锦囊时(写程序)时, 要考虑到不同情况发生
如下图:

图中, 我们明确看到了, 两个分支, 分支1, 分支2, 同时在执行分支前, 有个 判断的 东西
上面过程(流程) 用通俗语言可以描述为
如果 xxx 情况发生 就做下面的事情
锦囊x1
锦囊x2
等等
否则(就是没有发生上面的情况)就执行下面的事情
锦囊y1
锦囊y2
锦囊y3… 阅读全文