作者归档:qwj

微信小游戏“跳一跳”刷分代码

目前为止有效的代码。

可以看出,可能未来会加服务器端的验证,
根据客户端传来的seed,重新模拟一遍以确定是不是正确数据。
在此之前,这个代码还是可以跑的。

运行在 Python3 + pycryptodome 环境下。需要先抓包确定你的 session_id 然后填进代码里。

import requests, json, base64, random, time
from Crypto.Cipher import AES

session_id = "___your_weixin_session_id_here___"
score = 10000

game_data = dict(seed=int(time.time()*1000), action=[], musicList=[], touchList=[], version=1)
start = 0
for i in range(score+1):
    interval = random.randrange(40, 100)
    press = random.randrange(interval)
    start += interval
    game_data['action'].append([press*0.01, start*0.01, False])
    game_data['musicList'].append(False)
    game_data['touchList'].append((276+random.randrange(50), 298+random.randrange(50)))

action_data = {
    "score": score,
    "times": start+5,
    "game_data": json.dumps(game_data, separators=(',',':'))
}

aes_key = session_id[0:16].encode()
cipher = AES.new(aes_key, AES.MODE_CBC, aes_key)

str_action_data = json.dumps(action_data).encode()
length = 16 - (len(str_action_data) % 16)
str_action_data += bytes([length])*length

cipher_action_data = base64.b64encode(cipher.encrypt(str_action_data)).decode()

post_data = {
    "base_req": {
        "session_id": session_id,
        "fast": 1,
    },
    "action_data": cipher_action_data
}

headers = {
    "charset": "utf-8",
    "Accept-Encoding": "gzip",
    "referer": "https://servicewechat.com/wx7c8d593b2c3a7703/3/page-frame.html",
    "content-type": "application/json",
    "User-Agent": "MicroMessenger/6.6.1.1200(0x26060130) NetType/WIFI Language/zh_CN",
    "Content-Length": "0",
    "Host": "mp.weixin.qq.com",
    "Connection": "Keep-Alive"
}

url = "https://mp.weixin.qq.com/wxagame/wxagame_settlement"

response = requests.post(url, json=post_data, headers=headers)
print(json.loads(response.text))

关于如何抓包的简单流程:(iOS手机)

  • iOS上跑着微信,同时有一台电脑,电脑安装 burpsuite
  • 启动 burpsuite,配置好端口
  • 手机打开浏览器访问电脑 burpsuite页面,下载安装SSL证书
  • 通用->关于本机->证书信任设置->打开PortSwiggerCA (iOS 11以后)
  • 手机配置网络,选择用代理,地址和端口填电脑的
  • 启动微信小程序,这时候可以看到抓到的 HTTPS包,取出里面的 session_id

简评围棋世纪大战

W020160309499767463096AlphaGo与李世石的世纪大战在3月15日落下了帷幕,李世石终于不敌AlphaGo,最后战成了1:4。其中可圈可点的第四盘,AlphaGo走出奇臭无比的黑79手,并没有像很多IT专家开赛前预测的横扫李世石,把无数“专家”们的脸都打肿了。

甚至有很多国内“专家”开始鼓吹人工智能已经战胜人类,甚至人类将要被人工智能统治等无知言论,让人实在看不下去。做为围棋爱好者和一个普通挨踢工作者,这里可以简单说一下AlphaGo的原理和机制。

AlphaGo是一个通用型人工智能程序?这个恐怕是今年最大的误解。

让我们看看背后的英国团队DeepMind的Aja Huang(黄士杰),从2003年硕士论文开始研究围棋打劫程序,到2011年博士论文研究围棋MCTS算法,一直是各大围棋程序研究的中坚力量,其本人也有业余6段水平。DeepMind的创始人Demis还是一个国际象棋13岁的天才大师。DeepMind团队中其他懂围棋的也不在少数,团队更是从去年就开始请欧洲冠军樊麾做他们的全职围棋顾问。

其所使用的算法,主要可以分为三大块:蒙特卡洛搜索(MCTS),快速走子,和深度神经网络。MCTS是目前非常针对围棋的博弈类搜索算法,快速走子是充分利用围棋定式和规则的在极短时间内下子的算法,深度神经网络是一个获取统计知识的训练学习模型。可以看到,只有深度神经网络勉强算作通用性算法,其余都是相当针对围棋这一课题的专业性特殊算法。

最近深度神经网络炒作的火热,甚至有人认为从深度神经网络就可以发展出真正的智能来了。深度神经网络是统计知识的学习算法,它并不具备逻辑知识,从目前应用来看,可以解决一些图像识别问题,但是离真正的人工智能还有十万八千里。

