地球上的骨干网带宽真便宜啊

Tinet: $1/Mbps/month (到中国好,其它特点不太了解)
He.net: $1/Mbps/month (到全球基本说得过去吧)
NTT: $1/Mbps/month (日本)
Level3: $1.3/Mbps/month
Telia: $1.3/Mbps/month (欧洲)

当然,中国是排除在外的。(1000RMB/Mbps/month = $157/Mbps/month)

关于如何破除电信、联通的垄断,我刚刚想了这样一个办法

A去部署和经营一个全国性骨干网。其实一开始只覆盖大城市也好。

之后开始向那些大城市里的接入商出售骨干网接入服务。很多大城市都有区域性接入商,比如成都、杭州、北京、上海。同时向大城市的数据中心出售接入服务。

比如可以免费半年之类的。但本文完全不考虑成本问题。因为假定骨干网运营成本不会比电信、联通更高,因为他们的运营成本包括最后一公里的成本。

当然要注意做好两个措施:

  1. 跟地域性接入商签订消费者质量保障协议,要求接入商不得限制从骨干流入接入商的带宽。(不得oversale来自本骨干的带宽的意思),并保留因接入商接入带宽质量不好而随时终止提供带宽的权利;
  2. 对来自数据中心的流入带宽做好合理分配,避免配额超出骨干运行能力。

最重要的一点是:在免费服务结束后后,无论是最终用户接入的价格还是数据中心的接入价格一定要比电信便宜!

我们知道,目前电信、联通的状况是:

  1. 自建的骨干越来越支持不住自己的最终用户的正常上网流量。在光进铜退提高最终用户接入速度大跃进后必然更加糟糕。
    • 因此他们绝对不会降低数据中心接入带宽的价格。否则其骨干网根本撑不住,沦为一个劣质网络。
  2. 电信、联通垄断地位的基础是庞大的最终用户数量。
    • 其垄断和打击最终用户接入市场竞争对手的基础在于庞大的接入数量,故其断然不可能向地域性接入商提供低价的接入。
  3. 电信、联通抵抗其它骨干网运行商的法宝是1000元/M/月的昂贵接入费用。并给数据中心提供更低的接入费用,借此牢牢捆住数据制造者,也就是各种网站,尤其是小型网站。并且目前绝大多数数据中心都是电信、联通建设,缺少第三方独立建设的数据中心,另外可能对于这种第三方数据中心,电信、联通也有不同程度的价格歧视。

1、2对于A来说,都是绝对有利的竞争条件。最重要的问题是,A是否能成功破除中国的互联网市场的垄断性。(所谓垄断这里认为是定价权被某一方或者某个托拉斯掌握)

A必须同时接入一定规模的最终用户和数据中心,并且最离不开的是数据中心。

因为A通过更低的最终用户接入价格,成功得通过价格和网络质量将其最终用户接入业务包给了一些大城市内的最终用户接入商。并且由于价格的低廉性,凡是通过A的骨干网发送给其最终用户的流量,都会取代相同大小的电信、联通发送给其最终用户的流量,对接入商来说是绝对的好事。因此,A接入的数据中心越多,对整个市场,也包括A就越有利。

但问题也出在数据中心,在上面的3这个因素的作用下,电信、联通一定会其自有的数据中心向A或者A的数据中心用户收取极高的“进楼费”。而A自建数据中心,电信、联通一定不肯卖带宽给A。虽然我相信聪明的中国人一定能想出破解的办法,比如增加一个中间环节。但是没有一个简明正确的理论,最终还是难以迅速铺开,以改变现有市场生态。

不过对于已有的第三方数据中心,更便宜的骨干带宽一定是一件共赢的事情,这个与接入商是同理的。

总结一下我的思路和关键点:避免恶性竞争和保持物种多样性的最好办法是增加专一食物动物的比例、减少杂食动物的比例。于是欢迎讨论和设计更好的解决办法。

vaapi g45-h264 is still not usable

To install it, run

git clone cgit.freedesktop.org/vaapi/intel-driver/ -b g45-h264

then build the source and copy the *.so into the correct location.

