炎热焦灼的八月

显然,看到这个题目的时候,说明拖延症又犯了。

这个月天气炎热,个人也进入了一个相对焦灼的状态。从心里深刻的知道这不是一件坏事,只是当前面临的问题和挑战是需要去直面并迅速解决。

这个月最大的感慨是在「专注」上做得不够。导致很多事情都在上下文切换的过程中被肢解的支离破碎,完全没有了初心,当然离预期也就相去甚远了。

与之关联的另一个做得不好的点是「效率」。在思维体力上,自我感觉已经进入一个相对强韧的阶段,但是在解题效率上依然让自己常有隐忧。今天在路上,看了达里奥《原则》的个人生活部分。挺有启发的,他讲个人生活愿景的追求实现划分成5个阶段,每个阶段有给出了不同的原则。自我对照检查,我觉得自己在认清问题本质以及规划上面是存在严重问题的。导致问题主体识别出现偏差或错误,而规划上又没有达到完全开放大脑的状态,因此,无论是在视角高度还是做事深度上都深陷泥潭。

这个月尝试换一种心态和姿态与最爱的人相处。虽然依然做不到大脑完全开放的状态,但是意外的发现其实当我尝试这样去做的时候,至少我已经放下潜意识中的自我,不在用这种潜意识做一些理所当然的决定,然后筛选证据,去印证满足自己内心的欲望和幻想。妞儿给了自己机会让自己开了一个好头,期待自己后面的改变。

本月推荐的电影当然是《蚁人2》,因为这是这个月看过的唯一一部电影。适度的夸张而不荒谬,沉重的剧情总是用暖心的美式幽默裹挟,彩蛋中巧妙的与复联结合,这三点应该是本片让自己最喜欢的点。如果你还没去电影院,推荐你去看看。

本月推荐的书毫无疑问是《原则》。应该说这本书红黑的精装版本在很大程度上是可以让你在公共场所作为小资的装X读物的。但是,我觉得这本书的很多书评的确有点过誉这本书了。书的确不错,不过作者依然没有能够摆脱为了写一句话而堆砌一个章节的问题。并且,本质上,这其实就是大家口中最正宗的心灵鸡汤类读物。我并不反对心灵鸡汤,我只是很难理解为什么很多人总是向你表达自己不屑于心灵鸡汤读物的同时却认为《原则》是一本高大上的书。

就我个人而言,《原则》毫无疑问是一本让我受益匪浅的书。它让我自查出了很多自己以前认为理所当然的点,虽然我不一定完全同意其建议的原则和行事方式。但是,的确让我开始重新思考和认识一些事情。这与之前看到的陆奇给后辈的原则其实是相互呼应的:陆奇成功背后的故事:决定人生高度的,是这 7 条原则
。陆奇的给出的这些原则非常具体,但是做起来非常不易,摘录如下,以自勉:

  • 坚守价值观(坚持做对的事情)
  • 永远正能量
  • 高度自律
  • 每天学习
  • 把公司的事当成自己的事
  • 从我做起
  • 谦逊真诚

明天会认识很多优秀的新同学,带着小小的焦虑感,但一下能结识如此多有意思的灵魂,依然非常期待。

个税起征点调整到5000可能只是一针生理盐水

8月最后一个工作日,听闻我朝要将个税起征点调整至5000元人民币。本以为是一针兴奋剂,即使是短效的;仔细看了一下,却发现可能只是一针生理盐水。

中国修改个人所得税法的决定经十三届全国人大常委会第五次会议表决通过,起征点确定为每月5,000元人民币,新个税法于2019年1月1日起施行,2018年10月1日起施行最新起征点和税率。关于个税征收方面,央视新闻的这张图解释非常清楚:

变化1、3都是可以直接数字量化,这部分的确可以让大家立即尝到这次个税修改的甜头。而让大家想象空间很大的变化2因为缺乏具体实施的细则,这里不做任何揣测。

但是,这些变化其实不是什么国家发红包。这只是我国个税例行的周期性调整修改。之前两次调整分别是:2005年调整起征点到1600元;2011年,调整个税起征点至3500元。这次从3500调整到5000元,无论是调整周期还是调整幅度其实是远不如2011年的。这种情况一方面与个税调整是以增加税收为目标相吻合,另一方面也反映出当前经济压力。

你没有看错,个税调整是以增加税收为目标的。而这次个税调整造成的个税总额暂时性降低可能到不到一年就能逆转过来。

而这次调整被大家吐槽最多的可能就是税务局以后将负责征收社保。之所以被吐槽,是因为以前社保局负责征收社保的时候因为没有与收入挂钩,因此很多企业按照最低标准为员工缴纳社保。由税务局负责征收以后,这个中间的信息壁垒不复存在,企业只能够按照实际公司为员工缴纳社保。带来的后果就是企业的用人成本上升。

社保bug的修复所造成的影响可能比想象的大。这个bug不影响国企、央企、大厂,因为这些企业基本都是紧跟政策走。而对小微企业的影响就不可小觑了。在当前的经济压力背景下,这其实是对这类企业的征税(虽然缴纳社保并不算征税,但是哪个企业敢不给员工缴纳社保呢?)。可能员工觉得虽然社保会多交一点,但是日后可以领呀(暂且不论你退休的时候社保这个击鼓传花还能不能传下去……),企业主烦恼就让他们烦恼吧。短期看也许是这样的,但是在社会分工如此细化的今天,很多环节都是会联动受影响的。企业用人成本的增加最终一定会反映在整个经济层面。而具体到雇佣层面,要么会有更多的小微企业在明年关门大吉,要么企业主减少能提供的工作岗位数量。

从个税征收总额数据看,我国过去几年的个税都保持在10%以上的增长,是GPD增速的两倍以上。这次调整其实更多的是稳住税基,同时进一步巩固征税成本低的中等收入人群。在这次调整的细则中也可以应证这一点:草案中,将工资薪金、劳务报酬、稿酬和特许权使用费四项劳动性所得实行综合征税,目的是实施”按人征税“。此番修改的本意,是认为拥有多项收入来源的人士在现行税制下享受了更多的减免优惠,如果将多个收入来源综合起来征税,就会更合理,真正起到调节收入的作用。

我们再看一组财政部2017年财政收人情况数据:

从去年开始,你可能没少听说要为企业减免税负的的消息。但是增值税、消费税、企业所得税的实际数据可能让你失望了。所以,从整体上开,财政部这套班子的思路前后还是非常一致的🤔。而这次的个税调整,其实是去年开始实行的去地税化改革一揽子计划措施的一部分罢了。从这点看,税务局以后会兼任更多的职能和现金流入口。

总体来看这次个税改革喜忧参半,毕竟不能所有的好处都让P民给占了。我们看一下上述后面的税收大头:车辆购置税今年上半年宣布的减免政策估计大部分人都当成不存在了;进出口税在贸易战的当口根本指望不上。那么这次的个税改革可能代表了后续更多的系列财政举措,这个改革可能连一个国家红包都算不上,只是给你象征性的打了一针生理盐水,肯定打不死人,但是会让大部分自嗨的如同一支兴奋剂。

谈谈我认识的优秀的人和有趣的灵魂(二)

上周简单谈了谈认识的几个典型而有意思的人:谈谈我认识的优秀的人和有趣的灵魂。篇幅原因,还有很多有有趣的人没能记录下来。今天算是上一篇的姊妹篇,会谈更多的人,隐私关系,不会说的太细,但是人物的维度会更丰富。

大洋洲的 Bimmer

最开始关注到王同学是因为一个共同的兴趣:车,一个算不上高雅,稍微世俗的爱好。有人说,男人只不过是年龄更大的男孩,从某种意义上说是对的:很多男生的兴趣爱好从小到大始终是离不开枪、车、球。很不幸,在这点上,我跟王同学双双中枪。

因为跟王同学有很多趋同的背景和观点:IT男,喜欢驾驶,Bimmer,因此对其有一种天然的无距离感。王同学爱车,爱 BMW 在中文推特圈是非常有名的。毫不夸张的说,如果谁想咨询了解 BMW 任意车款,这个圈子很多人第一个想到的 Bimmer 一定是王同学。前不久,王同学购入了让人口水的 M2, 所以你丝毫不用担心其是否是键盘车神。

然而,王同学真正让自己印象深刻的是其强烈而明确的知道自己想要什么。M2 当然算是一个,但是远不是他的全部。因为都是 IT 从业者,因此特别关注过他的职业生涯。从移民大洋洲,到大洋洲非常「幸运」的前后加入若干家上市/被上市公司收购公司来看,履历是非常精彩的。在我认识的人中,他的履历还算不上世俗上的「成功」,但是,他的每一步都是如此清晰和确定。在王同学这里,上帝是不掷骰子的。

王同学是那种真正做到 work hard, play hard 的人。做任何事情都非常认真,让时间在任何事情上面流转的质量都很高。这是很多人都明白的道理,但是真正做到的人很少。

宝马东与迈巴赫东

作为一名肉身在天朝的 IT 从业者,几乎每天都要从事一项无形存在的网络运动。如果你从事这项运动的时间足够长,你应该有很大概率知道东哥。咳咳,不是京东那个娶了你们奶茶妹妹的东哥😅

在自己的职业生涯中,有过一次 gap season, 期间做的一些事情顺藤摸瓜摸到了东哥的推特。意外的发现,东哥也在成都,于是有了面基的机会。但是,东哥其实是一个比自己想象要有内容、经历要丰富的人:一个传统教育上的坏孩子,然后靠着勤勉、聪明和韧劲,活出了自己的野路子。除了网络相关,还在工地搬过砖,搞过旅行社,现在是本地一家硬件解决方案的大佬,经常介绍的项目单子都是千万起,诸位感受一下。

东哥聊起豪车来举重若轻,尤其是宝马和马巴赫。一般他的跟随者只能在他后面回复道:这种车我居然也敢点进来,看来我是膨胀了。

很多时候,村里的孩子找我聊一些人生困惑的时候,我都跟他们将东哥的故事。学历、家境和大环境都只是影响因素,但万万不能成为你的接口,至少,只要你手脚足够勤快,并且愿意动脑子,这个社会是饿不死人的。

拍拍屁股就下班的老专家

已经忘了最开始为何关注老专家了。后来印象深刻的却是因为老专家每天下班前都会发一张美臀照😂 (这一点跟冯大辉 Fenng 倒是挺类似的)。不过老专家的本事可不止发掉屁股照,而是一个资深的职场老司机。

可能很多技术出身的人会条件反射般的反感这种人,但是在我看来,其实他让我看到了职场的另一面。并不是说老专家一路上位是如何擅长玩弄权术,而是让很多人能够相对理性的看待真实的职场。