从对弈结果来看,我们也发现了AlphaGo极大的不足:大局观优秀,计算力不行。一个很尴尬的问题就是,为什么计算机还会计算力不行?这实际上还是因为围棋的棋盘太庞大,如果采用全盘搜索,即使深度再深,对于局部来说也搜不到几步。AlphaGo并不像其它围棋程序一样,在局部战斗的时候会临时缩小搜索范围,产生局部最大化的计算力,因此AlphaGo的局部往往会亏损,反而没有职业棋手算的清楚。

计算力不足导致的另一个严重问题是,一旦涉及到复杂的劫争,就会立刻陷入被动,导致崩盘。从对弈过程来看,AlphaGo有意的避免打劫的出现,是有目共睹的。实际上,大局观和局部计算力是任何一个围棋程序难以取舍的两个难点。要大局观,必须全盘搜索,使得局部计算力有一定缺陷。要计算力,必须在局部问题上加以限制,因此往往不会脱先去争别处的好点。

另一个问题是,自我训练(self-train)可以显著提高水平么?这一点在之前被专家们鼓吹的很凶猛,号称一直训练下去可以得到围棋上帝。实际上自己和自己下得到的谱,一般来说是有瓶颈存在的。在两个估价函数相同的程序看来,因为搜索深度和宽度局限,看不到的棋局依然看不到。随便举个例子,两个6岁小孩对下10000局可以提高到职业9段?只有和比你更厉害的高手对弈才可以显著提高水平。这也是AlphaGo团队请了樊麾去做围棋顾问,特训了几个月的原因所在。

Alp470e92b60339250b849feaf4802f0891haGo解决了围棋问题了么?AlphaGo就是围棋上帝?其实远远没有解决。人类研究围棋算法已有超过百年历史,最近十几年MCTS算法也给围棋程序注入了一股新鲜的活力,极大的提高了围棋程序的水平。然而,围棋由于状态空间的庞大,注定是需要更多更长时间来优化的。甚至如果说要完全“解决”围棋问题,搜索完全部的围棋状态空间,恐怕未来50年都看不到任何希望。

从世界范围来看,AlphaGo的算法改进创新上不见得很优秀,在我看来更像是利用了Google庞大的计算资源(相比之下其它围棋程序的可分配计算资源简直少的可怜)而取得的成果。本次对弈尽管从结果上来看非常的出色,机器程序有史以来第一次战胜了人类职业9段,但在我看来依然有着浓重的商业营销味。

围棋是个大问题,棋盘太大,可能性太大,职业棋手确实有时候都无法评价一步棋的好坏。未来几年,也许发展过后的围棋程序可以帮助职业棋手提高水平增强实力,不过如果要把围棋程序和人工智能生扯在一起,我觉得从目前来看依然是远远不够的。

到目前为止,没有任何迹象表明,深度神经网络对统计知识的学习可以表征人类智能,恰恰相反,深度神经网络其局限性也越来越多的被人了解。智能是非常复杂的统计知识的表征么?智能是什么,其实到现在依然是个谜。

 

浅谈部落冲突的协议设计

部落冲突(Clash of Clans)是一款风靡全世界的手机游戏。部落冲突的忽然流行造就了又一家神奇的芬兰公司Supercell,同时也带来了很多关于游戏成功秘诀的讨论。在这里我们暂且不论部落冲突为啥会吸引那么多玩家这个话题,简单来看看部落冲突里的底层协议设计。

部落冲突的底层协议可以说设计的非常的好,从技术上说,也是非常先进而且高效的。首先客户端和服务器端采用RC4进行加密。在第一次握手之后,服务器端会传回一个秘钥seed,然后客户端和服务器端把新seed扔给Scramble7算法,产生新秘钥。这个算法在客户端更新之后还经常进行变换,可见Supercell程序员的用功刻苦程度。算法握手大致描述如下:
client.rc4 = RC4(INIT_KEY)
server.rc4 = RC4(INIT_KEY)
client: login(user_id, user_pwd, client_version, device_info, client_seed)
server: login_success(user_id, user_pwd, client_version, client_bind, server_seed)
server: set_key(new_key)
prng = Scramble7(server_seed)
reset_key = prng.get_key(new_key)
client.rc4 = RC4(reset_key)
server.rc4 = RC4(reset_key)

在经过这一系列解密之后,我们才能开始看到明文,知道客户端和服务器之间到底交流了什么。

接下来让我们仔细分析一下部落冲突目前的核心玩法:部落战的协议内容:
client: attackwar(user_id)
server: attackwar_fail(user_id, reason) # If fail
server: attackwar(map_info) # If success
client: action(tick, checksum, [action1, action2, action3, ...])
action_list:
action_army: (x, y, army_id, tick)
action_ally: (x, y, ally_id, tick)
action_end: (tick)
action_spell: (x, y, spell_id, tick)
action_hero: (x, y, hero_id, tick)
action_herospell: (hero_id, tick)
action_start: (tick)
action_data: (data_content, tick)