But after installation, test it by [QYQ][BDrip][AIR][OP_Longver.A][AVC_FLAC][3769CFBF].mkv you may find it’s too slow to play. And black blocks occasional appears when it’s playing.

`mplayer2 -vc ffh264 -lavdopts threads=2 -benchmark -nosound` takes 104.122s to decode;
`mplayer-vaapi -benchmark -nosound` takes 196.749s.

But the total length of the video is only 201s.

unbound模块简要说明

unbound是一个DNS递归解析服务程序,支持DNSSEC、Caching以及pymod扩展。

pymod的链接包含了pymod的基本介绍和一些用pymod实现的小玩具。由于之前用python-libunbound时候被略坑了一下,并且在pythonmod/examples/resip.py中看到了这段话:

# Please note that if this module blocks, by moving to the validator
# to validate or iterator to lookup or spawn a subquery to look up,
# then, other incoming queries are queued up onto this module and
# all of them receive the same reply.
# You can inspect the cache.

由于我的模块有网络操作,必须写成async的或者只能在这里block,我不得不从C代码中寻找我需要的东西。

unbound模块的基本介绍在这里:http://unbound.net/documentation/pythonmod/examples/example0.html。阅读这里可以了解unbound module的大概。我在这里补充一些不可或缺的细节。

可用的模块列表被hardcoded到了services/modstack.c中,初始化检查合法性时会用到util/fptr_wlist.c中的函数。需要手工patch。

模块需要提供这些函数和一个static struct module_func_block yourmodule_block

/**
* Module functionality block
*/
struct module_func_block {
/** text string name of module */
const char* name;

/**
* init the module. Called once for the global state.
* This is the place to apply settings from the config file.
* @param env: module environment.
* @param id: module id number.
* return: 0 on error
*/
int (*init)(struct module_env* env, int id);

/**
* de-init, delete, the module. Called once for the global state.
* @param env: module environment.
* @param id: module id number.
*/
void (*deinit)(struct module_env* env, int id);

/**
* accept a new query, or work further on existing query.
* Changes the qstate->ext_state to be correct on exit.
* @param ev: event that causes the module state machine to
* (re-)activate.
* @param qstate: the query state.
* Note that this method is not allowed to change the
* query state 'identity', that is query info, qflags,
* and priming status.
* Attach a subquery to get results to a different query.
* @param id: module id number that operate() is called on.
* @param outbound: if not NULL this event is due to the reply/timeout
* or error on this outbound query.
* @return: if at exit the ext_state is:
* o wait_module: next module is started. (with pass event).
* o error or finished: previous module is resumed.
* o otherwise it waits until that event happens (assumes
* the service routine to make subrequest or send message
* have been called.
*/
void (*operate)(struct module_qstate* qstate, enum module_ev event,
int id, struct outbound_entry* outbound);

/**
* inform super querystate about the results from this subquerystate.
* Is called when the querystate is finished.
* @param qstate: the query state that is finished.
* Examine return_rcode and return_reply in the qstate.
* @param id: module id for this module.
* This coincides with the current module for the super qstate.
* @param super: the super querystate that needs to be informed.
*/
void (*inform_super)(struct module_qstate* qstate, int id,
struct module_qstate* super);

/**
* clear module specific data
*/
void (*clear)(struct module_qstate* qstate, int id);

/**
* How much memory is the module specific data using.
* @param env: module environment.
* @param id: the module id.
* @return the number of bytes that are alloced.
*/
size_t (*get_mem)(struct module_env* env, int id);
};

这里对函数的行为解释得差不多了。init()deinit()是模块全局初始化用的;operate()inform_super()clear()是在处理每个query中用的。我来说明一下struct module_envstruct module_qstate等。

在使用中其实module_env只会被创建一个,所有module的所有这些函数被传入的参数中的env都是它,env->modinfo[id]void *类型,是存放全局module信息的指针。指针的值由module在init()时候设置,这个指针指向的内存由init()自行malloc()deinit()free()get_mem()函数用来计算并返回这些东西的大小。

struct module_qstate是对每个询问创建的一个context,每个询问被创建后会按照module的顺序进行执行。计算一个query的结果时,程序自己可能需要创建一个subquery,subquery则又会对应一个独立的struct module_qstate