老专家经常挂嘴边的一句话是,如果这点自制力都没有,还攀登个屁的人生巅峰。这点自己感受挺深刻的。因为每当他发这句话的时候,我都还在肆无忌惮的刷手机或者消遣时间。看到他这句话如同挨了一耳光,还是继续刷手机和消遣时间😅

其实,任何人风骚都是建立在某种支撑上的。要靠先天和智力方面的优势全面碾压已经越来越不容易做到了。老专家当然是明白人,虽然平时说话风骚务必,但是其实每天拍拍屁股下班都是深夜;虽然平时拿股票奖金跟喝水一样,但是也会在遇到问题隐隐的焦虑和事情推动不顺利时的愤怒。什么时候老专家下班时候不在拍屁股了,我想那可能他真的有点累了。

怀揣互联网之心的央企许主任

有时候会尝试面试打靶,倒不是要换工作,而是了解一下市场最近技术和人才的风向标,同时聊一些人,且有很大概率结识一些有趣的人。许主任就是其中一个。

许主任就任于某央企,年轻骨干,距离下一步晋升部长就差临门一脚。阴差阳错,他们拿到了我的简历,让我过去聊聊。央企的背景让我还没去就闻到了一股浓浓的体制味道。因此聊天意愿并不强烈。但是发现他们公司离家很近,打算在上班前去聊聊,然后快速走人,即不影响上班,也算是礼貌地走一下流程。

一路聊下来,前面的小兵小将让我更加确信自己的判断。但是聊到许主任的时候,我的观点发生了一点变化,虽然对这家央企依然不感兴趣,但是对眼前这个人内心是发亮的,因此我们聊了一个上午。

以我对央企体制的了解,许主任是不应该对技术有如此深入和细致的研究的,这是在进行一场常规意义上面试时,其最初吸引我的地方。另一方面,他跟我介绍了其在部门进行互联网一些模式的尝试和探索,并非常坦诚的跟我沟通了这个地方的天花板和发展前景,自己的规划和面临的困难,以及对我的一些建议。其实这些聊天内容跟面试已经没有关系,更像是朋友之间的聊天。如果是去之前我认为央企就是一滩死水,但是遇到许主任以后,我知道了其实每个组织都有认真做事的聪明人,而一般这种大型的组织都是复杂的,你需要识别出其中有意思的个体。

后来当然是没有去许主任那里,但是就在我快忘了这件事的时候。许主任给我打了一通电话,并不是来谈条件,只是说这是他的联系方式,后面可以常聊天。

套路迥异的李哥

打靶认识的另一个人是李哥。应该说这次常规意义上的聊天是没有达到预期的,可能 HR 错误传达了简历中的某些内容吧。好在我在现场跟李哥进行了沟通,消除了了这种误会。

李哥已经是他们公司的元老,办公室内一排(注意是一排)整齐的咖啡机,以及一堆凌乱的硬件,倒还挺有反差的小资和科技美感。李哥很疑惑的说,你中午没吃饭就过来,要是HR这么安排我,我才不来呢……你现在的公司时间点非常好,要是我才不动呢……卧槽,打靶无数,第一次见到这种让人不要考虑这个机会的套路的人……就在我狐疑和懵逼的时候,李哥直接说去下面吃饭吧,我想反正吃谁不是吃呀,跟着下去了。

饭桌上的聊天跟职位就没有关系了。聊了聊生活、成都的圈子,以及最近资本的动向。了解到了李哥挺多的背景和经历,心里默念牛x,路上加了微信。日后也联系和关注着。李哥其实已经渐入中年,他展示了可能自己十年后一个可能的状态。但是现在的李哥是非常快乐的,虽然行事完全不遵从公司套路,办公室就是他的试验场,改落地和执行的事情一个也没少。按照李哥的话说,及时下午3点下班,那一定是心安的。李哥自称资深球迷,但是预测比分的水平堪忧(估计今年世界杯赔了不少钱)。他跟我提起过他对其现在生活的感受:去其他公司的可能性不大了,也会被人歧视;我也不喜欢现在的公司,但是在这里,他还有他要去完成的使命。


还有很多人,各种原因,不太适合写出来,比如混圈子时候认识的昊哥和涛哥,一个永远能给出你满意答案的前辈,一个在组织内遵从内心认真做事并不惜在一定程度是与组织对抗的见贤思齐的同龄人。其实我深刻的明白,每个人因为自身价值体系和背景的不同,对同一个人的感受是千差万别,甚至是完全相反的。我记录的这些人未必是你的体系中的有趣的人,但是这没有关系,至少有几点是具有共性的:

  • 你结识人的路径很大程度上决定了你身边都是怎样的人。而你身边的这些人基本上能从各个维度反映你当前的状态。
  • 人没有绝对的有点与缺点,多关注和了解一个人的特点。
  • 读万卷书,行万里路,路途本身是无聊的,一定是路上你之前认识或不认识的人。

谈谈我认识的优秀的人和有趣的灵魂

这两年关注的事情不太聚焦(坦率讲,应该是非常发散😂),因此有意无意地接触了非常多的人。对于我这种不太擅长社交的人来说,最开始干这种事的时候是一百个不愿意的,并且喜欢用「无意义社交就是浪费时间」来宽慰自己。必须承认,这种有点混圈子嫌疑的社交的确利弊参半,但是,如果你要问对这些「弊端」是否后悔,我的回答一定是否定了。其中最重要的一个原因是,认识了一众优秀的人,和一众有趣的灵魂。

为了避免造成不必要的麻烦和误解,下面提到的人我都尽量模糊化处理。人物的顺序按照我的思路出现,比较随机,不分先后。

我眼中的“华阳乔布斯”

任何时候,评论前东家老板其实都是挺忌讳的事情。一方面,可能这个员工当初离开的时候受了小委屈;另一方面这个老板可能已经在公司制度层面要求将这些离职员工纳入招聘黑名单了。如果你在成都某游戏公司工作过,你大概率可以一次把这两条一次集齐。

但是,请别误会我。虽然一个公司的文化必然受创始人的价值观影响,但是如果你能够跳出当时的那种雇佣关系,毫无分别心的看这个人的过往和经历,往往能够对他有不一样的认识和看法。显然,前老板“华阳乔布斯”(后简称乔)是让我意识到这一点的人。

乔因为极度推崇、学习和实践苹果乔布斯而得名。举几个例子:乔如果看到某个邮件存在问题,他会在全体邮件、公司大群中直接怼人,并在末尾附上一句「建议辞退该员工」;乔如果对项目不满意,他会直接过来跟执行人直接对骂,甚至……干架;要进入 t 公司也不容易,首先要测智商,“低能儿”不要,通过所有面试以后,还有一场面向公司高管的入职演讲,这可不是做样子,是真正的大概率刷人的;离开 t 公司,会上公司招聘黑名单……

我以前对乔的这些做法挺困惑的,还在 t 公司那会儿,一次跟领导聊道,乔这样行事,是不是你们这群高管惯出来的巨婴?领导稍微迟疑了一会儿,说,他虽然年长乔好几岁,但是内心对乔的心怀尊敬的,然后他谈了公司当初是如何在乔的带领下成长和如何克服困难的。我当时没有接话,陷入了尬聊。如今想来,很多人都会当局者迷,掉入屁股决定脑袋的陷阱,如果当时我对领导的回答是狐疑的,那么,现在想来,我相信其是坦诚的。

2016年以后,手游行业逐渐成为了几个寡头的后花园,手游之都,一夜之间,倒下数百家游戏公司。而 t 公司在乔的带领下却离上市越来越近。当然,去年上市答辩临门一脚的时候遇到了挫折,导致 t 当前还未上市,乔应该还是有失落的。但无论是在 t 公司还是离开,我对乔在大方向上的判断以及具体的执行是认可的。而显然,有时候事情的落地不会让所有人都准备好,更不可能让所有员工都满意。

离职以后,虽然上了“黑名单”,但是一直关注乔的朋友圈。隐私关系,这里就不透露他朋友圈内容了。因为已经没有了分别心,看他的朋友圈反而觉得有了点意思:一个财务自由、公司健康运转(至少看起来是)的CEO,勤奋、聪明、好学,时不时还能分享一些有趣的体验和见闻,脾气可能不算好,但是并不让人生厌。对了,离职最后一天的最后一个小时,还听了他的《穷查理宝典》读书分享会,印象中,那个分享会还是要买门票才能去听的。

这两年,自己也在认知上不断的刷新和挑战自己。虽然成长背景、认知路径完全不一样,但是在很多关键问题的认知和判断上,跟乔越来越相似。但是,有一点显著不同,乔能够支配的资源远不是我辈可及,因此,很多时候不仅仅是看其人,也在看他所做的事情来验证自己的思考和判断。

什么?你说你想听乔的花边新闻?算了吧,花边只是浪费你我的时间,人都是多元和复杂的,一个人哪有什么绝对的优点和缺点,关注他的特点就行了。

冯医生的氪金手术刀

坦率讲,我与冯医生并不算熟识。唯一的交流渠道截止目前为止也仅限于推特。但是,了解一个人有很多方法:如果是一个上推的人,你看看他过往的文字就可以了。

最开始关注冯医生是因为推友转发了其一例手术的总结。处于刻奇,关注了冯医生,也翻看了他历史 feed. 没看几分钟,我发现我应该找到了中国最有意思的外科医生(之一)。精湛的手术技艺经常被推友调侃为“冯医生到处给人割肾”;会给求助的推友一些中肯的诊疗建议,但是从来不懂装懂;喜欢摄影、电影、爱折腾网络,虽然非相关专业科班出身,但是逻辑和理解力极好,往往能在推友三言两语的线索中自我解决问题;有两个女儿,与我教育的观念非常契合,经常会分享一些非常具体的子女教育的实操和感悟;身在体制内,热爱自己的职业,同时也非常清楚边界和天花板,然后去贵州开了医院……

冯医生在体制内的时候,就是你能想象到的那种韩剧中才有的偶像医生:长得帅、专业能力突出、收入丰厚。前两条不需要解释,对于最后一条,在中国这么提一个医生容易引起误解,我这里稍微解释一下。冯医生能做到这样,并不是靠患者的红包,更不是跟医药代表勾结,而是因为其在行业的影响力和口碑,使得其有工资薪酬之外的收入,最典型的诸如可以在重庆片区可以开飞刀。而这些都是可以见阳光的。