我们先来看一个设计的非常巧妙的action指令。这个指令的头是tick和checksum,tick是以1/60秒为单位的整数(60就是第一秒,120就是第二秒),而checksum是一个客户端信息的总和。

信息的总和是如何算出来的呢?这里非常巧妙的是,客户端会把目前绝大多数数据做一个求和,再算上当前tick数,得到一个总的checksum。这个checksum非常的关键,因为服务器会校验。服务器如果不了解客户端信息,是怎么校验的呢?很简单,服务器在连接建立之后,会跑着一套和客户端同样逻辑的代码,然后对客户端发来的每一条信息进行checksum校验。

比如说,客户端说我第一秒在某处放了一条龙。客户端经过模拟后,发现第二秒龙会摧毁一个对方的建筑,这时候checksum就会有显著变化,因为一个建筑没了。这时候给服务器的checksum必须有体现,服务器也会跑一个模拟程序,检验第二秒龙摧毁了一个建筑,如果客户端发来的checksum对不上,那么服务器就会断掉连接,认为客户端非法。

所以要做一个脱机离开客户端直接向服务器发送请求的程序很难,因为必须包含客户端完整的模拟战斗逻辑。而这套逻辑是部落冲突的代码核心,每次版本更新都会大改,非常难以完整进行模拟。

在此基础上的协议基本杜绝了第三方脱机机器人的存在。大部分机器人必须依靠客户端才能进行,比如BlueStacks上运行的虚机。

然而,这样的协议之上依然存在很多漏洞。还是拿部落战举例,如果有一个Men-In-The-Middle拦截了打的不好的协议包,只传送打的好的协议包,那么其实是可以保证每一次部落战都完成三星。

在最近的一次更新中,新增了action_start和action_data两条指令,这是做什么用的呢?Supercell为了阻止日益猖獗的叉叉助手和iMod所谓沙盒模拟(就是脱机练习进行演练),将对手的一部分信息(电塔援军陷阱)进行了隐藏。在付出一次攻击代价的情况下,服务器会给客户端返回这些信息,客户端才能进行完整的游戏。大概的逻辑如下:
client: attackwar(user_id)
server: attackwar(map_without_key_info)
client: action(60, checksum_60, [action_start(0)])
server: key_info(data)
client: action(120, checksum_120, [action_data(61, data)])
client: action(180, checksum_180, [action_army(125, x, y, army_id), ...])
......

简单说就是在action_start之后,服务器才会返回关键信息,让客户端能够完整进行模拟。那么action_data的作用是什么呢?由于checksum机制的存在,服务器需要和客户端同步加入这部分关键信息,所以客户端需要在收到key_info之后,告诉服务器,我在何时(tick)把这些key_info加入到地图形成完整地图的。然后服务器收到之后,可以和客户端一起进行模拟,并且校验checksum。

那么目前版本有一个致命的bug,就是服务器对action_data返回的data并没有进行检验。导致的后果就是客户端如果发回的key_info和服务器之前传回的不一样,也能正常模拟下去。如果客户端发一个空的key_info,服务器会认为陷阱电塔援军都神奇的消失了!

当然这种bug可能并不影响普通玩家,可能只有深入研究了协议的才会发现。尽管存在很多bug,但是笔者认为部落冲突依然是一款从技术上设计非常精良的游戏。不管何时,技术上的完善都是一款游戏坚实的基石。如果外挂横行漏洞百出,不管游戏表面有多美丽,都是一摊烂泥无法流行起来。

 

经络就是血管

本不想谈“中医”这个敏感话题的。但是最近和人在微信上争论,有感而发,所以略写一些感想。

一个首先不可能回避的问题就是:中国有几千年的璀璨文化和历史。存在这样的可能,几千年里中国人一直没有发现血管的存在,转而发现了一个和血管大致位置相当,但是现代人都找不到准确位置的经络么?

中国古代战乱多,打仗死人也很多,虽然没有专业解剖学,中国古人也有身体发肤受之父母的顾虑,但是在死人身上稍加观察,也能知道皮肤底下不远处就有血管,血管里流淌着血液。其实经络的根源中医“圣经”《黄帝内经》里说的明明白白的:若夫八尺之士,皮肉在此,外可度量切循而得之,其死可解剖而视之。……脉之长短,血之清浊,气之多少,十二经之多血少气,与其少血多气,与其皆多血气,与其皆少血气,皆有大数。说人话就是,找个正常人,大概量量位置切开皮肉,下面就能看到脉了,脉里面流淌着血和气,有的脉里面血多气少,有的脉里面血少气多。

