本来这个公众号的交流消息中间件相关的技术的。十月去上海参加了QCon,第一次参加这样的技术会议,感受挺多的,所以整理一下自己的一些想法接公众号和大家交流一下。

三天的内容还挺多的,之前已经有上篇和中篇,这一片是最后一篇,内容包含以下三个议题:

  • 《携程第四代架构之软负载SLB实践之路》
  • 《恒生中间件如何助理证券经纪业务发展》
  • 《Heron的Exactly-Once实现》

《携程第四代架构之软负载SLB实践之路》

这场分享主要介绍了携程软负载的设计和实现。

首先我们先弄清楚什么是软负载,然后再来看这篇分享的内容。

这里的软负载一词确切的含义应该是通过软件进行负载均衡。负载均衡可以通过硬件设备实现,也可以通过软件实现。而由于硬件成本高,所以往往当系统的量达到一定阶段(这个时候堆硬件的成本已经不可以接受了)就会转向采用软件进行负载均衡的方式。LVS是业界最著名的软负载。

回到携程软负载的分享中,这场分享主要介绍了携程遇到的一些问题及解决方案:

  1. 如何设计一个业务开发人员可以使用的软负载系统?
  2. 如何提供高频调用且稳定返回的API?
  3. 如何解决多角色运维冲突的问题?
  4. 如何解决心跳检测的瓶颈问题?
  5. 如何利用好这个绝佳的监控场所?

第一个问题:如何设计一个业务开发人员可以使用的软负载系统?

携程对应用进行了抽象,将所有提供统一服务的应用抽象为一个group,group有如下属性:

  • id
  • domain和path
  • 健康检测链接health-check
  • 机器列表servers

这层抽象主要是为了屏蔽掉Nignx的只是壁垒,因此业务人员就不在需要了解Nignx的配置内容。

第二个问题:如何提供高频调用且稳定返回的API?

这个问题的来源是抽象出来的Group文件的变更合并到配置文件,这些变更导致写修改配置文件的时间变长的问题。

携程采用了增加队列,然后合并操作的方式,PPT中称为伪并发的方式解决Group变更导致的写入问题。

第三个问题:如何解决多角色运维冲突的问题?

这个其实非常简单的小技巧了,用多个位来标识不同的状态,最终根据值的结果来提供服务。

因为SLB节点的状态无非两种:提供服务 or 不提供服务,这里只要有一位为1就标识不可提供服务。

第四个问题:如何解决心跳检测的瓶颈问题?

SLB服务器是有限的,远小于应用数量的,如上图,随着应用不断增加,心跳数据就会成为SLB服务器的一个负担。

携程的处理方式也非常简单:将健康检测模块单独抽离出去,且健康检测模块也可以水平扩容,这样解决掉SLB服务端的压力。

不过这里隐含着一个问题,其实在网络环境中去判定一台机器是否可用是一个非常复杂的问题。

思考一下,如果Checker认为Server1不可用,这个时候可能是Checker本身存在问题或者Checker和Server1之间的网络存在问题,并不能断定Server1不可用。

又比如在网络分区的情况下,可能Checker认为Server1可用,但是其他应用可能无法通过网络访问到Server1。

分享现场我提出了这个问题,携程研发总监王兴朝给出的答复是这个问题确实非常复杂,确实通过单checker的方式是无法确定Server状态的(其实多Checker也很难)。携程的解决方式是由和应用在同一网段的checker去检查应用,尽量减少网络带来的问题。同时对一些状态比如5XX、4XX等会做记录,会有一些人工接入的处理措施。

其实我对这个实现并不是很满意,因为这个最困难的问题并没有解决,只是说结合人工去处理了。

第五个问题:如何利用好这个绝佳的监控场所?

这个是一个拓展的话题了,本身SLB是所有流量的入口,所以如何用好这块做好监控也是值得讨论的一个问题。

资料参考搜索2017上海QCon进行下载。


《恒生中间件如何助理证券经纪业务发展》

证券业务其实和平时接触的互联网业务相差还是比较大的,不过冲着“中间件”的标题就去听了这场分享。