冯医生大概年长我十岁,但是看他的文字,完全没有代沟,对新事物的认知和接受速度有过之无不及。有一段时间,冯医生摆弄医院进口的达芬奇机器人,遇到一个视频录制问题,然后在推特上求助。我不是这方面的专家,自然也就没有给不靠谱的答案,但是我顺着其他人的回答看了一下,冯医生最终用不到1000块采购的设备解决了该问题。要知道,冯医生旁边的医院解决这个问题可是花了20W+! 总听老一辈说知识改变命运,其实更多时候是见识和认知。冯医生只是一个医学博士,但是专业的训练对其影响是深远的,单凡你跟他对过话,你都能深刻感受到其背后的思考以及其透出的磁力,这种磁力有时候吸引到的是你的注意力和思考,有时候是他要寻找问题的答案。

今年年初,冯医生宣布自己辞职,前往贵州创业。我是创过业的人,深刻的明白创业所面临的问题和风险。不要误解我,我说的「深刻明白」并不是简单感慨“创业维艰,且行且珍惜”,而是我相对来说能更大概率判断其创业方向是否靠谱以及创业者不失败的概率。对于冯医生,从其宣布消息开始,我一直都在默默祝福他。并不是那种廉价的客套话。而是每次看他发布关于新医院建设的问题也好、困惑也好、求助也好,都有一众人提供以各种方式提供帮助、建议和支持。在看到冯医生在院长这个方向上迅速成长后,我也看到越来越多的人在询问能否加入新的医院。最有意思的是,冯医生周末会会重庆,一次请以前医院同事吃饭,结果,几乎整个科室都出来了……有时候,你甚至都没有跟这个人见过面,但是他的所作所为就是让你非常确信他要做的事情可以落地达成;有时候,一个人可能并没有强得那么绝对,但是他的见识领先了一步,做事上靠谱、nice,那么他大概率会成为那个被大家自然托起的人。

有时我跟妞儿讲,这个优秀的人其实就在成都旁边的重庆,得空的时候,也许我们可以找他一起吃顿火锅。

英伦归来的处女座赵教授

作为算是在天朝学术圈混迹过的人,对我朝科研的现状(计算机科学方向)是非常失望的。但是,你如果要说这个圈子没有优秀和认真做事的人,我是一百个不同意的。赵教授并不是我的导师,而是我的导师邀来做过一次学术报告的学者。因此,我与赵教授其实只有一面之缘。

那次交流,赵教授先是做了一个云计算相关的学术报告,由于时间比较充裕,后续自由讨论和交流了一些问题。我被赵教授吸引除了其丰硕的研究成果,还有其对时政的敢怒敢言。而这种敢怒敢言并不是浅薄的愤青,而是实际去参政议政。前两年,赵教授拿到了广东省的五一劳动奖章和五四杰出青年,我知道这不是虚妄,而是实至名归。广东省的数字化建设和政务水平能够领先国内其他地区,以赵教授为代表的这一群人的努力是分不开的。

赵教授是我认识的时间管理做得最好的人。工作上,其在广东最好的两所高校任职,同时积极参政,还是三个孩子的父亲。但是,我发现其实赵教授从来都是举重若轻。什么抱怨、工作家庭矛盾,不存在的,赵教授还可以做更多的事情!而能做到这样,而且在每个方面都游刃有余,除了基本的聪明以外,其实是其经常自嘲的那种处女座疯子版的严格与认真。我没有看到赵教授有过一个完整的周末,也没看到过其晚上不工作。经常看到的是,以小时为单位,在学校、实验室、家、机场、会场、体育馆之间快速的切换。我们经常说,生命的长度是一定的,但是可以选择宽度。我只能说,同学,你还是太年轻了,可能你选择出来的那点宽度比别人的地下室都狭窄。

如果你有机会去广东最好的高校求学,报考的也是计算机方向的专业,并且你看到一个赵姓的教授还有名额,并且认为自己也有变得优秀的潜质的话,毫无保留的推荐你选赵教授。


每当我跟妞儿讲,遇到优秀的人的时候,我内心的喜悦和对对方的喜爱是难以言说的时候,妞儿都会默默的扔下一句“你又没他们优秀”,然后决绝而去😂。要说认识这些自己欣赏的人完全没有功利心,那是不客观的。渐渐地,认识和接触的人多了,放平了心态,毫无分别心的看他们的时候,总能发现这个自己欣赏的群体的一些共性:

  • 独立思考构建的独一无二的认知。这种认知千差万别,你根本不用指望你能遇到一个跟你认知一样的人。识别出你们认知能共振的频段,珍惜交流的机会和质量即可。
  • 清晰的逻辑和极强的理解力。跟行业以及这个人的出生背景没有关系,直观感受就是他能够把他那个领域的问题很快跟你讲明白,同时他也能在很短时间内,提出挑战你自己领域的问题。
  • 严格的逻辑自恰。你也许有很多结论和判断与其是相反的,但是他一定会告诉你得出这个结论的原因和推理依据。
  • 极强的时间观念和严格的时间管理执行。其实生命的长度一样是骗人的,因为单位时间的时间运转效率差异实在是太大了。
  • 演讲力和号召力。不是政客那种带煽动和目的性太强的演讲号召。而是,因为内心有所表达,自然而然的会站到演讲台那个位置。而这种演讲往往其实没有功利心,反而可以被他人托举。
  • 喜欢阅读和写作。世界上为数不多的只有好处没有坏处的事,在这群人身上体现的尤其明显。我并不反感小资,但要说明的是,小资的阅读和写作是不在这个范畴的。
  • 好奇且富有同情心。对这个世界不敏感的人,难以有发自内心的同情心。

这个世界很大,光鲜的皮囊多,有趣的灵魂少;如果你遇到一个,请感谢时间的邂逅。

Go 中如何准确地判断和识别各种网络错误

Go 自带的网络标准库可能让很多第一次使用它的人感慨,这个库让网络编程的门槛低到了令人发指的地步。然而,封装层次与开发人员的可控性往往是矛盾的。Go 的网络库封装程度算是一个不错的折衷,绝大部分时候,我们只需要调用 Dial, Read, Write Close 几个基本操作就可以了。

但是,网络是复杂的。我们有时候需要细致的处理网络中的各种错误,根据不同的错误进行不同的处理。比如我们遇到一个网络错误时,需要区分这个错误是因为无法解析 host ip, 还是 TCP 无法建立连接,亦或是读写超时。一开始的时候,我们的写法可能是这样的:

    errString := err.Error()
    fmt.Println(errString)
    switch {
    case strings.Contains(errString, "timeout"):
        fmt.Println("Timeout")
    case strings.Contains(errString, "no such host"):
        fmt.Println("Unknown host")
    case strings.Contains(errString, "connection refused"):
        fmt.Println("Connection refused")
    default:
        fmt.Printf("Unknown error:%s", errString)
    }

这种根据错误信息进行字符串匹配进行判断的方法有非常明显的局限性:该错误信息依赖于操作系统,不同的操作系统对于同一错误返回的字符串信息可能是不同的。因此,这种判断网络错误类型的方法是不可靠的。那么有没有一种准确而可靠的判断各种网络错误的方式呢?答案是肯定的。

我们知道在 Go 中,error 是一个内建的 interface 类型:

type error interface {
        Error() string
}

要准确判断不同的错误类型,我们只需要类型断言出其错误类型即可。

在 Go 的网络标准库中,错误类型被统一封装为 net.Errorinterface 类型:

type Error interface {
        error
        Timeout() bool   // Is the error a timeout?
        Temporary() bool // Is the error temporary?
}

net.Error 类型的具体 concrete 类型又被封装为 net.OpError 类型:

type OpError struct {
        // Op is the operation which caused the error, such as
        // "dial", "read" or "write".
        Op string

        // Net is the network type on which this error occurred,
        // such as "tcp" or "udp6".
        Net string

        // For operations involving a remote network connection, like
        // Dial, Read, or Write, Source is the corresponding local
        // network address.
        Source Addr

        // Addr is the network address for which this error occurred.
        // For local operations, like Listen or SetDeadline, Addr is
        // the address of the local endpoint being manipulated.
        // For operations involving a remote network connection, like
        // Dial, Read, or Write, Addr is the remote address of that
        // connection.
        Addr Addr

        // Err is the error that occurred during the operation.
        Err error
}

其中,net.OpError.Err 可能是以下几种类型:

*os.SyscallError 错误比较特殊,与具体操作系统调用有关:

type SyscallError struct {
        Syscall string
        Err     error
}

对于我们关心的网络错误,SyscallError.Err 一般为 sys.Errno 类型,与网络错误相关的常用值有:

  • syscall.ECONNREFUSED
  • syscall.ETIMEDOUT

看到这里,你可能忍不住要吐槽 Go 这种错误嵌套处理了,事实上,官方也意识到了这种错误处理的问题,在 Go 2中,可能会出现新的错误和异常处理方式,可以参见 GopherChina 2018 keynote 点评: RETHINKING ERRORS FOR GO 2.

当前阶段,我们依然要直面这种错误处理方式。为了方便大家理解 Go 网络标准库中处理错误的方式,我们把上面的错误嵌套整理了一张关系图:

明白了网络标准库中处理错误的逻辑,判断和识别各种类型的网络错误就非常简单了:对网络错误进行类型断言。以我们团队主要关心的 DNS 解析错误、TCP 无法建立连接、读写超时为例,判断逻辑可以是这样:

func isCaredNetError(err error) bool {
    netErr, ok := err.(net.Error)
    if !ok {
        return false
    }

    if netErr.Timeout() {
        log.Println("timeout")
        return true
    }

    opErr, ok := netErr.(*net.OpError)
    if !ok {
        return false
    }

    switch t := opErr.Err.(type) {
    case *net.DNSError:
        log.Printf("net.DNSError:%+v", t)
        return true
    case *os.SyscallError:
        log.Printf("os.SyscallError:%+v", t)
        if errno, ok := t.Err.(syscall.Errno); ok {
            switch errno {
            case syscall.ECONNREFUSED:
                log.Println("connect refused")
                return true
            case syscall.ETIMEDOUT:
                log.Println("timeout")
                return true
            }
        }
    }

    return false
}

这种错误判定方式除了能解决最开始提到的可靠性和准确性问题,也具有良好的普适性。即基于 net 的其他标准库,如 net/http 也支持这种错误判断方式。

扩展阅读

那些产品设计中的小惊喜

虽然技术出身,但是日常工作中经常需要单独的设计一些产品的原型,因此,需要对产品有一些感觉。

你也许被《人人都是产品经理》“荼毒”过,不用悲伤,我也是;你也许跟我一样技术出身,习惯了从技术角度看功能和需求,对产品和业务比较麻木,不要心急,我也是。你也许无数次的跟产品经理争论这个功能的合理性和必要性,谁也说服不了谁,最后你还是做了这个功能,仅仅是“厌恶”了跟产品无意义的浪费时间,没有关系,我也是。