为什么《黄帝内经》会认为血管里有血也有气?这大概也是古人观察不仔细而已。毕竟没有解剖学,死人一般血液也流的差不多了,所以会给观察者以一个印象,有些血管里还有血液,有些血管里空空如也了。

“经络就是血管”是很新鲜的现代观点么?非也非也。其实早在清朝就有人发现了。清代著名医学家王清任有说:“古人言经络是血管”,在《医林改错》中,他还说:“著书不明脏腑,岂不是痴人说梦?治病不明脏腑,何异于盲子夜行?”,他开创性的尝试去解剖,了解人的五脏六腑结构,取得了在中国古代非常了不起得成果。但是这时候也已经太迟了,西方早已建立起了完整的现代医学和解剖学。

但是为啥此后的后人会把经络和血管当成两个东西?这里面有非常复杂的原因,根本上说还是中国人迷信上古文化、盲目的民族主义情绪在作祟。在现代解剖学传入中国,发现古人所描绘的经络图与现代解剖学所发现的血管、神经的分布都不符合之后,有人就开始宣称经络是现代解剖学也发现不了的存在了。还有人宣称古人是用“内视”看到自己体内的经络,借此宣传气功特异功能这些早已被一次又一次揭穿的伪科学内容。

每隔一段时间,就有人宣称用某种现代生物技术验证了经络的存在,这些研究大多是中国人在做,实验设计存在种种问题,也无法获得国际生物医学界的认可。如果经络真的存在,还那么的对针刺敏感,那么每年手术台下被切断的经络数以百万计。外科医生需要熟知人体的血管分布,但是从来不需要知道虚幻的经络是怎么走位,然后动刀时要考虑绕开它们。从这一点思考,就可以知道经络假设是多么的可笑和荒唐。

本来还想再写写古代文化、古代科学和现代文明的冲突问题,还是就此打住了。一个简单的观点就是:古代文化是宝贵财富,可以研究,但是拿来看病就要人命了。

原创微小说一则

女孩深爱着英雄,却遭到了父亲的反对。“为什么我们不能在一起?” “孩咂,他是来自异世界强大的英雄,而你只是一个负责派发任务的原住民!”
女孩不听父亲劝阻,千方百计的接近英雄。但是英雄却对女孩熟视无睹,嘴里还说着奇怪的话:“游戏公司也太省钱了吧,都是一个模子刻出来的”
女孩为了帮助英雄,发任务时将内容偷偷的删减,却只听到英雄自己偷笑,嘴里还说着奇怪的话:“难道我真是天命所归之人?连任务都比论坛上说的简单许多呢”
女孩为了更近距离接近英雄,走进了危机四伏的怪物洞穴,被有毒的蜘蛛咬了,无助的躺在洞穴地上。“救我!英雄!我就要死了。。” 走过的英雄连头都没有回,嘴里还说着奇怪的话:“倒霉的小姑娘,任务刚好做完,你没赶上最后一个!”

随笔于德拉诺之王100级,缅怀那些在升级路上被忽略被遗忘的系统NPC们

钻石恒久远?一个营销骗局和玩笑

钻石最早起源于古印度的河床。然而直到十九世纪末,钻石还不是啥值钱的玩意儿。1772年拉瓦锡同学眼睛眨都不眨的就拿棱镜烧掉了一块钻石,发现钻石迅速和氧气结合,最后变成了气体二氧化碳,以此证明了钻石的成分实际就是碳。如果放到今天来做这个实验,拉瓦锡同学一定会赔得倾家荡产。

1024px-National_Museum_of_Natural_History_Gold_Colored_Diamonds为什么如今的钻石已经变成了天价珠宝,远远超过黄金翡翠红宝石蓝宝石等稀有金属和宝石呢?

有人说这一定是物以稀为贵吧,钻石那么珍贵那么稀少,自然就比其他宝石要贵咯?实际上,钻石的天然储量远远比所有其它稀有宝石加起来都要多,多到开采公司建了大量的钻石仓库囤货避免快速贬值:一克拉以下的钻石数量和天上的星星一样多。另一个非常致命的事实是,人工钻石技术已经发展到了可以合成非常廉价和美丽的大尺寸珠宝钻石,逼真到连珠宝师都需要用仪器花很久才能分辨真假的程度了。

还有人说,钻石之所以贵是因为漂亮。被切割了那么多面的透明晶体还带着各色的光,非常炫目。实际上,所有晶体都有同样的特性。如今卖的火热的水钻,也就是水晶玻璃,如果不靠物理接触,是很难很难分辨和钻石之间的本质区别的。

那么也许有人会说起钻石另一个优点:耐久。钻石那么耐久,所以人们才喜欢呀。钻石恒久远(Diamond is forever),多么美丽的童话。然而实际上,就如本文开始提到的实验那样,钻石是所有珠宝和贵金属里最不易保存的。钻石的燃点只有区区800度,一场火灾或者一个事故就会让你花天价买来的钻石灰飞烟灭变成纯净的二氧化碳,比如前阵子有媒体报道过上海一个人家里着火,火灾过后数十万的钻戒只剩下个金属戒指框。