struct module_qstate中保存了询问相关信息、一些全局信息、模块相关信息还有一些会用到的函数指针。其中minfo[id]用来给module存放模块跟当前qstate相关的信息。ext_state[id]存放模块在处理这个query时的执行状态信息。模块执行状态信息是enum module_ext_state,包含:

/** initial state - new query */
module_state_initial = 0,
/** waiting for reply to outgoing network query */
module_wait_reply,
/** module is waiting for another module */
module_wait_module,
/** module is waiting for another module; that other is restarted */
module_restart_next,
/** module is waiting for sub-query */
module_wait_subquery,
/** module could not finish the query */
module_error,
/** module is finished with query */
module_finished

module的ext_state应该在operate()中设置,operate()会被unbound调用多次,分阶段完成module执行。如果module进行了外部询问,则应设置状态为wait_reply;如果将任务交给了下级,则应设置状态wait_module;如果生成了一个subquery,需要等待它的结果,则应设置wait_subqueryrestart_next比较特殊,一般当它下级的module跑挂了(module_error或者没给满意的结果)之后,当前module可以选择重启下级,此后下级会先被调用一次clear(),再被调用operate()重新来过。operate()会在外部请求被回答、subquery完成、下级module执行完成(errorfinished)后被调用以继续完成module的任务。

operate()被调用时,参数event用来传递被调用的原因:

enum module_ev {
/** new query */
module_event_new = 0,
/** query passed by other module */
module_event_pass,
/** reply inbound from server */
module_event_reply,
/** no reply, timeout or other error */
module_event_noreply,
/** reply is there, but capitalisation check failed */
module_event_capsfail,
/** next module is done, and its reply is awaiting you */
module_event_moddone,
/** error */
module_event_error
};

其中replynoreplycapsfail都是向外进行的询问被回答时传递的,moddonepass比较明显。noreplyreply都是字面意思,reply了空也算replycapsfail是说虽然有reply,但是这个reply是攻击者伪造的而非被询问者的回复。

caps是指Capitalisation randomisation,又叫dns0x20。是通过改变请求的大小写增加随机性避免暴力投毒的办法。穷举所有一般只要2^30。通过这个再增加8bits(平均)的安全性…

module的clear()inform_super()的注释解释得不太具体。

clear()通常用来清除qstate相关的module数据(一般只用清理minfo[id])。这里比较特殊,module在处理query时,请求内存应该用regional_alloc()函数,具体可参考iterator/iterator.c:iter_new(),被regional_alloc()的内存无须手工释放,它会在query的计算结束时自动被释放。因此clear()最多只需要把minfo[id]重设为NULL

inform_super()在两种情况下会被调用:subquery的计算结束、subquery由于计算时间太长被程序终止。此时父query的当前模块的inform_super()函数会被调用。看名字会误以为是subquery的某个模块的inform_super()被调用。之后父query会被设置为可执行,因此不必在此时进行operate()。我不知道为什么unbound要把inform_super()分开而不是在operate()时像外界询问被回复后传递outbound_entry一样把subquery作为附加参数一起传递进来,这样inform_super()就根本不需要了。

最后,模块执行时创建subquery和创建外部询问的方法可以分别参考validatorator.c:generate_request()ititerator.c:processQueryTargets()最后几行。

被我坑了一年半的项目pfdns,终于有望在今年写出来了

项目的地址在http://code.google.com/p/pfdns/,是给多线的网络设计的DNS。提出这个设想的背景自然是跟VPN有关。

虽然说既然是多线网络,路由表配置好了的话,也应该差不多好使了。过度蛋疼是不必要的。很多时候,选择dns的结果只是为了节省VPN流量和降低网络延时。

说说在教育网,大体上需要一个怎样的pfdns:

  • 尽可能把图片、视频、下载、门户流量弄到教育网,如果他们有针对教育网的解析的话,不然延时就要命了,用户受不了
  • 对于google等到处做了cdn的国际大站,不能解析到香港去,要用湾区的解析结果,这样从VPN出来只要不到10ms,各种有保证。
  • 接下来就是策略性的了,偏向电信还是偏向联通。比如北大到电信好,以及设想pfdns的时候清华到联通还挺好的。所以对北大来的询问返回偏向电信的好,对清华偏向联通不错(已经不成立了)。