然而,你要知道,大多数时候我们要做的产品设计其实都被前辈验证和解决过,是存在最佳实践的,也是可以从其他产品习得的。这种习得可能是一个特定的产品实现方式,但更多的是产品设计的思考和思路。这种习得,产品经理的整套方法论并不是必要条件,只需要你在使用产品的时候有意识的培养发现问题的敏感性和好奇心。

这里,我先把这几天使用产品过程中看到和体会到的一些产品设计中有意思的「小惊喜」整理一下,以后会不定期更新,争取能形成一个系列。

登录页面:简单的功能比你想象的更难更重要

随着 OAuth 以及开放平台的发展,国内绝大部分产品都支持微信、微博、QQ等多种社交账号的登录方式。这类登录方式不仅可以降低用户登录/注册的心里决策和输入成本,还能够从技术上简化整个账号系统的设计。因此,除了阿里和腾讯自成一体的公司产品,绝大多数产品都会在第一时间支持这类登录方式。然而,把这件事情做好的产品却寥寥无几。

以国内技术社区 segmentfault 为例,很多产品的社交账号登录页面可能是这样的:

从功能层面看,支持的登录方式挺多,把使用频率高的登录方式放在前面,这都没有问题。但是,我们的用户是健忘也是“无情”的。如果因为某种原因(APP更新、网络异常、更换手机等),用户需要重新登录,当用户再次看到这个页面的时候,是比较抓狂的:因为“登录”功能的使用频率很低,用户有很大概率不记得自己当初是以什么方式登录进来的;于是用户只能一个一个的去尝试不同社交账号登录方式来判断自己以前的账号是怎么登录的(这样做唯一能想到的好处就是注册用户数会提高,提前完成 KPI ……)。即使用户粘性高如微信,你去问问身边的朋友,他们的微信是手机号登录还是QQ登录,还是微信号登录,大部分人是搞不清楚的。

几天前用喜马拉雅听《晓说》,因为前一天晚上更新过APP,登录状态被踢了出来(这是个很糟的体验),尝试重新登录:

左下角提示微信为上次登录方式,这让我有了一点惊喜的感觉!

这是最佳的实践方式吗?私以为还可以再进一步:

之所以更加推荐这种将用户上次登录的头像和昵称显示出来的方式,不是因为这是东家咕咚APP采用的方式,而是因为,1)图片的阅读或者说注意力效率是远高于文字的;2)关系亲近的人之间可能会共用设备,显示头像和昵称有助于提高账号和登录方式判定的准确率。

在很多人眼里,登录页面这些改进太过于“鸡毛蒜皮”。但是如果你们的APP在登录页面的各个环节都有埋点的话,你也对这些数据足够熟悉的话,你会发现这些微不足道的改进对用户转化率的影响比你想象的重要得多。

说起转化率,使用社交账号登录一个非常常见也是非常糟糕的设计是:社交账号登录后,要求用户绑定手机/邮箱并设定密码。我能理解绑定手机号在我朝当前实名制政策下的无奈,但是大部分业务其实是不需要强制绑定手机号的。如果你是担心太过于依赖微信,要求用户必须有独立的登录用户民和密码,你应该想想你是不是太把自己当回事了?大部分情况下,我遇到这种社交账号登录后要求用户绑定手机和邮箱的服务,都会默默问候一个“产品13B”,然后直接关闭页面。

懂场景的音乐 APP

在听觉上,我应该算是典型的木耳。但是偏偏有喜欢在开车的时候听音乐。以前一直用豆瓣 FM, 歌曲推荐做的真心赞。但是豆瓣 FM 登录模块实在太渣,会因为各种原因把我从登录状态踢出来要求重新登录,老哥,我在开车呢,这样真的好吗?几经辗转,一次出行的时候,偶然打开了虾米音乐,因为连接了车载蓝牙,判断我是要开车听音乐,询问我是否进入车载模式:

进入车载模式以后,界面就变成跟老年手机一样,按钮巨大,按键也只有简单的几个上一曲,下一曲,暂停。心里默默念了一句: MMP, 这正是我想要的!

还没听完一首歌,又发现了一个小惊喜:

虾米把显示作者信息的地方用来显示歌曲的单词了!很Low是不是?是!很解决问题是不是?当然是!以后在车里想哼两句的时候终于不用因为不知道(不是不记得哟)歌词而随机脑补了。我知道很多技术背景的同学可能会对这种实现方式嗤之以鼻,但是以我对汽车软件行业平均水平的了解和自己折腾这台车歌词显示的经历看,这就是通用性最好、成本最低的方案!

坦率讲,虾米最主要的使用场景肯定不是车载,但是,透过这两个细节,我还是能够非常清晰的感受到虾米的产品在做音乐类 APP 是对场景的细致、全面的思考和实践。我们常常说一个功能或产品好用不好用,这其实是比较抽象和模糊的,如果你想找到具体的问题和原因,回到具体的场景和交互上,你一定能发现一些有趣的问题,同时给用户带来惊喜。

微信悬浮窗:悬浮的内容,流逝的时间

微信在不久前迎来了它的年度更新,其中最为大家津津乐道的一点就是悬浮窗设计:

但凡是常用微信进行阅读的同学,都能深刻的体会阅读文章与聊天消息之间切换的痛苦。悬浮窗一出,很多人大呼痛快。

使用一段时间后,发现了一个细节,随着悬浮时间的变长,悬浮的图标会逐渐变红,最终变成全红。有人说,悬浮窗是微信拯救不断被抖音等APP吞噬的APP使用时间所祭出的武器,此言不虚,但我想也一定有产品对提供更加良好的阅读体验的细致入微的思考和设计,毕竟,大家都是成年人了,「稍后阅读」往往就变成了「永远不读」。另一方面,我也比较悲观的认为,碎片化阅读其实是有非常明显的局限和天花板的,悬浮窗能做的已经接近这个极限。如果你真的是一个重度的微信公众号订阅者,悬浮窗是解决不了你的问题的,你应该关注一下订阅号展示形式的变化。

验证码繁与简

小区楼下有两个自动存取货柜,一般没人在家的时候,我都喜欢让快递老哥帮我把快递放在货柜中。回来的时候,凭验证码提取快递。一家是已经被中国邮政收编的速递易,它的验证码是这样的:

一家是顺丰家的丰巢,它的验证码是这样的:

都是6位验证码,不同的是前者使用的书“数字+字母”组合,后者只使用了数字。前者应该更加符合工程师思维:验证码空间要足够大,这样才能减少碰撞的概率,降低安全风险。但是,我倒觉得后者其实对验证码的认识更加深刻:

  1. 验证码是需要人工输入的,输入方式越简单成本越低。打一个不恰当的对比,前者需要用户会标准键盘输入,后者只需要用户知道如何打电话就够了。“会标准键盘输入”这个要求很过分吗?对你也许都不值一提,但是你要知道小区很多大爷大妈连手机上的T9输入法都不会用,只会手写输入,你要他会基本的标准键盘输入,显然是对你的用户群不够了解。
  2. 绝大部分用户短时间记忆一串数字是经过训练的,这种训练贯穿我们的小学数学教育以及功能机时代的“背电话号码训练”。因此,对于喜欢晚上出来遛弯取快递的同学来说,他们是可以看一眼验证码,然后放心的不带手机去取货。而背诵数字+字母组合,对很多人来说几乎就是不可完成的任务。
  3. 部分数字和字母字符不易区分,引入额外的错误率。典型字符如数字“1”和字母“I”, 数字“0”和字母“O”。
  4. 货柜的安全问题其实不在验证码。这个不方便细说,可以讲的是,如果你推演一下如何非正常手段获取货柜的的货物,你最后推演出来的方法一定不是傻乎乎的到带有好几个摄像头的货柜前去试验证码。

在验证码这个问题上,并不是说丰巢做的多好,而是想说速递易实在做得太烂:产品上的很多问题发展到今天已经是被很好的解决了,如果想在一些常用的产品设计上创新,请一定思考清楚这个「改变」是仅仅为了不同,还是因为当前设计存在很具体的问题。

浏览器地址栏存在多年的 bug

相信绝大部分人都注意到我们使用的浏览器地址栏是可以显示中文的:

但是,较真的工程师会告诉你:URL 地址的合法字符是 ASCII 字符的子集,是不支持中文的。也许浏览器地址栏显示中文是一个 bug?

虽然,平日里我是不太支持研发同学说 “这不是bug, 这是feature”,但是,这一次,我得说这的确是浏览器的一个 feature: 用户毕竟不是工程师,对于他们来讲,他们不关心也不在乎地址栏上面的字符是否经过 urlencode, 地址栏提供给他们的信息越直接越好。从这个逻辑出发,我们就不难理解地址栏中的安全绿色小锁以及直接显示中文了。当然,为了确保技术上的正确性,你通过 Chrome 地址栏复制的和开发者工具上看到的 URL 地址其实是经过 urlencode 过的:

Go 中一个非典型不加锁读写变量案例分析

前段时间在 v2 看到一个关于并发读写变量的问题:go 一个线程写, 另外一个线程读, 为什么不能保证最终一致性。帖子中给出的例子非常简单(稍作修改)main.go

package main

import (
    "fmt"
    "runtime"
    "time"
)

var i = 0

func main() {
    runtime.GOMAXPROCS(2)
    go func() {
        for {
            fmt.Println("i am here", i)
            time.Sleep(time.Second)
        }
    }()
    for {
        i += 1
    }
}

既然是问题贴,直接运行的结果应该是出乎大多数人预料的:

╰─➤  go run main.go                                                                                                                                     1 ↵
i am here 0
i am here 0
i am here 0
i am here 0
i am here 0
i am here 0
...

帖子的回复比较多,涉及的信息量相对杂乱,爬完楼反而感觉没有看懂。这里就不卖关子,直接给出脱水后的结论:出现上面结果的原因是 go 的编译器把代码 i 自加 1 的 for 循环优化掉了。要验证这一点也很简单,我们使用 go tool objdump -s 'main\.main' main 查看编译出的二进制可执行文件的汇编代码:

╰─➤  go tool objdump -s 'main\.main' main
TEXT main.main(SB) /Users/liudanking/code/golang/gopath/src/test/main.go
  main.go:11        0x108de60       65488b0c25a0080000  MOVQ GS:0x8a0, CX
  main.go:11        0x108de69       483b6110        CMPQ 0x10(CX), SP
  main.go:11        0x108de6d       7635            JBE 0x108dea4
  main.go:11        0x108de6f       4883ec18        SUBQ $0x18, SP
  main.go:11        0x108de73       48896c2410      MOVQ BP, 0x10(SP)
  main.go:11        0x108de78       488d6c2410      LEAQ 0x10(SP), BP
  main.go:12        0x108de7d       48c7042402000000    MOVQ $0x2, 0(SP)
  main.go:12        0x108de85       e8366bf7ff      CALL runtime.GOMAXPROCS(SB)
  main.go:13        0x108de8a       c7042400000000      MOVL $0x0, 0(SP)
  main.go:13        0x108de91       488d05187f0300      LEAQ go.func.*+115(SB), AX
  main.go:13        0x108de98       4889442408      MOVQ AX, 0x8(SP)
  main.go:13        0x108de9d       e8fe13faff      CALL runtime.newproc(SB)
  main.go:20        0x108dea2       ebfe            JMP 0x108dea2
  main.go:11        0x108dea4       e8c7dffbff      CALL runtime.morestack_noctxt(SB)
  main.go:11        0x108dea9       ebb5            JMP main.main(SB)
  :-1           0x108deab       cc          INT $0x3
  :-1           0x108deac       cc          INT $0x3
  :-1           0x108dead       cc          INT $0x3
  :-1           0x108deae       cc          INT $0x3
  :-1           0x108deaf       cc          INT $0x3

TEXT main.main.func1(SB) /Users/liudanking/code/golang/gopath/src/test/main.go
  main.go:13        0x108deb0       65488b0c25a0080000  MOVQ GS:0x8a0, CX
  main.go:13        0x108deb9       483b6110        CMPQ 0x10(CX), SP
  main.go:13        0x108debd       0f8695000000        JBE 0x108df58
  main.go:13        0x108dec3       4883ec58        SUBQ $0x58, SP
  main.go:13        0x108dec7       48896c2450      MOVQ BP, 0x50(SP)
  main.go:13        0x108decc       488d6c2450      LEAQ 0x50(SP), BP
  main.go:15        0x108ded1       0f57c0          XORPS X0, X0
  main.go:15        0x108ded4       0f11442430      MOVUPS X0, 0x30(SP)
  main.go:15        0x108ded9       0f11442440      MOVUPS X0, 0x40(SP)
  main.go:15        0x108dede       488d059b020100      LEAQ runtime.types+65664(SB), AX
  main.go:15        0x108dee5       4889442430      MOVQ AX, 0x30(SP)
  main.go:15        0x108deea       488d0d0f2d0400      LEAQ main.statictmp_0(SB), CX
  main.go:15        0x108def1       48894c2438      MOVQ CX, 0x38(SP)
  main.go:15        0x108def6       488d1583fb0000      LEAQ runtime.types+63872(SB), DX
  main.go:15        0x108defd       48891424        MOVQ DX, 0(SP)
  main.go:15        0x108df01       488d1d107c0c00      LEAQ main.i(SB), BX
  main.go:15        0x108df08       48895c2408      MOVQ BX, 0x8(SP)
  main.go:15        0x108df0d       e84eddf7ff      CALL runtime.convT2E64(SB)
  main.go:15        0x108df12       488b442410      MOVQ 0x10(SP), AX
  main.go:15        0x108df17       488b4c2418      MOVQ 0x18(SP), CX
  main.go:15        0x108df1c       4889442440      MOVQ AX, 0x40(SP)
  main.go:15        0x108df21       48894c2448      MOVQ CX, 0x48(SP)
  main.go:15        0x108df26       488d442430      LEAQ 0x30(SP), AX
  main.go:15        0x108df2b       48890424        MOVQ AX, 0(SP)
  main.go:15        0x108df2f       48c744240802000000  MOVQ $0x2, 0x8(SP)
  main.go:15        0x108df38       48c744241002000000  MOVQ $0x2, 0x10(SP)
  main.go:15        0x108df41       e85a9dffff      CALL fmt.Println(SB)
  main.go:16        0x108df46       48c7042400ca9a3b    MOVQ $0x3b9aca00, 0(SP)
  main.go:16        0x108df4e       e87d27fbff      CALL time.Sleep(SB)
  main.go:15        0x108df53       e979ffffff      JMP 0x108ded1
  main.go:13        0x108df58       e813dffbff      CALL runtime.morestack_noctxt(SB)
  main.go:13        0x108df5d       e94effffff      JMP main.main.func1(SB)
  :-1           0x108df62       cc          INT $0x3
  :-1           0x108df63       cc          INT $0x3
  :-1           0x108df64       cc          INT $0x3
  :-1           0x108df65       cc          INT $0x3
  :-1           0x108df66       cc          INT $0x3
  :-1           0x108df67       cc          INT $0x3
  :-1           0x108df68       cc          INT $0x3
  :-1           0x108df69       cc          INT $0x3
  :-1           0x108df6a       cc          INT $0x3
  :-1           0x108df6b       cc          INT $0x3
  :-1           0x108df6c       cc          INT $0x3
  :-1           0x108df6d       cc          INT $0x3
  :-1           0x108df6e       cc          INT $0x3
  :-1           0x108df6f       cc          INT $0x3

显然,

    for {
        i += 1
    }

直接被优化没了。我们可以在语句 i += 1 添加一个其他语句来避免被优化掉:

    for {
        i += 1
        time.Sleep(time.Nanosecond)
    }

重新运行程序,运行结果“看似正确”了:

╰─➤  go run main.go                                                                                                                                     1 ↵
i am here 30
i am here 1806937
i am here 3853635
i am here 5485251
...

显然,如此修改之后,这段代码并非真正正确。因为变量 i 存在并发读写,即 data race 的问题。而 data race 场景下,go 的行为是未知的。程序员最讨厌的几件事中,不确定性必居其一。因此,一步小心写出 data race 的bug,调试起来是不太开心的。这里的例子因为只有几行代码,我们可以目测定位问题。如果代码规模比较大,我们可以借助 golang 工具链中的 -race 参数来排查该类问题:

╰─➤  go run -race main.go                                                                                                                               2 ↵
==================
WARNING: DATA RACE
Read at 0x0000011d4318 by goroutine 6:
  runtime.convT2E64()
      /usr/local/go/src/runtime/iface.go:335 +0x0
  main.main.func1()
      /Users/liudanking/code/golang/gopath/src/test/main.go:15 +0x7d

Previous write at 0x0000011d4318 by main goroutine:
  main.main()
      /Users/liudanking/code/golang/gopath/src/test/main.go:20 +0x7f

Goroutine 6 (running) created at:
  main.main()
      /Users/liudanking/code/golang/gopath/src/test/main.go:13 +0x53
==================
i am here 1
i am here 558324
i am here 1075838

除了在 go run 上可以使用 -trace, 其他几个常用的golang工具链指令也支持这个参数:

$ go test -race mypkg    // to test the package
$ go run -race mysrc.go  // to run the source file
$ go build -race mycmd   // to build the command
$ go install -race mypkg // to install the package

需要说明的是, -trace 并不保证能够检查出程序中所有的 data race, 而检查出 data race 则必然存在。说起来比较绕,大家记住它跟布隆过滤器 (Bloom Filter) 的真值表是一样的就对了。

而要把最开始提到的代码改对,方法有很多,我们可以使用 The Go Memory Model 推荐的 sync 包中的读写锁即可:

package main

import (
    "fmt"
    "runtime"
    "sync"
    "time"
)

var i = 0