钻石的唯一值得称道的恐怕就是它的硬度了。钻石硬度是天然矿石里最高的,和别的物体打击也很难留下划痕,但是这也就是工业制造上比较有用。实际上工业制造中也已经用上了物美价廉的人工钻了,性能一点也不比天然钻石差。你有见过其它任何宝石或者贵金属可以完全被人工合成么?

最后和其它珠宝很不一样的一点是,钻石的二手交易市场非常惨淡。几乎不会有人愿意买二手的钻戒。钻石虽然是珠宝,但是更像是个人一次消费品,比如汽车或者手机。一旦买入再进行二手交易,价值就会大大下降。

那么为何短短一百年,钻石就从不值钱变成价值连城,人类结婚必备之物了呢?这个故事要从De Beers公司说起。

大概1870年,大量的钻石矿在南非被发现。当时的英国金融家认为这是个发财的好机会,就迅速霸占了矿场,后来成立了一个叫De Beers的公司。然而问题来了,在此之前,每年的钻石开采量也只有几公斤,需求量也不是很大,也卖不出什么价钱来。现在有了一个随便就能挖出几吨几吨的钻石矿,怎么能保证卖出个好价钱出来?

De Beers用行动最终告诉大家,只要垄断外加疯狂营销,市场供给规律不是大问题,就是一块破石头也可以给你卖出天价来!

De Beers花了一百年的时间,玩命砸钱做广告。广告的内容无非就是说,De Beers告诉你,女人就是天生离不开钻石的。钻石稀有,璀璨,拥有不可限量的价值,一颗钻石成就一段人生,一块破石头就是婚姻的见证。

在1938年,De Beers找了一家美国的广告公司N. W. Ayer,打造了人类历史上最成功的营销案例:钻石恒久远,一颗永流传。这个广告公司策划了一系列的大型宣传活动,甚至拉上了英国伊丽莎白女王一起做秀。在广告语里,每一颗钻石都可以比作毕加索的名画,是独一无二不可缺少的艺术品。在随后50-60年,做这个广告的De Beers甚至都不用加上公司名,因为他们垄断了市场上的几乎所有钻石的源头。到如今,钻石已经成为了人类结婚必备的必需品。尽管各个国家的新钻石矿不断的被开采,尽管钻石的供应量不断突破新纪录,然而由于垄断和心理营销,钻石的价值反而越来越高,到如今成为了珠宝之王。

在这里大胆预测,随着人工钻石技术的突破,以及俄罗斯钻石矿的开采和流向市场,未来会有这个破石头慢慢跌回原本价值的一天。

新一届菲尔兹奖随想

就在前两天,新一届2014年菲尔兹奖,在韩国首尔完成了颁奖典礼。四年之后的今年又诞生了四位新晋菲尔兹奖得主。菲尔兹奖又被称为数学界的诺贝尔奖,是所有数学家的梦想,每一位菲尔兹奖的获得者都是传奇天才数学家,挑战了各种人类的智商极限,每一届菲尔兹奖也是人类最可怕天才的展览会。今年的菲尔兹奖诞生了很多个“第一”,也是槽点满满的一届菲尔兹奖。让我们看看今年菲尔兹又出了哪些可怕的人物。

首先,人类的半边天,女性同胞,第一次登上了菲尔兹奖的领奖台!伊朗女数学家Maryam Mirzakhani,代表了全世界女性,摘取了第一次菲尔兹奖桂冠,彻底粉碎了女人数学不好的谣言。这位女数学家同时也是伊朗人第一个菲尔兹奖。(中国的第一个在哪里呢?)

Maryam Mirzakhani在17岁、18岁的时候就两夺IMO金牌,可谓是天才少女,而且在18岁参加1995年那一届IMO的时候获得过满分!也是伊朗历史上唯一一个满分IMO!之后在伊朗本科毕业,去了美国哈佛念了PhD,师从菲尔兹奖得主Curtis McMullen。PhD毕业后不到10年,黎曼平面上的成就让她于37岁的年纪摘获菲尔兹。

接下来另一位天才少年是巴西人Artur Avila。16岁获得IMO金牌,21岁拿到PhD学位,但是这还远远不是他的极限。仅仅35岁的他就依靠动力系统的成就摘取菲尔兹,同时打破多项纪录:第一个巴西人菲尔兹,第一个拉丁美洲菲尔兹。(中国的第一个在哪里呢?)