这场分享除去一些证券业务背景的介绍,主要分享了一下几个问题:

  1. 如何将交易状态返回给客户端?
  2. 如何让用户以最快的速度下单?
  3. 如何缩短券商的清算时间?
  4. 业务开发要快速并且没有缺陷?

第一个问题:如何将交易状态返回给客户端?

引用了OSPF算法,在B节点异常的时候,D节点的处理结果可以通过D->C->A的路径反馈给A。

关于这个算法我并不了解,有兴趣可以自己研究下。

第二个问题:如何让用户以最快的速度下单?

这块的解决方案技术含量挺高的,主要考虑到了CPU的亲和性、缓存对齐等问题,这些是Java程序员很难考虑到的点(可能99%的程序员也不会考虑到这么底层的优化)。

第三个问题:如何缩短券商的清算时间?

这个结合了证券业务的特点,在非交易时段机器都是空闲的,恒生中间件利用这个特点在非交易时段使用Docker的方式,更大限度的利用机器资源来做清算,提升效率(也是非常高效的利用机器,非常好的优化点)。

第四个问题:业务开发要快速并且没有缺陷?

看到这个的时候还是有点震惊的,恒生把证券业务的场景不断的固话下来,最终把这些场景的业务都插件化,做业务开发的时候都可以用这种伪代码的方式(且是中文)来实现。

真的是超出了我原本对业务开发的认知。

这样在恒生做业务开发的程序员还有加之吗,以后还找得到工作吗?答:转行到券商去,写代码这么累的事就留给别人干吧:)

这场分享干货还是挺多的,特别是优化的实现上的很多小技巧。


《Heron的Exactly-Once实现》

这场分享完全是冲着Exactly-Once去的,但是实际听下来感觉重点不在Exactly-Once上,更多在他们公司的产品介绍上。

不过借这个题目聊一聊Exactly-Once语义。

Exactly-Once语义更多的是在消息队列的场景中,比如Kafka就提供了它支持Exactly-Once语义。

在消息队列中,消息分发的语义(Message Delivery Semantics)有如下几种:

  • At Most Once:消息可能丢失,但不会重复投递
  • At Least Once:消息不会丢失,但是可能会重复投递
  • Exactly Once:消息不丢失、不重复,且只被投递一次

要弄清楚这些语义,首先先弄清楚消息为什么会丢失和重复。

简单画了一下消息的生命周期,

发送流程有三个阶段:

  1. Producer向Server写入消息
  2. Server存储消息
  3. Server响应Producer写入结果

消费也有三个阶段:

  1. Server将消息投递给Consumer
  2. Consumer在本地执行消费逻辑
  3. Consumer应答Server自己的消费结果

在上述的步骤中,以下情况都将导致消息丢失或重复:

  • 步骤①超时,此时Producer并不能确定消息是发送成功还是发送失败

    • 如果Producer选择重新发送消息,那么Server可能存储了两条相同的消息,即消息重复
    • 如果Producer选择不发送消息,可能Server一条消息都没有存储,那么消息就丢失了
  • 步骤③的情况和步骤①是完全一致的,如果步骤②可能成功也可能失败,如果步骤③超时,则Producer也无法确定消息的情况
  • 步骤1超时,此时Server不知道Consumer是否接收到了消息
    • 如果Server重新发一次消息给Consumer,那么Consumer就会消费两次
    • 如果Server不发送消息给Consumer,那么Consumer就可能没消费到消息
  • 同样步骤3即响应给Server进度信息,如果超时,情况和步骤1完全一致

上面的流程并不准确,比如消费流程中,可能是收到消息后先ack给服务端,之后再执行消费,即步骤2、3的顺序调换。

语义的选择

  • At Most Once:消息可能丢失,但不会重复投递
  • At Least Once:消息不会丢失,但是可能会重复投递
  • Exactly Once:消息不丢失、不重复,且只被投递一次

三种语义中,At Most Once、At Least Once都比较容易实现,Exactly Once在网络环境中则是非常困难的。

实际中,我们可能根据业务特点选择不同的语义支持(说白了是因为做不到支持Exactly Once),比如一些统计类的业务可以接受数据丢失那么可以选择At Most Once;而对于不能接受丢失的,采用At Least Once加业务实现幂等消费来支持。

