Weekly Reading 170820

  1. 阿里周洋分享了中间件技术峰会分享|双11高可用架构演进之路, 介绍了阿里第四代技术架构,将其分为了,容量规划、限流降级、依赖治理、开关预案、故障演练、流量调度。
    其实这是一系列,另外一篇中间件技术峰会分享|阿里电商架构演变之路,很简略的概括了阿里架构史,其实也是国内很多公司开发的架构史。里面将淘宝架构分为:
    淘宝从初创开始到今天,我们的技术架构总体上经历了四代:
    第一代是基于LAMP的一套结构。第二代是基于Java的应用架构。第三代是基于分布式体系,构建出一整套的分布式架构。第四代是基于IDC,不但应用能够分布,整数数据中心也能够分布。

    这里也可以看出,前三代,阿里跟随国外技术圈。本人工作过几家大公司其实也是该思路。
  2. 10,000 Java performance tips over 15 years - what did I learn
    上面是油管链接,也可以去voxxed 2017, devoxx conf上面一些基于JVM语言/优化等链接还是很值得看的。

    作者简介: Jack Shirazi
    Head of Engineering for Nexmo, the Vonage API, Java Champion since 2005,Founder of javaperformancetuning.com,Author of Java Performance Tuning (O’Reilly),JUG Leader.
    视频和ppt很值得一看,列举了JAVA优化(主要基于JVM/OS等层面)常见的方法,虽然许多介绍属于蜻蜓点水式的,但作为日常JAVA性能优化参考指南的需求还是可以的。这里的链接,以便不好翻墙或查找困难。

  3. MySQL 高性能的索引策略,总结了MySQL高效索引创建约定,很全面了。许多开发,存储上来首选就是NoSQL等,我觉得MySQL依旧是高并发的首选,只要你对设计得当。
    “在选择和编写利用索引的查询时,记住下面三个原则:
    a)单行访问是很慢的。(特别是机械硬盘存储,SSD 的随机 I/O 快很多,不过这点仍然成立。)最好读取的块中包含尽可能多所需的行。使用索引可以创建位置引用以提升效率。
    b)按顺序访问范围数据是很快的。原因:1,顺序 I/O 不需要多次磁盘寻道,所以比随机 I/O 快很多(特别是机械硬盘);2,如果服务器能够按需要顺序读取数据,那么就不再需要额外的排序操作,并且 group by 查询也无须再做排序和将行按组进行聚合计算。
    c)索引覆盖查询是很快的。存储引擎不需要回表查找行。”

  4. Linux 如何添加一个 Swap 文件 - Defonds 的专栏, 有些情况下,一些开发人员会选择增加swap空间以提升Linux 服务器/桌面系统的性能。本文作者翻译nixCraft创始人Vivek Gite在不创建一个新的分区的前提下添加一个swap文件到Linux系统的文章。
    虽然有人也强调过多的swap甚至swap有害,不过对个人桌面系统/非大型应用,本文值得一看。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # dd if=/dev/zero of=/swapfile1 bs=1024 count=524288
    # chown root:root /swapfile1 //为交换文件设置合适的文件权限
    # chmod 0600 /swapfile1 //为交换文件设置合适的文件权限
    # mkswap /swapfile1 //设置一个 Linux 交换区域
    # swapon /swapfile1 //启用交换文件
    # vi /etc/fstab //修改 /etc/fstab 文件
    追加一行:
    /swapfile1 none swap sw 0 0
    $ free -m
    # swapon -s //如何显示 Linux 上交换区的使用摘要
    # --
    # swapoff /swapfile1 //关闭 Linux 上用于 page 分页以及交换区域的设备和文件
    # swapon -s
  5. 发表在IBM dw上的文章 为什么完美的lambda表达式只有一行
    作者列举了充满危险的长lambda表达式(该用拆分短小的), 值得借鉴。
    不过,如果跟着作者的思路/需求来看,作者说的却是是有道理的,但可惜的是如果我们跳出 lambda函数的范畴,就会发现,或者实践中会发现,其实这么做坏处更多,这里有篇文章可以解释, 挺欣赏后者对DRY原则和“GoF”的Design Pattern的“have largely gone unchallenged for decades now and direly require reconsideration, especially so since the programming landscape as well as paradigms have evolved vastly in the recent years”质疑态度,如果你真的阅读并写过代码的话,作者质疑了程序员还在奉为圣经的《clean code》,Martin Fowler的function length讨论。在实际开发中,flexibility to accommodate any changes以及可持续/可控的修改也很重要,所以,我认为关键是作出好的Abstraction,不仅仅是模型的抽象,还有架构/代码/变与不变的抽象,受编程书以及大公司教条的误导,有的开发过分关注 int xxx =100这样“写死了”的问题,其实比这更严重的是代码组织架构组织架构死了,才是更严重问题,毕竟前者就算hard code,可是代码改起来好改。所以关键是要做好“Abstraction”。

  6. kafka-exactly-once引发的争吵。
    一个老生常谈的问题,源于kafka官宣Exactly-once Semantics are Possible: Here’s How Kafka Does itkafka 0.11版本引入exactly once的实现“we have hit an exciting milestone the Kafka community has long been waiting for: we have  introduced exactly-once semantics in Apache Kafka in the 0.11 release ”, 可以说是企图对消息幂等思考的致以尾声,并实现:正好一次传递与事务性消息。
    之后引发许多讨论Reddit/HN, 更多人质疑这是对 FLP理论或两个拜占庭将军的问题的违反,Kafka的co-creator Jay Kreps发文做了解释exactly-once-support-in-apache-kafka
    更多:what-kafka-exactly-once-really-means,里面:

    The features which make the above possible are:
    a)idempotent producers (introduced in 0.11)
    b)transactions across partitions (introduced in 0.11)
    c)Kafka-based offset storage (introduced in 0.8.1.1)
    Let’s see which of these features are useful at which stage of an exactly-once processing pipeline.
    

    Exactly-once or not, atomic broadcast is still impossible in Kafka – or anywhere, ZK的PMC Flavio Junqueira argued that No consensus in exactly-once.
    You Cannot Have Exactly-Once Delivery Redux里作者将该问题归结为“Exactly-once delivery” and “Exactly-once processing”. 文章虽简单,但是涉及许多分布式知识。

    “Delivery” is a transport semantic. “Processing” is an application semantic.
    “Exactly-once delivery” is a poor term. The word “delivery” is overloaded. 
    Frankly, I think it’s a marketing word. The better term is “exactly-once processing.” 
    Some call the distinction pedantic, but I think it’s important and there is some nuance. 
    Kafka did not solve the Two Generals Problem. Exactly-once delivery, at the transport level, is impossible. 
    It doesn’t exist in any meaningful way and isn’t all that interesting to talk about. 
    “We have a word for infinite packet delay—outage,” as Jay puts it. That’s why TCP exists, 
    but TCP doesn’t care about your application semantics. 
    And in the end, that’s what’s interesting—application semantics. 
    My problem with “exactly-once delivery” is it assumes too much, 
    which causes a lot of folks to make bad assumptions. 
    “Delivery” is a transport semantic. “Processing” is an application semantic.
    ...
    To achieve exactly-once processing semantics, 
    we must have a closed system with end-to-end support for modeling input, 
    output, and processor state as a single, atomic operation. 
    Kafka supports this by providing a new transaction API and idempotent producers. 
    ...
    Exactly-once processing is an end-to-end guarantee and the application 
    has to be designed to not violate the property as well. If you are using the consumer API, 
    this means ensuring that you commit changes to your application state 
    concordant with your offsets as described here.
    

    最后,Jay Kreps写了第二篇文章作解释,exactly-once-one-more-time

    We think the factoring of the problem into two pieces makes this far far easier:
    a)Processing using the streams api
    b)Connectors using the connect api
    This makes guarantees for processing quite transparent (you just set a config to enable it). 
    The only real restriction is that you must maintain state using the provided facilities.
    Connectors require more thought about the interaction between Kafka and the external system 
    but these can be made reusable. So if one person has implemented a Kafka=>Mysql connector 
    and tested it everyone else can just use that.
    

    这里美团消息队列的扫盲贴, 忘记了RocketMQ曾声称自己是exactly once还是消息顺序可保证了。

  7. 对上面补充,一篇很好的中文介绍 FLP Impossibility的证明FLP Impossibility作为分布式重要定理
    FLP 不可能原理:在网络可靠,存在节点失效(即便只有一个)的最小化异步模型系统中,不存在一个可以解决一致性问题的确定性算法。
    不可能原理实际上告诉人们,不要浪费时间去为异步分布式系统设计在任意场景下都能实现共识的算法. 不过作为细化,CAP定理则相当于在实践中提供了一个几乎可以打破FLP问题的解决方案。
  8. the morning paper,为作者叹,能有这么多时间去读paper,关键是精力涉及面如此之广
    A better, faster, smaller Approximate Membership Query data structure - time to retire your Bloom filters, 我们知道,在Approximate Membership Query (AMQ) data structures的需求里,许多追求高性能的系统喜欢用Bloom Filter作为去重方法,但是作为m位BitSet这样简单数据结构,支持插入和查找两种操作, 这在在需要经常变动(增删)的数据集中,Bloom Filter性能不如其改进版Cuckoo Filter,这篇文章介绍了类似Cuckoo Filter的数据结构Counting Quotient Filter,不过原论文好像被删除了。
  9. JVM Anatomy Park #2: Transparent Huge Pages JVM Anatomy Park系列文章第二篇,实验了并讨论对于java应用:What are Large Pages? What are Transparent Huge Pages? How does it help me?!
  10. 对LogLog Counting的进一步理解, 理解Hyperloglog Counting, Redis也引入非常节约资源的Hyperloglog,不过Hyperloglog只能Counting,实际还是鸡肋的。
  11. ifeve的ClassLoader解惑
    介绍了java classloader一些问题,不过文中举例可惜没有提到著名的SlF4j面对的classloader问题。
    另介绍了Tomcat的ClassLoader。
    总结下,默认情况下tomcat中commonloader,sharedloader,catalinaloader是同一个加载器,
    其类查找路径都是同一个地方。其实catalinaloader主要工作应该是加载tomcat本身启动所需要的类,
    而sharedloader是webappclassloader的父类,所以应该是加载一些所有webap共享的类,而commonlaoder作为
    sharedloader,catalinaloader的父类,自然设计目的是为了加载二者共享的类。所以如果能恰当的使用tomcat中设计的这种策略,
    修改catalina.properites中三种加载器类加载路径,就会真正达到这种设计效果
    
  12. 另一篇介绍SpringBoot Classloader的文章深入Spring Boot:ClassLoader的继承关系和影响
    总结spring boot里ClassLoader的继承关系
    a)在IDE里main函数执行时,只有一个ClassLoader,也就是SystemClassLoader
    b)在以fat jar运行时,有一个LaunchedURLClassLoader,它的parent是SystemClassLoader
    LaunchedURLClassLoader的urls是fat jar里的BOOT-INF/classes和BOOT-INF/lib下的jar。
    SystemClassLoader的urls是fat jar本身。
    c)在解压目录运行时,和fatjar类似,不过url都是目录形式。目录形式会有更好的兼容性。
    spring boot 1.3. 和 1.4. 版本的区别
    在1.3. 版本里应用的类和loader的类都是打包在一个fat jar里应用依赖的jar放在fat jar里的/lib下面。
    1.4.
    版本后loader的类放在fat jar里应用的类打包放在fat jar的BOOT-INF/classes目录里
    应用依赖的jar放在fat jar里的/lib下面。
    带来的问题
    a)demo.jar!/BOOT-INF/classes!/ 这样子url不工作
    b)demo.jar!/META-INF/resources 下的资源问题
    c)getResource(“”) 和 getResources(“”) 的返回值的问题
    d)类似 classpath:*-service.xml 的通配问题

  13. 入门tf。
    http://www.pinchofintelligence.com/detecting-bats-recognising-sound-tensorflow/
    https://medium.com/towards-data-science/how-to-build-a-dynamic-garden-using-machine-learning-d589468f7c04
    https://medium.com/towards-data-science/number-plate-detection-with-supervisely-and-tensorflow-part-1-e84c74d4382c

  14. 来自火丁笔记的SYN和RTO问题
    RTO的最大值是 120 秒,最小值是 200 毫秒,在建立连接后,因为目前网络都很快,所以大部分连接的
    RTO 都会接近 TCP_RTO_MIN,也就是 200ms,可以通过「ss -int」命令来确认
  15. http://developer.lightbend.com/blog/2017-08-11-sbt-1-0-0/
  16. https://pragmaticintegrator.wordpress.com/2017/08/13/small-hack-to-avoid-ssl-validation-in-spring-resttemplate/
  17. 该来的终究要来的。JDK 9: Pitfalls For The Unwary, infoq的一篇Java 9 新特性介绍及 Jigsaw 一览
  18. cp 命令两个高效的用法
    cp -r Misc /media/clh/4388-D5FE //更新你的文件夹
    cp –force –backup=numbered test1.py test1.py //版本备份
  19. 没想到啊,一致性还分这么多种类!casanddra 跟最终一致性
    Cassandra 被称为”最终一致性”,有点误导人,Cassandra 一致性是可以调整的。
    那么什么是一致性?现实世界是按照一致性的级别进行衡量的,最终一致性是几种一致性模型的一种:
    严格一致性(Strict Consistency):所有的请求必须按照线性方式执行。读出的数据始终为最近写入的数据。
    这种一致性只有全局时钟存在时才有可能,在分布式网络环境不可能实现;
    顺序一致性(Sequential Consistency):所有使用者以同样的顺序看到对统一数据的操作,但是该顺序不一定是实时的;
    因果一致性(Causal Consistency):只有存在因果关系的写操作才要求所有使用者以相同的次序看到,对于无因果关系的写入则并行进行,
    无次序保证。因果一致性可以看作是对顺序一致性功能的一种优化,但是在实现时必须建立与维护因果依赖图,是相当困难的;
    管道一致性(PRAM/FIFO Consistency):在因果一致性模型上的进一步弱化,要求由某一个使用者完成的写操作可以被其他所有的使用者按照顺序感知到,
    而从不同使用者中来的写操作则无需保证顺序,就像一个一个的管道一样。相对来说比较容易实现;
    弱一致性(Weak Consistency):只要求对共享数据结构的访问保证顺序一致性。对于同步变量的操作具有顺序一致性,
    是全局可见的,且只有当没有写操作等待处理时才可进行,以保证对于临界区域的访问顺序进行。
    在同步时点,所有使用者可以看到相同的数据;
    释放一致性(Release Consistency):弱一致性无法区分使用者是要进入临界区还是要出临界区,释放一致性使用两个不同的操作语句进行了区分。
    需要写入时使用者 acquire 该对象,写完后 release,acquire-release 之间形成了一个临界区,
    提供释放一致性也就意味着当 release 操作发生后,所有使用者应该可以看到该操作;
    最终一致性(Eventual Consistency):所有的复制都会在分布式系统内部传播数据,但是需要花点时间,最终所有节点的副本数据会实现一致。
    当没有新更新的情况下,更新最终会通过网络传播到所有副本点,所有副本点最终会一致,也就是说,
    使用者在最终某个时间点前的中间过程中无法保证看到的是新写入的数据。可以采用最终一致性模型有一个关键要求,
    需要用户可以接受读出陈旧数据;
    Delta 一致性:系统会在 Delta 时间内达到一致。这段时间内会存在一个不一致的窗口,该窗口可能是因为日志迁移的过程导致的。
    最终一致性的几种具体实现
    读不旧于写一致性(Read-your-writes consistency):使用者读到的数据,总是不旧于自身上一个写入的数据。
    会话一致性(Session Consistency):比读不旧于写一致性更弱化。使用者在一个会话中才保证读写一致性,启动新会话后则无需保证。
    单读一致性(Monotonic Read Consistency):读到的数据总是不旧于上一次读到的数据。
    单写一致性(Monotonic Write Consistency):写入的数据完成后才能开始下一次的写入。
    写不旧于读一致性(Writes-follow-reads Consistency):写入的副本不旧于上一次读到的数据,即不会写入更旧的数据。
    Cassandra 把一致性级别的决定权交到了客户端手中,这意味着客户决定每一次操作的一致性级别,即决定写入操作过程中集群内部必须有多少份副本完成才能响应读请求。如果客户设置的一致性级别的值小于设置的副本数量值,那么即便一些节点宕机,更新依然成功。
  20. Elasticsearch前沿:ES 5.x改进详解与ES6展望
  21. 一篇老文章2017年会是Serverless爆发之年吗,虽然已过0.75年,可见批评之声还是很多的。
  22. SpringBoot源码分析之条件注解的底层实现
  23. 数据库事务系列-事务模型基础, 好文,记忆不熟的可以常看,至少可以用来。
  24. Using JUnit 5 Parameterized Tests系列文章
  25. @Transactional导致AbstractRoutingDataSource动态数据源无法切换的解决办法
    在org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin 这个类的源代码中找到了答案
    第7-16行,在开始一个事务前,如果当前上下文的连接对象为空,获取一个连接对象,然后保存起来,下次doBegin再调用时,就直接用这个连接了,根本不做任何切换(类似于缓存命中!)
    这样就解释得通了: doSomeThing()方法被调用前,加了一段select方法,相当于已经切换到了slave从库,
    然后再进入doBegin方法时,就直接拿这个从库的链接了,不再进行切换。
    那为啥其它同样启用事务的方法,又能正常连到主库呢?同样的解释,因为这类方法前面,没有任何其它操作,
    而xml中的动态数据源配置,默认连接的就是master主库,因此没有问题。
  26. 如何评价波恩大学 Norbert Blum 关于 P≠NP 的证明,这个链接跟进Norbert Blum 关于 P≠NP 的证明。
    虽然每隔一段时间都会有证明冒出,虽然基本上认为不相等才是正道,还是有人不死心企图证明之。吾等表示围观还是要围观的。
  27. 最后,来一段中二的 Daily WTF 有趣的计算机幽默