再来看看Manjul Bhargava,14岁完成高中课程,18岁哈佛大学毕业,23岁普林斯顿的PhD。尽管没有IMO金牌,但是经历依然非常的传奇。师从解开费马大定理的Andrew Wiles,在PhD毕业两年之后就拿到了普林斯顿终身教授,被认为是常青藤学校里的最快纪录保持者。他在非常多的领域里都有贡献,于40岁时摘获菲尔兹桂冠。

最后让我们看看Martin Hairer,和另外三位相比就不是那么耀眼,但是依然能在14岁就用Mac写软件解偏微分方程,之后就一直在和编程以及随机偏微分方程打交道。自己还在网上做了一个叫hairersoft的共享软件工作室,同时在线出售Mac上的音频软件,可以很好的处理噪音杂音。现年38岁的他,以随机分析里的重大理论斩获菲尔兹。他的共享软件最近一定会迎来一个购买热潮吧!

做为国人,不得不面对的一个尴尬问题,就是中国的数学教育和人才。其中中国IMO问题一直是公知们批评的重点。尽管中国国家队不停的在国际上取得好成绩,囊括各种奖牌和总分第一,但是中国依然整体数学水平很弱,缺少带有中国国籍的数学大师。这是为什么呢?

首先,菲尔兹奖确实太难拿了,IMO金牌每年都会有几百个新鲜出炉,而菲尔兹奖每4年才会有2-4个人。到目前为止也只有13个IMO拿过菲尔兹,相比IMO奖牌的基数,以及中国IMO奖牌的总数,这个比例还是相当的低。如果按照概率来算,目前中国拿不到菲尔兹,好像还算正常范畴。

第二,中国IMO奖牌们有一部分因为生活或者家庭压力都最终放弃了走数学这条道路。这也是无可厚非的,回报父母,尽早独立,也是中国孩子们必须要承担的责任之一。苦苦在数学道路上煎熬很多年,如果天分不够,可能真的要像张益唐那样要坚持非常多年才可以厚积薄发。

第三,中国IMO相对其它国家的天才们确实有一些水分。中国的举国体制下,各个奥赛的培训时间长度向来是世界第一的,和其它国家的天才少年比起来,同样是金牌,可能平均水平是要略差一些。当然,并不是说中国的IMO们不够天才,只是说国外的IMO们更加天才妖孽,有的没有经过太长的训练就能斩获金牌满分。

第四,中国目前没有能够培养出菲尔兹的环境和土壤。有一位世界级的好老师,才更有可能将来自己也成为大师。国外天才少年们在本科阶段就早早的在老师带领下开始了学术之路,而中国的本科孩子们还在为学分积和考G考T苦苦挣扎,甚至还有因为没有正确引导,迷茫失落最后去出家的小天才们。也有那么一些已经成为数学大师的中国人,往往在国外辗转漂泊那么多年,早早就加入了外国国籍。

最后,目前依然还是有相当多的在数学领域耕耘拼搏的中国天才。期待4年后或者8年后能在菲尔兹奖台上看到他们的身影!

 

浅谈 Swift 语言