不过说到DNS的解决方案,由于pfdns被我自己坑了这么久,我在做电信+VPN解析或者联通+VPN解析的时候,没有沿用教育网的思路。而是对解析用了中国内、中国外的分割方法,设定bind的路由表,让它递归解析。询问中国的权威时,使用电信/联通的地址,而询问国外时,通过VPN。这是基于假设有愿望做国内智能解析的网站,基本上会把权威放到国内的。这个方法实践效果其实我挺满意的。

对教育网,是不能用这个方法的。一来,我没有一个能访问整个国内IP范围的教育网的机器。二来,不少国内的智能解析服务商十分不靠谱(是基本没一个靠谱),给清华IP(有时候清华IP并不被认为是教育网IP,因为whois……)的解析结果经常会出乎意料。就算给的结果正确,也总有这种情况发生:似乎外界都认为联通到教育网挺好的,所以给教育网的解析IP就是联通IP。而这并不是我想得到的结果。三就是虽然都是教育网,每个学校的网络不怎么一样的,甚至很不一样。

DNS是很复杂的,这是我一直坑着pfdns的主要原因。加上以前写tcp的async server也写错过,最终写了一个无bug的后来也不想用。作为懒人我看了看libex,文档有一部分没有看懂,使用它干活还算可以接受吧。总之觉得自己写网络通信什么的有点烦,UDP什么的还要recvmsg去看IP_PKTINFO。

最近看wikipedia的DNS服务器对比列表的时候,发现libunbound(虽然很早就知道unbound,且机器上一直装着libldns-dev)支持async得解析,并且意外发现unbound有一个叫做pymod的模块可以让用户根据需求编辑递归resolver解析的结果。

虽然文档不怎么详细,demo没告诉我我能做的所有事情。看了看代码我觉得unbound的模块和状态机设计应该可以让我完成我想做的事情。另外这几天用libunbound-python写了一下async的解析,对每个域名同时问几个upstream的DNS,最终根据它们的结果选择到底使用哪个结果。只可惜用python的binding无法把answer_packet拿出来,只好写C了。

回转企鹅罐 ED3

一直想在正式的场合(blog)表现的很认真,但反而觉得每天在校内发GalGame截图和翻译的(在汉化组的)朋友、在打扮得很宅的blog上写下自己心情的朋友们很幸福。

前一段时间看到@virushuo关于博客和自我的观点,让我重拾wordpress写了一点东西,对我做了的事情聊作记录,毕竟连纪念都说不上。在我那快要被心因性遺忘失去并且不想找回来的大三大四之后,总想做点什么找回自我的事情。

说起来我不喜欢做VPN什么的。都只不过是我的死脑筋而已,我认为应该有的东西,没有的话我就要自己做出来它,而且它要足够reasonable。

晚上不知道怎么说起我想干什么,会这个多好啊,的,尽管说到爱好是不能当饭吃的,其实我想说有爱真好。世上太多美好的东西,向往但又一个也抓不住。

http://www.bilibili.tv/video/av153960/

所以我要把歌词抄下来。还不会日语就抄翻译过来。

无法传达的思念
被撕裂的羁绊
宛若一片空白
云朵静静流淌
灰色的星期三
来吧回想起来吧
那曾经闪耀的时刻
所有的一切如此耀眼
那坠入爱恋的时刻
来吧回想起来吧
那相思相爱的时刻
以无比认真的眼神
那互相凝望的时刻
来吧回想起来吧
那曾经闪耀的时刻
那与梦为伴的时刻
那相思相爱的时刻

配置owamp通过带外通信测量单向延时丢包信息

主机A到主机B之间有某条待测线路C<->D,其中A、B、C、D均为IP地址,A、B为公网地址,C、D为内网地址。C<->D线路上可能出现极端的丢包情况,也可能是某个单向出现问题,这时却因为owamp无法建立控制连接导致不能测量单向丢包。

owamp设计时是允许通过别的链路建立控制连接进行测量的。