简单粗暴的支持At Most Once语义的方式即:

  1. 遇到超时则不重发
  2. Consumer在收到数据后先ack进行进度更新,之后再进行消费(如果此时Crash了,下一次则从已经更新的进度开始继续消费,所以会丢失数据)

对于At Least Once语义支持:

  1. 遇到超时场景就重发
  2. 业务自己实现幂等(重复消费一条消息对业务无影响)
  3. Consumer消费完消息后再ack进度(可能消费完了消息未更新进度,此时Crash下一次获取的消息是上次消费过的)

Exactly Once

能做到支持Exactly Once吗?

Exactly Once是理想的消息分发语义(谁不期望消息补充不丢呢),业务方不需要过多的考虑消息的语义。

根据上面的消息生命周期,要实现这个语义,我们需要做哪些事情呢?

  1. 消息发送不重复(或发送重复的消息不会被存储下来)
  2. 已经发送成功的消息不会丢失
  3. 保证消费时,如果消息被消费了,那么进度一定被更新;如果消息没被消费,进度一定不会更新

对于第一步,保证发送不会重复或者重复的消息不会被存储下来

首先,消息需要唯一的ID,来识别两条消息是否是同一条消息。

(这里的唯一ID设计又是一个有趣的问题)

其次,Server端保证幂等,即如果收到的消息的ID相同,过滤掉消息。

这里涉及Server端需要缓存多久的消息来判断消息是否重复呢?不能每条消息过来之后把历史消息遍历一遍进行判断吧?

如果消息的ID是连续的会不会有一些帮助?

第二步,保证发送成功的消息不会丢失

这里涉及到数据的可靠性,一般消息中间件中我们都会对消息进行持久化,即写入到磁盘中。

然后通过主备或者其它方式来增加数据备份,保证数据可靠性。

第三步,保证消费进度和消费行为一致

在消费之前跟新进度则可能丢失消息;

在消费之后更新进度则可能重复消费;

那就是消费和进度要同时更新!

“保证消费时,如果消息被消费了,那么进度一定被更新;如果消息没被消费,进度一定不会更新”——这个描述,很容易想到事务。

这里可以通过将业务结果和消费进度在一个事务里面进行保存来达到一致。

比如借助MySQL来存储业务结果和消费进度(业务结果本身可能就是存在MYSQL中),通过事务保证了如果业务结果存储成功,那么进度一定保存成功;业务结果保存失败,那么进度也不会保存。

(业务结果没保存成功自然可以理解为没有做业务,可以重新消费消息重做业务)。

完成以上步骤,好像可以一定程度上满足Exactly Once语义。


总结

以上是最后一篇关于2017上海QCon的总结。

3天的QCon之旅,还是收获挺多的,也认识了一些朋友。如果有机会,去参加一些类似的技术会议,对个人成长还是有一些帮助的。

2017QCon上海站PPT下载:PPT下载

欢迎关注公众号交流。