在刚过去不久swift_taylor的万众瞩目的 WWDC 2014 上,苹果发布了 Swift 语言。注意这个和已存在很久的 Swift Parallel Language (http://swift-lang.org/) 是两个东西。这是由苹果独立开发完成的,基于 LLVM 的全新语言,是一个从头到脚都打上苹果烙印的新东西。作者于是来赶趟儿简单写写对 Swift 语言的体会和感受。

Swift 做为一个崭新的2014年才发布的语言,全身上下都透着各种狂拽酷炫吊炸天的味道。从各家语言中博采众长,非常具备时代气息。关于 Swift 从哪些语言里继承了哪些特点,各家说法都有。个人第一印象觉得 Swift 更像 Ruby 一些。

然而做为一个新生语言,Swift 也有着一些小缺点:

  • 你依然需要学Objective C。Swift的大量底层库还是Objective C写的。如果真想写个游戏的话,难免还是会涉及调用大量的Cocoa风格的API。当然,有一部分Objective C的库已经专门为Swift进行了参数简化和改写,你有时候不需要再写Objective C里的反人类的长达几十个字母的常量名了。比如:let myTableView: UITableView = UITableView(frame: CGRectZero, style: .Grouped)
  • 缺少私有属性、异常处理等机制。私有属性很多语言都没有,个人觉得没有太大关系;异常处理的话,做为新时代语言来说,缺少了还是比较不应该,虽说Objective C里也没有。
  • 类型非常诡异的复制特性。比如下面代码
    var ages = ["Peter": 23, "Wei": 35, "Anish": 65, "Katya": 19]
    var copiedAges = ages
    copiedAges["Peter"] = 24
    println(ages["Peter"])
    // 23
    var a = [1, 2, 3]
    var b = a
    a[0] = 42
    println(a[0])
    // 42
    println(b[0])
    // 42
    a.append(4)
    a[0] = 777
    println(a[0])
    // 777
    println(b[0])
    // 42

    大家可以体会一下这让人毛骨悚然的设计。简单说就是字典赋值都会复制一份出来,而数组不会。但是数组一旦长度做了更改也会立刻原地复制一份出来。这种设计模式很让人摸不到头脑,比较反常识。
  • 文档依然不是很齐全。需要较长时间来补充。
  • 无法跨平台。说到这一点确实有人要说这是勉为其难了。Apple凭啥做个能跨Android的东西来呢。然而,大概询问了几家游戏开发公司,都表示最大得导致他们不会用Swift开发游戏的原因就是没法跨平台。而现有的很多游戏引擎都做到了跨平台开发。

由于 Swift 的优点太多,网上也有很多人做了分析,这里就不一一详述了。这里只想总结说,Swift 确实是门开发效率非常高的语言。如果你只做 iOS/Mac 开发,Swift 现在是你的第一选择。

有人问 Swift 会不会是 iOS 开发的未来。我可以毋庸置疑的回答,是的。Apple的策略倾向导致,将来会有大量的资源像 Swift 倾斜。对于一个公司策略级的开发语言来说,Swift 的前途已经注定灿烂了。就像 Apple 描述 Swift 的那样:A complete replacement for both the C and Objective-C languages。

最后祝大家在 Swift 学习中能找到乐趣。

 

云服务为什么会是未来?

今天在交流时候有记者问过我,使用云服务主要还是成本的考虑吗?是的。和传统服务相比,云服务实际上没有哪一点是完全不可替代的。而成本恰恰是小团队最关心的一个问题,时间成本、人力成本、以及最直接的机时售价价格,这些问题累积在一起,才是做为初创公司选择云服务的所有理由。

 

英国经济学家杰文斯曾经在《煤矿问题》中指出一个看似互相矛盾的问题:对蒸汽机性能的改进提高了煤炭的能源转化率,用更少的煤可以产生更多的能源了,而能源的价格降低往往又导致了煤矿的消费量增加。这种现象被称为杰文斯悖论,既:对资源的利用率降低了资源的价格,最终会增加资源的使用量。在云计算领域,该悖论也非常的适用,云服务大大改进了计算资源的利用率,改进的方式包括:更简单的获取计算资源的方式,以及将闲置计算资源更好的释放出来。当开关服务器就和开关水龙头一样便捷之后,公司以及个人对服务器资源的需求会大大的增加。

举个切身体会到的例子。曾几何时,公司弄一台线上服务器是如此的困难。早先我们需要首先买一台服务器,然后找个机房托管,签完各种合同,交完押金和钱,将庞大的机器搬到机房里的某个机柜,插好各种线,终于可以接入互联网开始服务了。再然后有了服务器租赁业务,依然会比较麻烦,填完合同之后,大概需要2-3天不等,机器才能准备好。在如今云服务提供的便利之下,5分钟可以开一台服务器,用完即关。

对于传统互联网公司来说,一方面,在计算资源获取困难的时候,一个项目或者一个新计划只能压缩到有服务器的时候才能开展,而根据流量动态调节服务器响应能力变得几乎不可能。另一方面,在计算资源过剩的时候,闲置在那里的服务器资源对于能源的浪费,简直是一件令人发指的事情。有一个听来的真实的笑话是这么说的,老板发现了公司服务器CPU闲置的非常厉害,让手下想办法。某公司手下用脚本检查CPU占用率,如果没满就写一个死循环占满。另一个公司觉得这样太直白了不太好,就暗示开发把代码写的烂一点,以占用更多的CPU让数字看上去好看些。对于大型互联网公司来说,目前每年都有无数的钱财和资源浪费在了闲置服务器上。

如果将传统服务器比作每天早上下山挑水喝,那么云服务就像是自来水入户,打开水龙头,水就流了出来,不用的时候,可以随时关上水龙头。既充分利用了资源,也没有造成资源浪费,把成本降到了最低。将计算能力分割成块然后当成自来水一样出售给大众,这无疑是大势所趋。在未来,任何一个普通学生想起一个复杂的算法,都可以经过简单的操作,然后开启100台服务器进行计算,最后在验证完算法之后关闭。云服务会真正像自来水一样走进千家万户。

有感而发写一点不那么务实的东东。

 

 

用 AWS 构建高性能 Appflood 广告服务

众所周知,广告业务是对服务器的性能考验最为严峻。首先广告业务的访问量十分巨大,动辄每秒成千上万的请求,其次广告业务对于实时性的要求非常之高,在 RTB 环境下要求请求延迟不超过100毫秒,而我们对自己的要求往往是请求延迟不超过20毫秒。

重新从底层搭建所有框架对于创业型公司来说是很不现实的。Key-Value DB、Cache、LoadBalancer、TaskQueue,这一切如果都用开源框架来搭建,无异于一场灾难。从易用性到健壮性,从 Availability 到 Scalability,开源框架往往都不能完整的满足所有。幸好亚马逊提供的 AWS 服务提供了完整的全套的解决方案。我们从中也学到了很多东西。

1. Colocation -> IaaS

早先公司自购的服务器并且用的美国公司的托管服务。后来发现对于创业公司来说,繁复的服务器维护工作简直是一场灾难。在09年左右卖掉了服务器,投靠了 AWS 的怀抱,开始全部用 IaaS 做为服务器平台。

说实话初期 AWS 的虚拟 Instance 很不好用。做为第一批吃螃蟹的用户来说,体验过各种奇葩的问题,比如 Instance 失去响应,Reboot失效等等。经过询问 AWS 工程师,给出的结论一般是:Linux内核问题、底层硬件坏了,或者就是他们也不知道原因。

不过虚拟 Instance 的好处也非常明显,就是开关很便捷。如果真的坏了而且也找不到原因就再开一台吧。AWS可以靠低价的Instance数量取胜。

2. Key-Value -> DynamoDB

公司早期我们就是Key-Value的狂热热爱者。在试用过Tokyo Tyrant,MongoDB,Riak等等服务之后,最后我们还是采用了 AWS 的 DynamoDB。Key-Value看似美好,但是其背后的维护人力成本也非常之高。在数据快速增长的时候,在节点出现意外的时候,在磁盘满了需要更换节点的时候,往往都是灾难发生的时候。虽然标榜具有很高的 Availability,但是往往需要开大量的冗余节点支撑,平时在不用的时候浪费很多的钱。在个别节点崩溃之后,剩余节点的负载又往往高居不下,很难调节。

最后我们试用了 DynamoDB,到目前为止感觉良好。无需自己考虑节点问题,无需考虑存储空间不够。唯一的问题可能就是无法做 Replica。当然这一问题也有其他办法可以解决。

3. TaskQueue -> SQS

对于读写分离的线上业务来说,TaskQueue 服务一般是必不可少的。早期我们自己搭建的TaskQueue Service,后台采用 Redis 做存储,也尝试过较为成熟的 RabbitMQ 等开源方案。一个经常遇到的比较严重的问题就是,存储满了怎么办。

相信所有 TaskQueue 系统最怕的就是存储满了怎么办,无论你的存储是在很大的内存里,还是在磁盘上,如果 Worker 不工作总会有满了的时候。突发流量增加导致后端 Worker 处理不过来,或者因为 Worker 的代码异常导致处理速度过慢。一般的 TaskQueue 系统遇到这种情况往往就是崩溃掉,丢失 Queue 里的所有任务。

对于 Queue 系统还有一样需要考虑的就是并发性。如果流量增长过快,需要考虑的是要增加更多 Queue Master节点,以及更多的 Worker 来处理。这些问题都需要大量人力来维护。

随后我们还是投靠了 SQS 服务。Master 的所有问题都交给了 AWS 来解决。偶尔遇上线上故障也会有积累几千万个任务的时候,但是不需要考虑存储和Master节点的可用性,一切都很平稳,数据也没有丢失过。使用 Autoscaling 也可以很好的实时增加 Worker 数量,保证任务处理可以跟得上。

唯一的缺点就是 SQS 的时序性稍差。当然这一点也可以在应用层加以处理,避免时序错乱问题。

4. OnDemand -> Spot

AWS 的 Instance 有 OnDemand 和 Spot 两种类别。区别在于 OnDemand 比较贵,Spot很便宜但是可能随时被关掉。然而实际上给一个很好的bid price,Spot是可以开很久很久的。通过做好现成的 AMI,然后用 Spot 方式动态启动服务器,可以将各个时段不均匀的访问导致的开销降到最低。比如定时在访问量最大的时候多开几台,然后在大家睡觉的时候再关掉。不管是什么服务器能提供多好的 Availability 和 Scalability,它的最关键的分母还是 Cost。使劲花钱用最豪华的配置搭一个稳定服务,只是看上去很美,所有人都会。而 Spot 可以让我们用最好的性价比,搭出优良的在线服务来。

最后

总之,AWS 使我们从后端的海量运维工作和底层框架搭建工作中解脱了出来,让我们有更多的精力处理上层业务逻辑和算法。另外,充分利用 Spot Instance 也使得我们的服务器成本非常的低廉。目前我们有 5台c1.xlarge做为广告服务的前端处理Web请求,5台m1.xlarge做为广告服务的Worker。除掉静态请求统统走 CDN CloudFront 之外,动态请求的平均响应延迟是 13毫秒,日均访问量是亿量级。服务器负载都在 <1 以内。