func main() {
    runtime.GOMAXPROCS(2)
    mtx := sync.RWMutex{}
    go func() {
        for {
            mtx.RLock()
            fmt.Println("i am here", i)
            mtx.RUnlock()
            time.Sleep(time.Second)
        }
    }()
    for {
        mtx.Lock()
        i += 1
        mtx.Unlock()
        time.Sleep(time.Nanosecond)
    }

扩展阅读

QUIC 存在 UDP 反射 DDoS 攻击漏洞吗?

今年年初,360信息安全部发布了一篇关于利用 UDP 反射 DDoS 的分析报告:Memcache UDP反射放大攻击技术分析。报告一出,引起了业界的普遍关注。根据文中所述,光是Qrator Labs 在 medium.com 上 批露的一次DDoS攻击看,其攻击流量峰值达到 480Gbps。而360信息安全团队本身也监测和确认有更大的攻击已经实际发生,只是未被公开报道。

而就在这个这个事件纰漏没多久,我把博客升级为支持基于 UDP 的 QUIC 协议来改善小站的访问体验:本站开启支持 QUIC 的方法与配置。本着小站没几人访问的蜜汁自信,当时也没太纠结 QUIC 是否也存在 UDP 反射漏洞。前几天,看到著名博主,阮一峰同学网站被 DDoS 攻击,心里咯噔一下:出来混迟早是要还的,还是填坑为安吧。

什么是 UDP 反射 DDoS 攻击

简单讲,就是攻击者利用IP网络不做真实源地址检查的“设计缺陷“,向提供基于 UDP 服务的服务器发送伪造源地址(一般为被攻击者的主机IP)的 UDP 报文请求,使得这些 UDP 报文的响应数据都会发送给被攻击者主机,这种攻击我们称之为 UDP 反射 DDoS 攻击。

之所以要通过被利用的服务器反射流量到被攻击的服务器,是因为被利用的服务器一般存在流量放大效应。即一个伪造IP的 UDP 请求发送到到被利用服务器后,被利用服务器会发送比请求更多的数据到被攻击者服务器。

被利用服务器输出流量与输入流量的比值我们称之为放大系数。这个系数与被利用服务器所提供的 UDP 服务有关。之前提到的利用 Memcache 漏洞的 DRDoS 攻击,可以获得稳定的 60000 倍放大系数。而我们日常使用的 DNS 则可以轻松的获得 50 倍的放大系数。

由放大系数反推,我们可以知道,如果一个 UDP 服务被利用以后,放大系数小于等于1的话,则不存在利用价值,因为这个时候,只从带宽流量方面考虑的话,还不如直接利用攻击主机对被攻击服务器进行攻击效率高。

QUIC 存在 UDP 反射攻击漏洞吗

按照蛤乎惯例,照顾猴急的同学,先给结论:可以。

QUIC 主要通过以下机制来解决该问题:

  1. 对于首次发起建立 QUIC 连接的客户端,服务端要求其初始化的 hello 数据包必须完全填充。这个包在 IPv4 下一般是 1370 字节,在 IPv6 下是 1350 字节。在 QUIC 协议中,服务器和客户端数据交互的基本单位是就是 UDP 数据包,而一个全填充的数据包已经达到了数据包大小的上限,因此服务器的响应数据包一定是小于等于这个 hello 数据包的。显然,放大系数小于等于1. 因此,新连接的建立没有反射利用的价值。
  2. 建立 QUIC 连接后,客户端发出的数据包就不会全填充了。这个时候,如果被 UDP 反射利用,放大系数是大于1的。因此, QUIC 引入了源地址token (source address token):在成功建立 QUIC 连接后,服务器会用发放一个源地址token给客户端,并要求客户端在后续的数据包中带上这个token;服务器只对源地址token有效的数据包进行处理。源地址token中一般包含客户端的源地址和服务器的时间。因此这是一个客户端证明其IP所有权的凭证。
  3. 由于源地址token可能会被网络中的攻击者嗅探收集,因此 QUIC 设计了一套源地址token的过期和刷新机制。另一方面,每次客户端发送的数据包如果都带上源地址token的话,不仅客户端流量大,服务器验证token也是额外的开销,使得协议延迟变高。因此 QUIC 协议允许客户端按照一个动态策略选择是否在数据包中夹带源地址token:服务器端收集和统计源地址的数据包,当统计到源地址数据包交互响应异常的数量超过阈值时,要求该源地址的客户端必须夹带源地址token, 对于无法提供合法源地址的token的请求进行 reject 处理。

扩展阅读

魔鬼在细节中:Base64 你可能不知道的几个细节

Base64 是我们常用的编码方式,广泛用于邮件编码、数据签名/数据校验编码以及HTML/XML复杂数据编码。这本来是一个花两分钟了解一下就无需关注的技术,但是最近线上遇到一个相关问题。于是重新梳理了一下 Base64, 发现了一些以前未曾注意到的细节,记录如下,希望对你也有帮助。

Base64 是什么?

Base64 是一种将二进制数据表示为可打印字符的编码方法。基本操作是将3个字节编码为4个 Base64 单元:3 * 8 bit = 4 * 6 bit. 这种编码方法常用于处理文本数据的场合,例如在 HTML/XML 中表示、传输、存储一些二进制数据(如数据签名、数据校验等)。Base64 编码后数据增长为原来的 4/3 ≈ 1.33 倍。相较于将二进制数据按照十六进制输出数据增长为原来2倍,Base64 更加节省空间。Base64 的标准是 RFC 4648,如果你不想直接阅读这个拗口啰嗦的RFC,可以继续往下看。

Base64 不是什么?

Base64 不是一种加密方式,因此它不提供任何安全特性。我们在论坛、个人博客中发现很多人使用 Base64 编码显示自己邮箱主要是避免被搜索引擎及其他批量化工具发现和索引。

Base64 编码结果是唯一的吗?

不是的。Base64 根据编码字典表不同以及是否 padding (使用=作为 padding 字符),对同一数据的编码结果可能不同。使用最多的字典表有两个:

                      Table 1: The Base 64 Alphabet

     Value Encoding  Value Encoding  Value Encoding  Value Encoding
         0 A            17 R            34 i            51 z
         1 B            18 S            35 j            52 0
         2 C            19 T            36 k            53 1
         3 D            20 U            37 l            54 2
         4 E            21 V            38 m            55 3
         5 F            22 W            39 n            56 4
         6 G            23 X            40 o            57 5
         7 H            24 Y            41 p            58 6
         8 I            25 Z            42 q            59 7
         9 J            26 a            43 r            60 8
        10 K            27 b            44 s            61 9
        11 L            28 c            45 t            62 +
        12 M            29 d            46 u            63 /
        13 N            30 e            47 v
        14 O            31 f            48 w         (pad) =
        15 P            32 g            49 x
        16 Q            33 h            50 y

         Table 2: The "URL and Filename safe" Base 64 Alphabet

     Value Encoding  Value Encoding  Value Encoding  Value Encoding
         0 A            17 R            34 i            51 z
         1 B            18 S            35 j            52 0
         2 C            19 T            36 k            53 1
         3 D            20 U            37 l            54 2
         4 E            21 V            38 m            55 3
         5 F            22 W            39 n            56 4
         6 G            23 X            40 o            57 5
         7 H            24 Y            41 p            58 6
         8 I            25 Z            42 q            59 7
         9 J            26 a            43 r            60 8
        10 K            27 b            44 s            61 9
        11 L            28 c            45 t            62 - (minus)
        12 M            29 d            46 u            63 _
        13 N            30 e            47 v           (underline)
        14 O            31 f            48 w
        15 P            32 g            49 x
        16 Q            33 h            50 y         (pad) =

这两个字典表的区别主要是 6263 使用的字符不同(我们将这两个字符称为特殊字符)。因此,对于同一数据最多可能有 2 * 2 = 4 种编码结果。以 0x0F0xF1(2 bytes)为例,有以下4种编码结果:

  • 字典表1 + padding: D/E=
  • 字典表1 + nopadding: D/E
  • 字典表2 + padding: D_E=
  • 字典表2 + nopadding: D_E

这种一个数据有多个编码结果的情况,往往会给我们解码带来困扰。因此,在使用 Base64 的场景中,务必在文档中注明你是使用的哪一个字典表以及是否需要 padding. 当然,国内环境对文档普遍不够重视,在这么小的技术点上写如此细致是不敢奢望的,有一条有用的经验是:在没有特殊说明的情况下,技术文档中的 Base64 一般是指 字典表1 + padding.

Base64 是 url/filename safe 的吗?

如上所诉,我们默认的 Base64 编码使用的是字典表1,而这个字典表中的字符 +/ 无论是在url还是文件系统中都是特殊字符。因此,基于字典表1的Base64编码不是 url/filename safe 的,不能将该 Base64 编码直接与url拼接或用来命名文件。基于字典表2的 Base64 编码是 url/filename safe 的。但它不是我们大部分编程语言的默认字典,因此,你如果选择这个字典进行 Base64 编码,在解码时也选择该字典。否则你有很大概率会遇到部分数据能解码,部分数据不能解码的问题。

Base64 可以自定义特殊字符吗?

字典表2使用了不一样的 6263 特殊字符以实现 url/filename safe. 但这可能无法满足所有应用场景。因此根据 RFC, 你是可以自定义这两个特殊字符建立自己的字典表的。有一点需要注意,如果你使用了自定义字典表,那么请确保自己编码和解码使用的字典表是一致的。

Base64 编码结果中的等号(=)可以省略吗?是多余的设计吗?

可以省略,但不是多余的设计。

我们先看为何可以省略:

对于数据 A, 如果我们省略padding的等号,解码的时候我们从QQ是可以推断出来,原始数据长度必然是1 byte, 因此可以可以正确解码。数据 BC 同理。

既然 padding 的等号完全不影响解码,是否可以取消这个设计呢?答案是否定的。对于一些将多个Base64编码拼接在一起的场景,padding的等号可以标记一个 Base64 编码单元的边界,使得拼接后的 Base64 编码整体是可以无歧义正确解码的。如果省略等号,则无法保证无歧义性。我们看一个例子:

  • I Base64编码为 SQ (SQ== with padding)
  • AM Base64编码为 QU0 (QU0= with padding)
  • Daniel Base64编码为 RGFuaWVs (RGFuaWVs with padding)

如果使用省略等号的方式,拼接后的Base64编码是 SQQU0RGFuaWVs, 因为我们无法区分边界,我们只能对整个字符串进行解码,显然解码结果是不正确的。如果我们不省略等号,则拼接后的编码 SQ==QU0=RGFuaWVs 可以根据等号区分边界,然后分块正确解码。

扩展阅读

什么车最适合跑滴滴——数据化思维小记

背景

端午节回村里,发小问买个车跑滴滴应该选什么车。在发小眼里,跟互联网相关的,我应该都懂……但是,我也就是滴滴伪司机,2015年注册以来就跑过一单。我虽然也喜欢车,但是也深知车这东西到手就开始贬值,实实在在的负债。看着他手里几十万预算的拆迁款,回想一下平时跟他吹牛皮的聊天记录,感觉这家伙就是趁着端午想让我去他家说服叔叔们同意他买个 BMW 330 曜夜版。这个坑我怎么可能跳?

我跟他分析了N条跑滴滴一定是要选低油耗、养护成本低、贬值率低的车。但是始终说服不了他。尝试从网上搜了一下什么车适合跑滴滴,结果大概分三种,一种是明显的车托写的软文,直接pass。一种是凭自己主观感受推荐的车型,这种个人感情色彩太强烈,难以客观,容易好心办坏事。还有一种是给出了选车的方法,但是没有给出具体车型,例如:

你只要多做几次快车,就会发现什么车最多。

多做几次车,和司机师傅聊聊,就知道什么车合适了。

出处:大学毕业,想专职跑滴滴,什么车比较合适?

第三种类型的信息是最有用的,毕竟授之以鱼不如授之以渔。按照上面的思路,无非就是需要搜集点数据,然后得出结论。正在苦恼数据的时候,想起我经常使用滴滴加油薅羊毛,里面可以看到滴滴车主的实时订单和近30日回头客的加油统计,数据简直就是现成的。于是,我决定用实际数据给发小上一课。

如何获取数据

我们要获取的数据位于 滴滴车主 APP -> 滴滴加油 页面:

页面中,我们可以看到滴滴加油站的实时订单和30日回头客两个非常有用的数据。数据获取阶段,我们的任务就是把这两个数据抓下来保存到本地。

这个页面是一个web页面,但是会验证动态token。考虑到我们只是简单的收集一点数据,因此不想正面逆向token的生成方式,仅仅通过一个小工具进行中间人攻击的方式就可以收集数据:

这个小工具 didi-car-rank 放在了github上,感兴趣的同学可以安装玩一玩。

如何解读数据

我们假设滴滴司机中跑得最勤快、数量最多的车型是最适合跑滴滴的车型。而我们采集的数据只有两项:实时订单和30日回头客。因此,简单统计一下我们采样的实时订单和和30日回头客加油次数即可。以成都为例,统计结果如下:

车型订单数量排名 统计了我们获取到的成都市各个加油站实时加油订单中各个车型的数量。它反映了车型的车型保有量,准确讲是车型在滴滴车主中的保有量。一般来说,保有量越大的车,其维修成本越低,保值率越高,当然这不绝对,相关性大抵如此。由于我们采集实时订单的时间不长,因此统计中的绝对数字不是那么重要,主要关注相对值。

车型加油积分排行 统计了成都市各个加油站近30天滴滴加油次数前50名的各个车型次数(1次=1积分)。它反映了滴滴专职司机(绝大部分)使用的车型。有了积分以后,用积分除以上面的订单数量,就可以得到每个车型的平均积分。这个指标在一定程度上反映了滴滴的冠军车型。

滴滴分为快车和专车。其中,专车基本被凯美瑞、天籁、帕萨特三分天下,因此没什么可分析的,看个人喜好买就对了。我们主要看一下快车车型。按照上面的思路,我们是否该选快车中平均得分最高的长安逸动呢?答案是否定的,因为这款车型的加油订单数量只有17(图中未入榜),也就是说长安逸动的保有量并不大,很可能是因为车价便宜,而被少数人用来专职跑滴滴拉高了平均分,选择这种车型后期的保值率会有较大问题。类似的,也可以排除平均分为45.33的别克凯越。如果不介意保值率,准备把这个车开滴滴开到报废,倒是可以考虑这样的车型。

我们尽量考虑实时订单数加油积分平均积分都在top 10的车型。因为这可以相对全面的放映车型在油耗、养护成本、保值率、可靠性等方面的实际认可程度。丰田卡罗拉、大众朗逸、大众新捷达、斯柯达明锐、日产轩逸都是不错的选择。考虑到油耗是实际运营中的长期成本,且占比较高,给发下及其家人安利的了丰田卡罗拉双擎,一箱油跑1000KM不是梦。同时也成功破除了发小实现蓝天白云的小心思。希望下次回村里的时候他不会上来跟我干架,毕竟我也是良苦用心……

需要说明的是,上面的选择是成都地区一个相对合理的选择。对于其他城市,由于受地域政策(区域车企保护、限行、新能源扶持)的影响,这款车型可能并不适合你所在的城市。比如,根据我们抓取到的数据,我们发现在上海市最受滴滴司机青睐的车型是荣威550/e550和比亚迪秦,重庆最火的是长安逸动。

附录给出了国内热门城市的滴滴热门车型排名数据,可供参考。如果附录数据没有你的城市,你也可以使用小工具 didi-car-rank 自行抓取数据进行分析。

小结

在数字化如此发达的今天,数据就是资源。利用数据分析事物的相关性能在很大程度上辅助我们减少或消除不确定性,提高我们判断的准确性。所谓的数据指导运营背后的思路也是如此。同时也应该意识到,大部分时候我们获取的数据往往是含有噪音的。因此,要学会使用其他数据来佐证或剔除一些可疑的数据。做到大胆假设,小心求证。

数据的收集可以跟技术没有半毛钱关系。比如,如果我们不通过数据抓取也可以通过直接到加油站蹲点数车型的方式来获取数据。这个跟你要开一个奶茶店,去线下数人头、算人流、估流水是一样的。商业本质的东西其实一直没有大的改变,有时候甚至会让你觉得很low.

很多时候,人们凭经验估计的数据偏差是非常大的。比如,在抓取一个城市的加油站数据的时候,第一直觉是一个城市的加油站太多了,抓数据会不会累死(因为需要手指滑动来获取数据)。但是,实际发现,北京的滴滴加油站也才不过在3位数,上海因为一直在给滴滴这类网约车平台开罚单,只有区区十几个滴滴加油站。我们常常说一个好的产品经理要有清晰的思维来估计一个城市有多少个理发师,对于研发而言,这个数据化分析和思考的能力一样重要。因为它可能决定了你对系统关键部分的设计和选型。

其实,滴滴加油站的数据除了分析滴滴的热门车型,如果你是滴滴的竞争对手,是不是可以监控/分析/对比一下……(此处略去几个字);如果你是整车厂,是不是可以更加有的放矢呢?如果你是汽车后市场从业者,是不是看到了其他机会呢?数据本身是冰冷的,但是你的敏感性却可以使之发光发热。在这一点上,我还是一个没入门的初学者。共勉之。

附录:国内热门城市滴滴热门车型排名

北京市

车型订单数量排名:
+------+--------------+------------+
| 排名 |     车型     | 实时订单数 |
+------+--------------+------------+
|    1 | 大众朗逸     |        126 |
|    2 | 日产阳光     |        116 |
|    3 | 大众新捷达   |        113 |
|    4 | 大众帕萨特   |         97 |
|    5 | 日产天籁     |         89 |
|    6 | 日产轩逸     |         85 |
|    7 | 丰田凯美瑞   |         81 |
|    8 | 大众速腾     |         71 |
|    9 | 丰田卡罗拉   |         70 |
|   10 | 现代悦动     |         68 |
|   11 | 本田雅阁     |         68 |
|   12 | 大众宝来     |         65 |
|   13 | 起亚K2       |         64 |
|   14 | 现代朗动     |         62 |
|   15 | 大众新桑塔纳 |         50 |
|   16 | 马自达CX-5   |         50 |
|   17 | 大众迈腾     |         48 |
|   18 | 别克GL8      |         45 |
|   19 | 雪佛兰科鲁兹 |         43 |
|   20 | 起亚K3       |         43 |
+------+--------------+------------+

车型加油积分排名:
+------+--------------+----------+----------+
| 排名 |     车型     | 加油积分 | 平均积分 |
+------+--------------+----------+----------+
|    1 | 出租车       |    17804 | N/A      |
|    2 | 大众朗逸     |     6547 |    51.96 |
|    3 | 日产阳光     |     4305 |    37.11 |
|    4 | 现代悦动     |     2827 |    41.57 |
|    5 | 起亚K2       |     2672 |    41.75 |
|    6 | 日产轩逸     |     2628 |    30.92 |
|    7 | 现代朗动     |     2483 |    40.05 |
|    8 | 大众帕萨特   |     2309 |    23.80 |
|    9 | 丰田凯美瑞   |     2159 |    26.65 |
|   10 | 日产天籁     |     2131 |    23.94 |
|   11 | 雪佛兰科沃兹 |     1942 |    57.12 |
|   12 | 丰田卡罗拉   |     1855 |    26.50 |
|   13 | 大众新捷达   |     1809 |    16.01 |
|   14 | 雪佛兰科鲁兹 |     1806 |    42.00 |
|   15 | 大众宝来     |     1670 |    25.69 |
|   16 | 起亚K3       |     1584 |    36.84 |
|   17 | 本田雅阁     |     1387 |    20.40 |
|   18 | 丰田威驰     |     1255 |    33.03 |
|   19 | 别克凯越     |     1218 |    29.71 |
|   20 | 别克英朗     |     1206 |    70.94 |
+------+--------------+----------+----------+

上海市

车型订单数量排名:
+------+---------------+------------+
| 排名 |     车型      | 实时订单数 |
+------+---------------+------------+
|    1 | 比亚迪秦      |         37 |
|    2 | 荣威550       |         37 |
|    3 | 荣威e550      |         16 |
|    4 | 荣威ei6       |         13 |
|    5 | 别克GL8       |          9 |
|    6 | 别克英朗      |          8 |
|    7 | 日产轩逸      |          6 |
|    8 | 丰田卡罗拉    |          6 |
|    9 | 华晨华颂华颂7 |          6 |
|   10 | 斯柯达明锐    |          6 |
|   11 | 本田思域      |          5 |
|   12 | 荣威950       |          5 |
|   13 | 大众新桑塔纳  |          5 |
|   14 | 丰田雷凌      |          5 |
|   15 | 福特福克斯    |          4 |
|   16 | 大众帕萨特    |          4 |
|   17 | 日产天籁      |          4 |
|   18 | 荣威350       |          4 |
|   19 | 上汽G10       |          4 |
|   20 | 大众宝来      |          3 |
+------+---------------+------------+

车型加油积分排名:
+------+---------------+----------+----------+
| 排名 |     车型      | 加油积分 | 平均积分 |
+------+---------------+----------+----------+
|    1 | 荣威550       |     4668 |   126.16 |
|    2 | 比亚迪秦      |     1940 |    52.43 |
|    3 | 荣威e550      |     1930 |   120.62 |
|    4 | 荣威ei6       |     1178 |    90.62 |
|    5 | 华晨华颂华颂7 |      812 |   135.33 |
|    6 | 日产轩逸      |      687 |   114.50 |
|    7 | 别克GL8       |      377 |    41.89 |
|    8 | 荣威950       |      271 |    54.20 |
|    9 | 大众帕萨特    |      255 |    63.75 |
|   10 | 出租车        |      232 | N/A      |
|   11 | 大众朗逸      |      201 |    67.00 |
|   12 | 丰田卡罗拉    |      197 |    32.83 |
|   13 | 丰田凯美瑞    |      196 |    65.33 |
|   14 | 上汽G10       |      186 |    46.50 |
|   15 | 丰田雷凌      |      170 |    34.00 |
|   16 | 别克英朗      |      157 |    19.62 |
|   17 | 福特福克斯    |      128 |    32.00 |
|   18 | 荣威e950      |      125 |   125.00 |
|   19 | 别克君威      |      125 |    62.50 |
|   20 | 本田锋范      |      118 |    59.00 |
+------+---------------+----------+----------+

广州市

+------+--------------+------------+
| 排名 |     车型     | 实时订单数 |
+------+--------------+------------+
|    1 | 日产轩逸     |         88 |
|    2 | 丰田卡罗拉   |         79 |
|    3 | 比亚迪秦     |         77 |
|    4 | 日产逍客     |         47 |
|    5 | 丰田雷凌双擎 |         43 |
|    6 | 本田凌派     |         43 |
|    7 | 日产天籁     |         42 |
|    8 | 福特麦柯斯   |         42 |
|    9 | 丰田雷凌     |         41 |
|   10 | 捷豹XF       |         37 |
|   11 | 本田锋范     |         36 |
|   12 | 丰田凯美瑞   |         35 |
|   13 | 本田飞度     |         24 |
|   14 | 宝骏560      |         23 |
|   15 | 日产阳光     |         21 |
|   16 | 本田雅阁     |         20 |
|   17 | 丰田威驰     |         20 |
|   18 | 吉利帝豪     |         19 |
|   19 | 荣威950      |         19 |
|   20 | 别克英朗     |         18 |
+------+--------------+------------+


车型加油积分排名:
+------+--------------+----------+----------+
| 排名 |     车型     | 加油积分 | 平均积分 |
+------+--------------+----------+----------+
|    1 | 比亚迪秦     |     3702 |    48.08 |
|    2 | 日产轩逸     |     3465 |    39.38 |
|    3 | 出租车       |     2891 | N/A      |
|    4 | 丰田卡罗拉   |     2419 |    30.62 |
|    5 | 日产天籁     |     2294 |    54.62 |
|    6 | 本田凌派     |     1822 |    42.37 |
|    7 | 丰田凯美瑞   |     1311 |    37.46 |
|    8 | 丰田雷凌     |     1228 |    29.95 |
|    9 | 丰田雷凌双擎 |     1164 |    27.07 |
|   10 | 本田锋范     |      907 |    25.19 |
|   11 | 宝骏560      |      633 |    27.52 |
|   12 | 本田飞度     |      526 |    21.92 |
|   13 | 日产轩逸经典 |      519 |    51.90 |
|   14 | 本田雅阁     |      486 |    24.30 |
|   15 | 现代朗动     |      479 |    26.61 |
|   16 | 起亚K3       |      430 |    30.71 |
|   17 | 丰田威驰     |      418 |    20.90 |
|   18 | 本田思域     |      416 |    32.00 |
|   19 | 广汽传祺GS4  |      412 |    58.86 |
|   20 | 日产阳光     |      396 |    18.86 |
+------+--------------+----------+----------+

深圳市

车型订单数量排名:
+------+----------------+------------+
| 排名 |      车型      | 实时订单数 |
+------+----------------+------------+
|    1 | 丰田卡罗拉     |         92 |
|    2 | 日产轩逸       |         70 |
|    3 | 福特麦柯斯     |         39 |
|    4 | 日产逍客       |         38 |
|    5 | 比亚迪秦       |         37 |
|    6 | 日产天籁       |         27 |
|    7 | 现代朗动       |         25 |
|    8 | 捷豹XF         |         24 |
|    9 | 宝骏560        |         24 |
|   10 | 日产全新轩逸   |         22 |
|   11 | 丰田凯美瑞     |         22 |
|   12 | 丰田卡罗拉双擎 |         21 |
|   13 | 日产轩逸经典   |         20 |
|   14 | 本田凌派       |         19 |
|   15 | 起亚K3         |         18 |
|   16 | 大众朗逸       |         18 |
|   17 | 丰田威驰       |         17 |
|   18 | 本田雅阁       |         16 |
|   19 | 丰田雷凌       |         16 |
|   20 | 日产阳光       |         16 |
+------+----------------+------------+

车型加油积分排名:
+------+----------------+----------+----------+
| 排名 |      车型      | 加油积分 | 平均积分 |
+------+----------------+----------+----------+
|    1 | 日产轩逸       |     5569 |    79.56 |
|    2 | 丰田卡罗拉     |     4988 |    54.22 |
|    3 | 比亚迪秦       |     3269 |    88.35 |
|    4 | 丰田凯美瑞     |     1824 |    82.91 |
|    5 | 本田凌派       |     1790 |    94.21 |
|    6 | 日产天籁       |     1512 |    56.00 |
|    7 | 丰田雷凌       |     1360 |    85.00 |
|    8 | 大众朗逸       |     1342 |    74.56 |
|    9 | 日产轩逸经典   |     1266 |    63.30 |
|   10 | 荣威ei6        |     1221 |    81.40 |
|   11 | 宝骏560        |     1139 |    47.46 |
|   12 | 丰田威驰       |     1071 |    63.00 |
|   13 | 别克凯越       |      968 |    80.67 |
|   14 | 本田锋范       |      808 |    53.87 |
|   15 | 日产阳光       |      768 |    48.00 |
|   16 | 丰田卡罗拉双擎 |      716 |    34.10 |
|   17 | 本田雅阁       |      697 |    43.56 |
|   18 | 现代朗动       |      676 |    27.04 |
|   19 | 现代悦动       |      609 |    40.60 |
|   20 | 丰田雷凌双擎   |      572 |    71.50 |
+------+----------------+----------+----------+

杭州市

车型订单数量排名:
+------+--------------+------------+
| 排名 |     车型     | 实时订单数 |
+------+--------------+------------+
|    1 | 比亚迪秦     |         46 |
|    2 | 别克凯越     |         18 |
|    3 | 大众朗逸     |         14 |
|    4 | 日产轩逸     |         14 |
|    5 | 日产轩逸经典 |         13 |
|    6 | 本田雅阁     |         13 |
|    7 | 丰田卡罗拉   |         11 |
|    8 | 丰田雷凌     |         11 |
|    9 | 日产天籁     |         10 |
|   10 | 别克英朗     |          9 |
|   11 | 现代朗动     |          9 |
|   12 | 荣威950      |          9 |
|   13 | 现代领动     |          8 |
|   14 | 奇瑞艾瑞泽7e |          8 |
|   15 | 荣威ei6      |          8 |
|   16 | 荣威e950     |          7 |
|   17 | 马自达CX-5   |          7 |
|   18 | 现代悦动     |          7 |
|   19 | 宝马X6       |          7 |
|   20 | 雪佛兰科鲁兹 |          6 |
+------+--------------+------------+

车型加油积分排名:
+------+--------------+----------+----------+
| 排名 |     车型     | 加油积分 | 平均积分 |
+------+--------------+----------+----------+
|    1 | 出租车       |     4768 | N/A      |
|    2 | 比亚迪秦     |     3290 |    71.52 |
|    3 | 日产轩逸     |     1345 |    96.07 |
|    4 | 荣威ei6      |      824 |   103.00 |
|    5 | 奇瑞艾瑞泽7e |      631 |    78.88 |
|    6 | 日产轩逸经典 |      593 |    45.62 |
|    7 | 现代朗动     |      573 |    63.67 |
|    8 | 丰田雷凌     |      521 |    47.36 |
|    9 | 荣威e950     |      443 |    63.29 |
|   10 | 丰田卡罗拉   |      424 |    38.55 |
|   11 | 别克凯越     |      419 |    23.28 |
|   12 | 大众朗逸     |      416 |    29.71 |
|   13 | 现代悦动     |      313 |    44.71 |
|   14 | 福特福克斯   |      307 |    51.17 |
|   15 | 雪佛兰科鲁兹 |      301 |    50.17 |
|   16 | 现代领动     |      289 |    36.12 |
|   17 | 起亚K3       |      273 |   136.50 |
|   18 | 本田飞度     |      272 | N/A      |
|   19 | 起亚K2       |      260 |    86.67 |
|   20 | 吉利帝豪     |      259 |    86.33 |
+------+--------------+----------+----------+

成都市

车型订单数量排名:
+------+--------------+------------+
| 排名 |     车型     | 实时订单数 |
+------+--------------+------------+
|    1 | 大众新捷达   |         52 |
|    2 | 斯柯达明锐   |         50 |
|    3 | 大众宝来     |         46 |
|    4 | 大众朗逸     |         42 |
|    5 | 丰田卡罗拉   |         39 |
|    6 | 起亚K3       |         35 |
|    7 | 马自达CX-5   |         30 |
|    8 | 大众速腾     |         29 |
|    9 | 大众新桑塔纳 |         28 |
|   10 | 日产轩逸     |         27 |
|   11 | 标致301      |         24 |
|   12 | 现代瑞纳     |         24 |
|   13 | 福特福克斯   |         23 |
|   14 | 标致408      |         22 |
|   15 | 哈弗H6       |         22 |
|   16 | 雪铁龙爱丽舍 |         21 |
|   17 | 雪佛兰爱唯欧 |         21 |
|   18 | 别克英朗     |         20 |
|   19 | 斯柯达昕锐   |         19 |
|   20 | 大众帕萨特   |         19 |
+------+--------------+------------+

车型加油积分排名:
+------+--------------+----------+----------+
| 排名 |     车型     | 加油积分 | 平均积分 |
+------+--------------+----------+----------+
|    1 | 丰田卡罗拉   |     1613 |    41.36 |
|    2 | 大众朗逸     |     1504 |    35.81 |
|    3 | 斯柯达明锐   |     1452 |    29.04 |
|    4 | 大众宝来     |     1283 |    27.89 |
|    5 | 日产轩逸     |     1232 |    45.63 |
|    6 | 大众速腾     |     1222 |    42.14 |
|    7 | 大众新捷达   |     1146 |    22.04 |
|    8 | 长安逸动     |     1002 |    58.94 |
|    9 | 起亚K3       |      870 |    24.86 |
|   10 | 别克英朗     |      846 |    42.30 |
|   11 | 大众新桑塔纳 |      743 |    26.54 |
|   12 | 现代朗动     |      720 |    42.35 |
|   13 | 丰田凯美瑞   |      719 |    79.89 |
|   14 | 日产天籁     |      694 |    49.57 |
|   15 | 标致301      |      671 |    27.96 |
|   16 | 雪铁龙爱丽舍 |      653 |    31.10 |
|   17 | 福特福克斯   |      570 |    24.78 |
|   18 | 现代瑞纳     |      568 |    23.67 |
|   19 | 别克凯越     |      544 |    45.33 |
|   20 | 斯柯达昕锐   |      527 |    27.74 |
+------+--------------+----------+----------+

重庆市

车型订单数量排名:
+------+-------------+------------+
| 排名 |    车型     | 实时订单数 |
+------+-------------+------------+
|    1 | 标致408     |         19 |
|    2 | 本田凌派    |         16 |
|    3 | 长安逸动    |         16 |
|    4 | 大众朗逸    |         15 |
|    5 | 起亚K3      |         14 |
|    6 | 马自达CX-5  |         14 |
|    7 | 日产天籁    |         14 |
|    8 | 吉利帝豪    |         10 |
|    9 | 奇瑞艾瑞泽5 |         10 |
|   10 | 大众新捷达  |         10 |
|   11 | 别克威朗    |          9 |
|   12 | 名爵锐行    |          9 |
|   13 | 标致308     |          9 |
|   14 | 宝骏560     |          8 |
|   15 | 日产轩逸    |          8 |
|   16 | 荣威i6      |          8 |
|   17 | 吉利帝豪GL  |          7 |
|   18 | 日产阳光    |          7 |
|   19 | 众泰Z560    |          7 |
|   20 | 长安CS35    |          7 |
+------+-------------+------------+

车型加油积分排名:
+------+--------------+----------+----------+
| 排名 |     车型     | 加油积分 | 平均积分 |
+------+--------------+----------+----------+
|    1 | 长安逸动     |      548 |    34.25 |
|    2 | 本田凌派     |      427 |    26.69 |
|    3 | 日产天籁     |      379 |    27.07 |
|    4 | 大众朗逸     |      364 |    24.27 |
|    5 | 起亚K3       |      298 |    21.29 |
|    6 | 日产轩逸     |      287 |    35.88 |
|    7 | 福特福睿斯   |      252 |    42.00 |
|    8 | 本田锋范     |      246 |    49.20 |
|    9 | 丰田卡罗拉   |      233 |    38.83 |
|   10 | 大众新桑塔纳 |      203 |    67.67 |
|   11 | 名爵锐行     |      197 |    21.89 |
|   12 | 丰田凯美瑞   |      183 |    36.60 |
|   13 | 别克威朗     |      175 |    19.44 |
|   14 | 吉利帝豪GL   |      169 |    24.14 |
|   15 | 众泰Z560     |      164 |    23.43 |
|   16 | 宝骏560      |      160 |    20.00 |
|   17 | 雪佛兰科鲁兹 |      159 |    22.71 |
|   18 | 长安CS75     |      157 |    78.50 |
|   19 | 起亚K5       |      155 |    25.83 |
|   20 | 哈弗H6       |      151 |    75.50 |
+------+--------------+----------+----------+