owping的参数中,可以增加创建控制连接用的server地址。但是3.2rc4版本的实现中,在上述背景下,owping会通过A创建到B的控制连接,随后进行的是A和D这两个地址之间的单向延时丢包信息,不是C<->D。owping的-S选项在manpage中说会将本地socket绑定到指定的IP上,然而它会将控制连接和测试的本地IP都指定为源地址。此时,指定-S C后,C到B根本无法创建控制连接(公网、内网不互通),也无法正确测试C<->D的单向延时丢包信息。

为此我修改了owping的代码,将-S参数的作用仅仅限定为测试时使用这个本地地址,控制连接不绑定到本地IP。补丁见:owping.patch

在patch代码后,owping就是通过系统(自动使用地址A)创建到B的控制连接,再测量C<->D链路了。然而patch owping的代码仍然不能正确运行:为了防止owping被用来攻击,(B上运行的)owampd拒绝了测试IP(C)跟控制连接的客户端(A)不同的测试请求。

        /*
         * Check for possible DoS as advised in Section 7 of owdp
         * spec.
         * (control-client MUST be receiver if openmode.)
         */

阅读owamp/sapi.c可以发现,只要不是openmode,这种测量行为就被允许。

为此,只要对owpingowampd加上验证信息,并进行正确配置。

增加验证信息的方式十分简单:在B上执行pfstore -f /etc/owampd/owampd.pfs -n yangzhe输入密码即可创建yangzhe的认证信息。将owampd.pfsyangzhe这行复制到机器A的owampd.pfs中去。

owampd.limits中,还可以增加assign user yangzhe root取消用户yangzhe的流量限制。

在B上重启owampd后,在A上就可以通过owping -S C -i 0.001 -c 1000 -k /etc/owampd/owampd.pfs -u yangzhe D B以0.001秒的间隔来回发送1000个数据包对C<->D线路进行双向测试了,并且控制连接是在A、B间建立的,不用担心C<->D本身的不稳定造成无法测量。

owamp测量单向延时、丢包

中国互联网极其坑爹,在很多情况下,为了更加清楚地了解问题所在,需要对单向延时、丢包率进行测量。

owamp的网站地址在http://www.internet2.edu/performance/owamp/index.html。由于它是用来测量单向延时的,这要求两端的机器时钟必须同步。

时钟同步

服务器可以安装ntp进行时间同步。必须注意的是,为了得到精确时间,所选NTP服务器和本地服务器之间的延时应该对称的,也就是往返所需时间相等。另外NTP服务器和本地服务器之间的延时应该稳定,否则时钟会随时间漂移。

根据经验,即使在同一城市同一ISP,在一天之内延时都可能有1ms左右的波动。因此对NTP的精度要求在精确到若干毫秒就可以了。

在坑爹的中国网络中,寻找一个可以将本地时间同步精确到若干毫秒的NTP服务器难上加难。国家授时中心的NTP服务器尽管是多线路的,不受电信、联通难以互通之影响,然而电信和联通也不能保障从北京到用户所在地一天24小时内延时稳定。例如联通存在南北互通问题、电信存在“CHINANET核心压力很大”的问题。教育网的s2a.time.edu.cns2b.time.edu.cn跟标准时间相差340ms左右,也不可用。

我目前使用的NTP服务器分别是:

清华大学(北京教育网):ntp.cuhk.edu.hk的ipv6地址和ntp2.cuhk.edu.hk(ipv4)和另一个ipv6地址用来中转clock.isc.org //ipv6不稳定的学校例如北大、北邮就不必使用ntp.cuhk.edu.hk的ipv6地址了。即便清华ipv6目前没有问题也不能过于相信ipv6,首选ntp设置为了ntp2
上海片区电信:首先要确定本地到上海国际出口的延时是否稳定,在稳定的情况下,clock.isc.org可用。
联通:联通勉强可以用ntp2.cuhk.edu.hk,只不过联通到cuhk的延时有2ms左右的波动外加丢包。
美国:美国好啊,一般ISP都会提供ntp的,更别说各种机构了,并且一般延时稳定。我用的是clock.isc.orgntp.nasa.gov对比观察。

这套组合我验证过了在清华、美国、电信、联通的机器如此设置相互间的时钟相差在2ms以内。