2017上海QCon之旅总结(下)的更多相关文章

  1. 2017上海QCon之旅总结(中)

    本来这个公众号的交流消息中间件相关的技术的.上周去上海参加了QCon,第一次参加这样的技术会议,感受挺多的,所以整理一下自己的一些想法接公众号和大家交流一下. 三天的内容还挺多的,原计划分上下两篇总结 ...

  2. 2017上海QCon之旅总结(上)

    本来这个公众号的交流消息中间件相关的技术的.这周去上海参加了QCon,第一次参加这样的技术会议,感受挺多的,所以整理一下自己的一些想法接公众号和大家交流一下. 下面进入正题,从自己参加了的一些分享中挑 ...

  3. F# 之旅(下)

    写在前面的话 学习 F# 一定要去体会函数式编程的特点,推荐一下阮一峰的日志<函数式编程入门教程>. 在这篇文章中 递归函数 记录和可区分联合类型 模式匹配 可选类型 度量单位 类和接口 ...

  4. Linux之旅-ubuntu下搭建nodejs环境

    .NET Core也开源了,并且可移植到Linux下,而ubuntu作为linux发行版的翘楚,极大的方便了初学者的入门,搭建完ASP.NET Core运行环境后,作为半前半后的开发人员,就继续着搭建 ...

  5. 移动端踩坑之旅-ios下fixed、软键盘相关问题总结

    最近一个项目掉进了移动端的大坑,包括ios下fixed布局,h5唤起键盘等问题,作为一个B端程序员,弱项就是浏览器的兼容性和移动端的适配(毕竟我们可以要求使用chrome),还好这次让我学习了一下相关 ...

  6. 2017上海C++面试

    今天参加了一次面试,觉得比较有意思,收获蛮多,简单的在这里总结下. 开始做了一道算法题,也就是算术运算表达式中的左括号和右括号的匹配,用c++写.我大概10分钟就写完了.其实以前一直想实现这个功能的, ...

  7. 我的Android进阶之旅------>Ubuntu下不能识别Android设备的解决方法

    Bus 001 Device 006: ID 1b20:0c81 MStar Semiconductor, Inc.      今天不知道Ubuntu发了什么疯,昨天还用的好好的,今天就突然不能识别我 ...

  8. UOJ#335. 【清华集训2017】生成树计数 多项式,FFT,下降幂,分治

    原文链接www.cnblogs.com/zhouzhendong/p/UOJ335.html 前言 CLY大爷随手切这种题. 日常被CLY吊打系列. 题解 首先从 pruffer 编码的角度考虑这个问 ...

  9. .NET跨平台之旅:探秘 dotnet run 如何运行 .NET Core 应用程序

    自从用 dotnet run 成功运行第一个 "Hello world" .NET Core 应用程序后,一直有个好奇心:dotnet run 究竟是如何运行一个 .NET Cor ...

随机推荐

  1. 新旧apache HttpClient 获取httpClient方法

    在apache httpclient 4.3版本中对很多旧的类进行了deprecated标注,通常比较常用的就是下面两个类了. DefaultHttpClient -> CloseableHtt ...

  2. 自定义工作流活动报错:您无法登陆系统。原因可能是您的用户记录或您所属的业务部门在Microsoft Dynamics 365中已被禁用。

    本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复265或者20170926可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong.me ...

  3. 如何关闭eclipse对js xml的验证

    经常会发现导入一些js框架,eclipse会编译报错 这是eclipse对js的瞎验证,如何解决呢? 关闭eclipse对js,xml的验证即可: 菜单Window - > Preference ...

  4. margin:0px auto和text-align:center区别

    (1)margin:0px auto :作用于块级元素,对块级元素进行居中 (2)text-align:center:作用于内联元素,必须放在要居中的内联元素所在的块级元素. 例: (1) <d ...

  5. java数据库编程之数据库的设计

    第一章:数据库的设计 1.1:为什么需要规范数据库的设计 1.1.1:什么是数据库设计 数据库设计就是将数据中的数据实体及这些数据实体之间的关系,进行规范和结构的过程. 1.1.2:数据库设计非常重要 ...

  6. ch3-模板语法({{}} v-html v-bind:id 表达式 指令 修饰符 过滤器)

    1 模板语法 Vue.js 使用了基于 HTML 的模版语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据. 所有 Vue.js 的模板都是合法的 HTML ,所以能被遵循规范的浏览器 ...

  7. Mysql安装后打开MySQL Command Line Client闪退解决方法

    1.开始菜单下;Mysql--->mysql server 5.6-->mysql command line Client ---右击,选择属性 2.在属性下查看目标位置: 3.将安装目录 ...

  8. 学习PID

    最近在想自己的文章有些是不是写的太难以理解了呢.........竟然好多人看了还是会直接问我很多问题....... 其实PID哈靠自己想像就能自己写出来自己的代码,也许是网上的讲的太过的高深什么积分微 ...

  9. Docker入门系列(一):目标和安排

    Docker入门系列(一) 这个系列的教程来源于docker的官方文档,此文档的目的在于一步一步学习docker的使用方法. 这一系列的教程有如下几篇文档: docker安装启动 构建第一个docke ...

  10. python批量修改word文件名

    最近不小心把硬盘给格式化了,由于当时的文件没有备份,所以一下所有的文件都没有了,于是只能采取补救措施,用文件恢复软件恢复了一部分的数据出来,但是恢复完毕的文件的文件名全丢了,所有的文件只有代号,如下面 ...