- 解放前蒋介石居然要暗杀张学良,这样的历史掌故可发一笑。果然是任人打扮的小姑娘。揭秘:国民党在大陆最后暗杀名单 令毛人凤震惊 (2016-06-03)
- 读杰克伦敦的《海狼》,感觉有作者自己的影子在里面。(2016-06-07)
- 唐德刚认为近代中国只有两个半外交家:一为李鸿章,一为周恩来,半个是顾维钧。基辛格则是被周氏操弄于股掌中,等而下之的人物。按唐氏标准,整个世界也不见得有几个可称为外交家。(2016-06-14)
- 皇室战争中,若等级相差太远,防守方后发制人成功率更高。(2016-06-15)
- 计划在Ardb里增加两个功能:一为cluster,实现或者基于zookeeper或参考redis;二为graph,实现参考cayley. 两者都是考虑已久的,不过都属相当复杂的功能,而且前者尚未设计定型,具体实现遥遥无期。不过下月可能空闲时间较多,优先考虑实现cluster部分。(2016-06-20)
- 360公开了一个兼容redis的pika,看了下文档,粗略看了下代码,几个看法:
- 一个比较有意思的地方:加上版本号用以快速的删除大量key/value对。 这个可能是双刃剑:删除某个较大的hash/set/list/zset是很快。不过当重复删除修改同一个hash/set/list/zset时,读取这个key理论上会很慢,因为key/value并未被删除,只是迭代读取过程中根据版本号过滤而已。 我在rocksdb的facebook group里提过一个DelPrefix需求,据说可能会在后续版本实现,理论上在rocksdb内部实现会更加高效,且不存在前述问题。
- 仍然存在大量和redis冲突或者不一致的地方,文档里号称不用修改应用层代码即可迁移,其实指的是要详细阅读文档以及代码后,如果不冲突则可以迁移。
- 感觉实现过于复杂,分成三四个项目,代码调用层次比较深(大部分C++项目通病),过度模块化了;这样的话,外部人员其实很难参与进来,至多只是周边一些日志,typo修改而已
- 锁粒度细化到了key级别,和ardb一样;其它的几个基于leveldb/rocksdb的实现都没做到。
- 直接修改了rocksdb代码实现某些功能。这种做法也是双刃剑,改动太多的话,社区的一些修改是很难merge进来的。
- “碧海青天夜夜心”
- 本厂的管理相当初级,仍然存在大量因人设事,因人废事的情况,人走代码废屡见不鲜。比较好奇本厂的代码平均寿命是多少,感觉比鹅厂的要少。可惜了两年余写的十余万行代码。(2016-06-25)
- 花了两天读完《万历十五年》,对万历帝的固有印象(基本负面)改变很多。说来对万历的这些印象还是大学时看过的一本《张居正》的小说得来。(2016-06-26)
- 金圣叹评水浒,列举了很多作文之法,如草蛇灰线等等;后来红楼梦里也大量应用,可见自古已有比较成熟的小说作法。(2016-06-27)
- 装修基本结束,花费甚多,费神更多。据说日本,美国这些行业均已标准化,不知在本国要花费多长时间才能达到友邦的程度。(2016-06-28)
- 跳槽:现东家马上成前东家,前东家马上成现东家。文雅点说是“前度刘郎今又来”,粗俗点是“胡汉三又回来了”。尝下回头草是啥滋味。说来讨价还价还是不在行,面皮甚薄,不善讨论“阿堵物”。(2016-06-30)
Ardb内部编解码格式
在Ardb的设计中, 编解码层是一个很重要的环节。编解码层的存在, 屏蔽了各种kv存储实现的不同,可以在任意一个简单的kv存储引擎上, 封装实现string, hash, list, set, sorted set等复杂类型的数据结构。这里简单介绍下Ardb中的编解码层的设计实现。
Overview
首先,有这样的设计约定:
- 所有的数据结构,都可以被一对或者多对简单key-value表示
- 每种数据结构,至少包含一个元信息key-value对(meta),用于保存额外的信息(db,类型,expire时间等);如hash、set、list、sorted set等复杂结构均是每个key对应有一个meta
内部Key的格式
对于所有的Key, 包含同样的前缀,编码格式定义如下:
[<namespace>] <key> <type> <element...>
Note: namespace 为可选部分。
杂感之五
- 政策与既得利益权贵之无耻,可见一斑 —— 央行放松限贷有感
- “肉食者鄙”
- 现在一些开源项目上来就号称全面替代xx, 是xx的killer,也给出一个漂亮的benchamrk对比图,不过在实际环境中表现却是惨不忍睹,中外皆有
- “一生大笑能几回,斗酒相逢须醉倒”
- 《饥饿游戏》小说的翻译也是糟糕无比
- 孤陋寡闻,直到今天才知道“带鱼”另有它解, 再次感叹中文之博大精深,诸多隐语遁词,方法大约是从史书里的春秋笔法一脉相承而来
- 方舟子貌似会以极快的速度成为twitter第一大V
- 读唐史,“牛李党争”中,对李德裕的评价更高一些
- 唐末,宦官擅权远比东汉末年以及明代为甚,甚至到了多次弑君,废立自如的地步;小说演义却很少描述这一点
- 俄国叶卡捷宁娜女皇时代,波将金亲王为了使女皇对其领地的富足留下深刻映像,在女皇经过的道路上建造了一些假村庄,史称“波将金化”。在中国也有类似的行为艺术,更早的有隋炀帝的丝绸缠树,往后则更是不胜枚举。在所有的以媚上为目的手段的社会,这种行为是永远禁而不止的。
- 秦昭王时的丞相范睢提出的”远交近攻“可能是中国历史乃至世界历史上第一个外交战略。
- 维特根斯坦和希特勒是中学同学,这倒是个有趣的历史片段
- 对一个正题及其反题同时予以证明,然而却都成立的现象,谓之”二律背反“,由康德提出。针对这类问题,如果一方坚称唯有自己是真理的情况下,就非常值得警惕了。如中世纪基督教的“上帝万能论”,以及政治课本中的部分结论
- 权力不被利用与操纵的可能性为零
- 硕鼠不见人犬之忧
- 历史上的一些名人在微时,与显贵”扪虱对谈“足以显得豁达,不卑不亢,如王猛对桓温“扪虱对谈”则成了千古美谈;而发迹之后若仍如此,则显得倨傲无礼,如司马迁很鄙视刘邦的类似行为,借郦食其,萧何之口批评了一下。也许两种情况兼而有之的原因,是以斯诺记载的我朝太祖的类似行为就没有特别地广而告之。
- 搬家时不知道怎么找到一本冯唐的书, 随手翻了下,有几个感觉:一是其人作文喜欢往“脐下三寸”走;二是文风也相当造作,故作洒脱;三是其人对于文学有一定见解;四是这个人最好继续做商人
- 冯唐不是”冯唐易老”的冯唐
GScan:一个Google HTTPS IP可用性扫描工具
前几天接触了解websocket时,顺便试了下之前写过的代理工具gsnova,发现几乎不能用了,究其原因,则是Google的IP大批被封锁,但仍有部分可用的IP,不过需要自行查找测试,手工测试比较繁琐;有一个GoGoTester工具做了自动化搜索测试的工作,内置了大量的IP,很不错。不过还有一些缺陷,比如缺少证书检测,性能上也需要优化,默认只启动5个线程?
另外有一些Hosts工具,比如smarthosts, 最近可能也多是Google的IP被封锁原因,加上Google自身的部署调整,很多IP有问题,比如默认的google搜索访问就有404的问题,看了下smarthosts生成hosts的脚本,也是在可访问性上检测不够,只检测了是否能连接,对404之类错误则没有任何检测
对于此类的工具,我另外还有自己的一些想法,所以国庆花了两天时间粗略实现了一个基于IP段的扫描工具gscan,整合实现这两类功能,顺便也熟悉下来近两年没碰过的golang。
完成后测试了下实际使用效果,看起来还不错,Go的性能这两年看起来提升不少,用GoGoTester内置的所有IP段随机扫描可用HTTPS的Google IP, 100个goroutine工作,ThinkPad X230笔记本上大约平均每秒能扫描100个IP上下,内存占用不到10M,CPU占用15%上下。
gscan的相关说明在github上, 地址https://github.com/yinqiwen/gscan
后记:golang这两年语法没什么变化,看了下go的release notes, 大部分还是库,GC,编译器层面的改进, 周边的IDE工具(开源、商业)支持还是不多, GoClipse一如既往的难用。 另外发现一条新闻说是Go在1.4会官方支持Android开发,这个比较令人兴奋,也许可以把gsnova移植到Android上。
利用Ardb/Redis构建基于位置实时服务
Ardb早在半年前的0.7.0版本就已经具备了二维空间数据的存储/查询的能力;基于此能力,可以构建基于位置实时服务, 比如实时查找附近的地理位置,附近的人等LBS类型服务。以下介绍Ardb中空间索引的实现原理以及如何使用。
原理
Ardb中的二维空间索引实现从原理上说,可以简化为GeoHash + Sorted Set。 在比较早的时候写过一篇英文原理介绍在这里, 这里用中文再介绍一次。
所谓二维空间索引, 就是对二维空间数据建立索引, 通常key-value形式的存储只能存储一维的数据, 针对二维数据, 就需要做降维处理。降维的方法有很多种,Ardb中采用的是成熟的GeoHash。 GeoHash是一种对经纬度进行编码的实现,利用GeoHash可以将二维的坐标编码成一维的数据, 如字符串。这样,我们就可以将二维的坐标作为索引的key保存了。
大部分的GeoHash实现都是将二维的坐标编码编码为Base32的字符串, 这种结果不适用于Sorted Set(只支持double类型的score),另外也存在精度问题。 由于Base32字符串中一个字符代表5个bit,和GeoHash编码步骤每次产生2bit不匹配,当Base32字符串长度为奇数时,此GeoHash值代表一个长宽不相等的矩形,这个对于计算半径精度误差较大。 此外,由于一个字符代表5个bit,意味着增加/减少位置精度需要每5bit增减,这对于范围查询时,存在较大的浪费。
我另外参考GeoHash原理写了另外一个GeoHash-Int库, 只生成64bit integer结果,每增加/减少位置精度只需要2bit增减。
关于GeoHash于GeoHash-Int的详细介绍,可以参考这篇文章GeoHash介绍与改进的GeoHash-Int.
关于Redis的Sorted Set, 可以暂时理解为一个排序的集合。 由于GeoHash有一个特点,相近的坐标的GeoHash值有很大几率非常接近,从属于同一个GeoHash编码区域,即使在边缘情况不相邻下,也可以通过通过查找邻居的方法找到所在GeoHash编码区域。 我们可以将GeoHash值作为score,坐标点的名称作为value存储到一个sorted set中。 这样,在查找相近坐标时,可以利用Sorted Set的ZRANGEBYSCORE
方法找到相近的指定范围的坐标集合。
以下介绍在Ardb中的具体实现与相关协议命令。
杂感之四
- 古龙之《七种武器》水准排名,多情环 = 离别钩 > 孔雀翎 > 碧玉刀 > 长生剑 > 霸王枪; 似乎结局愈惨我才觉得更触动人心
- 如隔云端
- 阿布特说:“电一来,灯一亮,工人们便一骨碌爬起来,操作一两个小时的机器,直到下一次停电。” ——《外媒:朝鲜人其实跟别国人一样》
- “中秋谁与共孤光,把盏凄凉北望。”, 国庆亦然。
- Facebook的RocksDB的bug也不少,有些还是很初级的问题;最近就发现了两个,提了一个bug加一个PR
- 《马丁伊登》里, 马丁最后用特殊的方式了结了自己;现实里,杰克伦敦也自己了断了自己。杰克伦敦在《马丁伊登》里极为推崇社会达尔文主义,在现代中国可能会更适应一些。
- 魏氏春秋曰: 成济兄弟不即伏罪,袒而升屋,醜言悖慢。自下射之,乃殪。 身为棋子却承担太大责任的后果,可能一步登天,可能万劫不复
- 三国后期淮南三叛之时,只有吴国协助, 未见有蜀国任何动作,当是蜀国比较大的战略失误, 当此时已离蜀汉灭亡不远了
- Raft, 号称比paxos更简单,后面还是要花一定时间深入理解下(不过计划在Ardb里引入的集群支持还是会采用zookeeper这个更成熟的paxos实现,毕竟了解的更多一些)
- 冰塞黄河,雪满太行,梦里乘舟
- 雍和宫里有个殿内门口有两条“地狱犬”的塑像,口鼻之中都被游客塞满了纸币硬币,模样殊为可笑;中国人在佛教的地方似乎很喜欢类似的行为。
- 国子监博物馆里看到一则介绍:清朝时科举增加了官、民分卷法, 据说是为了避免官宦出身的占了太多科举名额。抑制不平等有很多办法,就看是否有决心执行了,还有很多地方,今不如古。
- 清朝时科举增加了官、民分卷法是为了抑制官宦出身的占科举名额太多; 如今高考分省卷目的却是相反
- “长恨人心不如水, 等闲平地起波澜”
快速Interleaving bits
昨天在reddit上提交了geohash-int , 引来了一些讨论, 其中一位外国朋友Steve132给出了一个更快的实现, 虽然里面有些较低级bug,但修改编译后,简单测试了下,100万次encode/decode性能提升了6倍之多,耗时统计如下:
Cost 425ms to encode
Cost 75ms to fast encode
Cost 671ms to fast decode
Cost 98ms to fast decode
GeoHash encode/decode算法中一个关键步骤是Interleaving bits(位交错运算?可能需要更好的翻译), 大致相当于将一个64bit的int,按二进制位将此int拆分为两个32bit的int, 其中偶数位的为一个, 奇数位的二进制位为另一个。 Steve132给出的实现主要就是优化这一个操作。 原来我的做法是老老实实做位偏移合并运算,算法复杂度为O(N), 其总N为二进制位个数。
Ardb-RocksDB的一些生产环境实践总结
部署运营情况
Ardb(RocksDB)目前在生产环境中是作为一个在线推荐/查询系统的存储服务部署,持续运行了约半年,相关的一些运营情况
- 1T SSD机器,主从互备
- 共存储约450GB的原始数据(integer变长存储,snappy压缩并compact后120GB),每天约更新150GB的数据(存放到redis同样结构,大约700G内存占用)
- 最大写入qps为20000(Ardb配置中限制), 大多为hmset,sadd,geoadd,zrem,del等写/删除命令;写入数据由后台例行任务调用redis命令
- 峰值查询qps在2000以上, 平均则近600, 查询命令多为hgetall, smembers, geosearch
- 查询平均延迟不到1ms,准确说0.3ms左右
杂感之三
- 尝试了PyCharm半个小时,最后还是回退到了Eclipse上;在两个IDE间来回切换还是颇为折腾的;
- 仍然用sourceinsight写代码的,多半还是代码写的不够多, 尤其是用来写C/C++/Java
- 尚记得7,8年在H公司工作之时,sourceinsight版本就已经是3.5了, 今日一瞅仍是3.5; 这个和最近关于PHP版本的调侃有相近之处
- Replication is difficult, distribution/cluster is much more difficult.
- 鲁迅有一篇《豪语的折扣》中提到中国人有故作豪语的习惯,不独文人,连市井人物吵架都会见到。今天外出就遇见一个样例。
- 古之豪语之一:“仰天大笑出门去,我辈岂是蓬蒿人”
- 安庆绪杀安禄山;史思明杀安庆绪;史朝义杀史思明。 安史之乱中安史自乱。
- Y君自比黄鹄而待举
- 《银河系漫游指南》译文不忍卒读,当是译者之过;《冰与火之歌》则是正面典型
- 在考虑是否重新拾起Go语言,看起来1.3比1.1改进不少
- 《浮生六记》只有四记。 “世事一场大梦,人生几度秋凉”。
一种基于Redis/Ardb的混合部署存储方案
考虑这样一种场景:每天有较多的数据更新,也有较多的数据被访问;从一个时间段总体看来,某份数据只在一定时间段内会被频繁访问,超过这个时间就极少被访问,这样的数据比率占到绝大部分。
例如网站统计数据就与这种场景类似,只有当天的统计数据会被更新,只有最近7天(或30天)的数据有较大可能会被访问到,极少有人会主动访问历史数据。可以参考下百度统计,CNZZ, GA等系统的数据。
针对类似数据存储场景, 我们可以构建一个Redis为Master, Ardb为Slave的存储系统。Ardb需要更改两项默认配置为’yes’:
slave-ignore-expire yes
slave-ignore-del yes
前端应用层写入数据只写入到Redis,每更新一次数据,设置expire时间为7天(或30天,自行控制);该数据会被同步至Ardb, 同时被忽略掉expire设置; 另外由于Redis的expire机制是当expire触发时,redis生成一个’del’命令同步至slave, 所以Ardb slave也需要忽略del命令已保证数据不丢失。 伪码逻辑如下:
redis.Set(key, value)
redis.Expire(key, 7*24*3600) //expired after 7day