其中ntp2.cuhk.edu.hkclock.isc.org基本无差别(小于0.5ms)、clock.isc.orgntp.nasa.gov有3ms左右的差别。

安装owamp

我的系统是Debian,目前还没有Debian安装包,因此要手动编译。configure时指定
./configure --prefix=/usr --exec-prefix=/usr --libexecdir=/usr/lib/owampd --sysconfdir=/etc/owampd --sharedstatedir=/var/lib --localstatedir=/var --mandir=/usr/share/man --infodir=/usr/share/info
安装后复制conf/目录中的owampd.confowampd.limits/etc/owampd/,并编辑owampd.conf中的datadir。(/var/lib/owampd/ ?)

启动owampd的命令行为owampd -c /etc/owampd -R /var/run/。可能要在运行owampd之前运行ntptime -N

处理owping数据

owping的运行参数设置为-i 0.001 -R -L 1较方便。

-R选项对应的输出格式是每行输出SEQNO SENDTIME SSYNC SERR RECVTIME RSYNC RERR TTL。其中TIME的格式是:高32位是从1900年1月1日到现在的秒数(不是Epoch time),低32位是纳秒数/10^9 * 2^32。

记录是按照收到回复的顺序排列的,最后会补上没有收到回复的记录并将RECVTIME标记为0。

增加、删除、修改RRD文件中的DS、RRA记录

最近想变更RRD的存储内容,再对RRA进行扩容,保存1年多的5分钟数据备查,却在rrdtool提供的action中找不到合适的方法。

用rrddump生成xml编辑后rrdrestore出来不失为一种办法,不过对扩容来说要生成过大的文本文件,并且脚本处理xml比较麻烦。

后来找到了perl Module RRD-Editor能完成这类任务。这个Module使用起来也很简便,例如我要修改前4个RRA的大小,删除后4个RRA(共8个),只要执行如下perl程序:

#!/usr/bin/env perl

use strict;
use RRD::Editor ();

if (@ARGV < 1) {
    print "USAGE: $0 <rrd file name>\n";
    exit 1;
}

my $rrd = RRD::Editor->new();
$rrd->open($ARGV[0]);

for (my $i = 4; $i < 8; ++$i) {
     $rrd->delete_RRA(4);
}

$rrd->resize_RRA(0, 105408);
$rrd->resize_RRA(1, 35136);
$rrd->resize_RRA(2, 8784);
$rrd->resize_RRA(3, 732);

$rrd->save();

活在错误的基础之上

很久很久以前我很鄙视写CSS这行,因为要应对各种浏览器bug。而且这行还缺人。因为是个人都需要至少半年学会,并且以后的工作全是重复。写浏览器的人总会希望,有那么一天,自己的浏览器没有bug了吧。如果这一天真的来了,那些写CSS的人是不是都可以去死了?

说到正题:教育网目前有多糟糕有目共睹,晚上到电信丢包10%。这简直就是没有人愿意花钱用的网络了(我指包月)。没有人愿意花钱,就没有钱用来改造,恶性循环。

接下来我们来比较清华和北大:清华绝对是个更官僚的地方。

北大为了改善上网环境,专门购买了电信通的500M光纤接入。其实价格也就一年50万多而已。平均到1万人,一人一年只有50元。得到的是在晚上网络使用高峰连接电信的速度仍然有200KB/s以上,经常可以达到500KB/s。

听说当年北大把每个月网费从5元涨到10元的时候还有学生群起抗议。在这点上我觉得聪明的独裁比乌合之众强不知道多少倍。比傻逼的官僚更不知道强多少倍。

以上是清华和教育网的错误。而我们每一个人,很不幸得活在这个错误之上。我,就更不幸得活在了一个更大的错误之上。还居然动过花3万一年从电信通搞个10M的微波接入到机房的念头。

再看电信通和北京联通:实际上这两个在北京恶评也不小。俩字“垄断”。你看10M的接入都3万一年。然而联通的20M FTTH虽然每个月只要不到600元,却只有部分地方可以接入。我们设想3年后,联通的北京网络改造完成,清华可以接入联通的光纤了(好吧就算清华你不接,我接可以了吧?),情况又是怎样?

 

Follow

Get every new post delivered to your Inbox.