etcd的discovery URL是怎么回事

今天玩 CoreOS,得知他们提供了一个 etcd discovery service https://discovery.etcd.io/new?size=初始数量

当足够数量的etcd按照这个URL相互发现之后,就能成功组成集群。

问题是:

这个数量是怎么被各个etcd知道的呢?搜了一些文章,也谈到了自建 discovery service的方法,但URL似乎都是/v2/keys/random_ID/_config/size 这样的,而不像 discovery.etcd.io 这样是 /random_ID 。不过后来试了试访问 https://discovery.etcd.io/random_ID/_config/size 发现能得到那个值,就明白了,这个网址其实有rewrite,把 /random_ID 给proxy_pass到后面etcd的/v2/keys/random_ID 了,让这个URL看起来更友好,但却更迷惑了。

参考资料:https://github.com/coreos/etcd/blob/master/discovery/discovery.go#L214-L217

Posted in 默认分类 | Tagged | Leave a comment

免签过境韩国、坐船去日本手记

我总有一种不愿意走回头路的情结,虽然给自己找了许多麻烦,依然乐此不疲。
这一次,经@tigerWu 提醒,我打算从韩国坐船去日本,以期获得一个日本的“上陆许可”。虽说日语里上陆就是入境的意思,但在汉语看来,有明确的从下到上的方向指示,也就是说得从海里上来才算。

去韩国驻华大使馆网站看看,中国公民持日本旅游非团体签证可以免签证过境韩国并给予30天入境期,查验标准是下一段“机票”。但我想坐船啊!那会不会是翻译有问题呢?要知道韩国大使馆上的汉语文件基本上行文都狗屁不通。再去看看韩国出入境管理局的网站,其英文版写了“flight ticket”。
这么看来是没戏了?我不甘心,就给“国民申闻鼓”写信,等不及回答又给出入境管理局的immigration contact center打电话,第一次问仁川机场进、釜山海港出,被拒了。不过比较有意思的是这个呼叫中心并不是直接做出行政解释,而是客人报告了自己的行程计划之后,她们代为向入境口岸当局咨询。考虑到中国对外国人的72小时免签证政策限定外国人不能离开口岸城市,我就尝试咨询釜山机场进、釜山口岸出,获得了允许,遂立刻买票,但为时已晚,只买到了没有头等舱的一架飞机的商务舱。(插播八卦:东航卖大韩航空的票比大韩自己卖的便宜)与此同时,我之前向韩国信访局“国民申闻鼓”递交的信访“是否可以空进海出,没指定具体口岸咨询”也收到了回答,我还到处求爷爷告奶奶找人翻译,后来发现其实有汉语翻译版的回答,就是:不限定转乘空路或海路。我把这一页打印出来了。

2月4日,大韩KE830,办理登机牌遇到了麻烦,地服代理请示大韩航空工作人员,我出示联程船票和信访记录之后拿到登机牌;中国边检出境,按规定应该查验联程客票,但都没理我就直接把中国出境章盖在了日本签证旁边。
到釜山机场,iPad丢了,于是落了单,在后面跟机组一起,机组走专用通道,我走外国乘客通道,是一位大妈入境官。入境官翻了半天,我主动提醒我是visa free transit资格,然后出示票。该女入境指着班次号问:这是flight吗?我说是ship,她拿不准,就问韩国人通道那个男入境官,然后我就被提到那个通道受审去了。因为JR九州beetle航运公司的船票确认页只写“釜山发”没说去哪儿,男入境官不能确认这是正确的票,我又重申了我从Busan international ferry
Terminal走,要去日本的Fukuoka,但他还是将信将疑,又问我是不是crew,我说不是之后,被拉出来去条凳上坐着(传说中的边检小黑屋?),入境现场指挥官,一位大妈过来问我,入境期间准备去哪儿玩,我说JSA(也就是板门店)她说板门店很远啊你知道吗,我说我做坐韩国高铁KTX,我有KR PASS,一种外国人专用的票。然后各位入境官扔下我不理,带着护照走了!!!这时船票在他们手里,信访函在我手里。过了一会儿,指挥官和男入境官把我带到入境通道,先盖章,然后手写了截止日期,又写了个不知道是TS还是TIS的字在入境章下面,这时还扣着,又说了我几句应该详细说明啊什么什么的,然后才用摄像头拍照,又说了我几句,最后主动和我握手,这事入境官的表情是很友好的。

2月8日,我提了行李到釜山火车站,经案内所工作人员指点,到站后去坐去往ferry的shuttle bus,但是没找到,只好打了个出租车去。一打吓一跳,原来google maps标的那个terminal现在已经不用了,新的在站后的左前方(东北),出租车到南边路口掉头从我到港口。巧的是,好像韩国人找零算法和美国人一样,出租车费2800、咖啡4800,我给整几千加三百,他们很难理解我是要一个500硬币找零。值得注意的是,港口的指示牌写boarding为“登机、搭乘”,写“便名”为“flight”,甚至有个指示牌写“快速船 登机口 flyer gate”我一直以为flight是飞机航班,而船班叫voyage呢!!

日本入境,边检极其顺利,其中问了我要去哪儿,我说福冈、仙台、东京,问我是飞过去吗,我说我有JR PASS,坐火车去,就给我贴了从海里上博多港陆地的“上陆许可”一枚,其实和上次大阪关西机场的只差下边的地名不一样。海关,又跟上次一样搜我的箱子,我长得有那么像走私犯吗?而且那个女关员还钓鱼执法,问我是不是住本地,我说不是啊我是中国人,然后就问那海关卡上那个地址是什么,我说那是hotel;然后又问我去哪些地方玩;最后甚至指着签证问这是什么,我说那是签证啊!!然后就过关了。他们是在考察什么?

结论:由于韩国出入境管理局各口岸部门执行政策不一致,目前这么走并不是一个很靠谱的方案,而且边检入境问话有时会有陷阱,比如问我是不是crew、问境内怎么交通之类的,稍有不慎就有可能被认为是有问题的。韩国边检把我扔在冷板凳好几分钟,谁知道是去打电话核实船票还是打电话请示政策去了……
《中国合伙人》教导我们:真实、自信、具体、合理,是签证的基本思想基本哲学,我的行程是真实的,就不怕核查、我的行程是符合信访回信解释的,也应该能进去。
不过我觉得,我得以自己的真实经历,去督促船运公司把票写清楚,不要只写起点站。

2月8日,写于博多

Posted in 默认分类 | Tagged , , , , | Leave a comment

Sentry整理杂记

本讨论均基于Sentry 7.7版本

插件机制

自带插件

src/sentry/plugins/ 每插件一个目录
自带插件loader:src/sentry/conf/server.py 里的 INSTALLED_APPS tuple
外装插件loader:utils/runner.py 里的 install_plugins()函数,对iter_entry_points()遍历并将其加入 INSTALLED_APPS tuple 中
外装插件注册:插件的 setup.py 里执行注册 entry_points 的过程:

例:https://github.com/getsentry/sentry-groveio/blob/master/setup.py
参考资料:https://pythonhosted.org/setuptools/pkg_resources.html

#!/usr/bin/env python
import pkg_resources

for ep in pkg_resources.iter_entry_points('sentry.apps'):
    print str(ep)

for ep in pkg_resources.iter_entry_points('sentry.plugins'):
    print str(ep)

sentry-jira 插件

插件基本配置

每 Project 分别配置,需要输入 jira 的 instance URL、用户名和密码。以上内容 base64 存在数据库 sentry_projectoptions 表里 where `key` like ‘jira%’
配置用户名密码之后,选择 Sentry project 关联到哪个 JIRA Project,保存设置,并 Enable Plugin 即可。

Due Date 问题

在 Sentry Event 页面右边点击 Create JIRA Issue 进入创建页面。但下面 Due Date 总提示 Operation value must be a string 。
经 tcpdump,插件发送格式为

"duedate": {"id": "2015-07-31"}

根据 /rest/api/2/issue/createmeta?projectKeys=<我们的KEY>&expand=projects.issuetypes.fields 的说明,duedate 的 schema 为

"duedate": {
    "hasDefaultValue": false,
    "name": "Due Date",
    "operations": [
        "set"
    ],
    "required": true,
    "schema": {
        "system": "duedate",
        "type": "date"
    }
}

根据网上流传的消息(https://answers.atlassian.com/questions/319018/jira-eclipse-mylyn-transition-fails-when-date-is-required-french-format#comment-319464),Jira期望的格式应该是

"duedate":"2014-07-23"

发送格式和期望格式的不同导致了无法创建 Issue。不过 sentry-jira 插件创建的内容是 id,而上述 bugreport 中是 name,也不太一样。
倒推检查插件源代码,发现从 Form 提交到 jira 客户端对象的数据就已经是u’duedate’: {‘id’: u’2015-07-31′} 了
sentry_jira:forms.py里

elif (schema.get("type") != "string"
  or schema.get("item") != "string"
  or schema.get("custom") == CUSTOM_FIELD_TYPES.get("select")):
    v = {"id": v}

这一段缺乏对 date 类型的 Jira 字段的特殊处理,导致前面多加了 id。
也就是说,如果不改 sentry-jira 插件,就无解。所以我提交了pull request https://github.com/thurloat/sentry-jira/pull/71
5日下午突然发现,目前线上 Sentry 6.4.4 的 duedate 显示为 django 的 SelectDateWidget,而不像我自己的测试装 Sentry 7.7 一样直接用文本框。经过仔细对比,发现服务器上的 sentry-jira 插件是修改过的版本,forms.py 文件class JIRAIssueForm 新增了一段

duedate = forms.DateField(
    label="duedate",
    #widget=adminwidgets.AdminDateWidget(),
    widget=SelectDateWidget(),
    initial=datetime.datetime.now(),
    #widget=DateWidget(usel10n=True)
    required=True
)

但这段代码没在公司的git库里保存。

SSO集成

厂家SSO讨论:https://github.com/getsentry/sentry/issues/1372
新版Sentry有 auth backend 基类https://github.com/getsentry/sentry/tree/master/src/sentry/auth/
SENTRY_FEATURES[‘organizations:sso’]改为 True 可以开启 Auth 页面,设置sso。
然后我就参考 sentry-sso-google 写了一个插件。

SENTRY_SINGLE_ORGANIZATION=True 会导致 /auth/login/ 跳转到 /auth/login/org_slug/ ,从而无法登录 非 SSO 的用户(如系统自带的名为 sentry 的超级用户)

Organizations

当 SENTRY_SINGLE_ORGANIZATION=False 时,utils/runner.py加载配置之后会将 SENTRY_FEATURES[‘organizations:create’] 强制改为 False,从而禁用了右上角新 创建 Organization 的“加号”链接。如果在此状态下删除了最后一个 Organization,则其中的  Team会变成游离状态,只能改掉参数重启服务重新创建了,而且重建之后某种情况下会导致游离状态的 Team 丢失。切记不要删除 Organization!!
根据 getsentry 原厂GH-1372号 issue,每个 Organization 只能开启一个 SSO AuthProvider

Posted in 默认分类 | Tagged , | Leave a comment

某种情况下PATH不生效的问题

今天遇到的情况,我同事在 virtualenv 里执行 gunicorn 运行 Django app,出来的 Django 错误信息却是 /usr/local/ 路径下面那套 Python 里的:

2015-09-18 15:32:47 [11538] [ERROR] Error handling request
Traceback (most recent call last):
File “/usr/local/lib/python2.7/dist-packages/gunicorn/workers/sync.py“, line 131, in handle_request
respiter = self.wsgi(environ, resp.start_response)
File “/usr/local/lib/python2.7/dist-packages/django/core/handlers/wsgi.py“, line 236, in __call__
self.load_middleware()
File “/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py“, line 57, in load_middleware
raise exceptions.ImproperlyConfigured(‘Middleware module “%s” does not define a “%s” class’ % (mw_module, mw_classname))
ImproperlyConfigured: Middleware module “django.contrib.auth.middleware” does not define a “SessionAuthenticationMiddleware” class

尝试 which gunicorn 返回结果是 virtualenv 里的那个 gunicorn;尝试 strace gunicorn 执行,却能正常执行。

我试了试,把 /usr/local/bin/gunicorn 的x权限取消,再让同事执行,就返回 Permission denied 说明执行的不是 Virtualenv 里的 gunicorn。改试 type gunicorn 返回结果:

gunicorn is hashed (/usr/local/bin/gunicorn)

目前尚不清楚是什么原因造成了该命令被 bash 给 hash 了。source virtualenv的 activate 命令的时候 hash 表会被清空的。

Posted in 默认分类 | Tagged , , | Leave a comment

Python import语句一处文档和行为不一致的问题

话说,我团运维组曾一度极为昌盛,可惜后来公司里有人搞政治,好好的一个组被拆成了好几个,后来竟分属不同大部门,工作关系也开始形同陌路。考虑到丰富经验,换换方向,今年7月,我转岗到了运维开发组,开始真正把Python作为职业。

无奈,基础差,还得学,8月18日,这么吉利的一天,我第n次在看Python的文档,看着看着,注意到一些标准库的名字是带点的,比如os.path,再比如logging.config等。然后就开始help各个模块,发现os.path的名字居然不叫path而是posixpath!!再看,logging是个package,但os居然是个module!!

于是,问题就来了:

Python语言里对 import A.B.C 这种形式是这么规定的:

when using syntax like import item.subitem.subsubitem, each item except for the last must be a package; the last item can be a module or a package but can’t be a class or function or variable defined in the previous item.

于是那就奇怪了,这个os既然不是package,怎么能 import os.path 呢?

本着技术事问咕果的原则,搜到这么一篇,其中提到,python在初始化时会加载一堆模块,其中就包括os,而os模块判断系统类型之后,选定了posixpath模块来配合工作,让它在本命名空间里叫path,还又把它以os.path的名字加入了sys.modules之中;待我执行import os.path时,import语句发现sys.modules里已经有了,于是直接做个symbol过来就了事。

本来事情到这里已经结束了。但是水木上有朋友在参与讨论的时候,为了说明上述其实是语言引擎的行为,而不是os的特殊性导致的,例子如下:

a.py文件:

import sys

import json as shit

sys.modules[‘a.shit’] = shit

然后从另一处import a.shit 居然也成功!

如果从a.py里去掉第三行,虽然import a.shit时会报告NameError: name ‘a’ is not defined,但sys.modules里已经出现了a,这说明a模块已经被import进来了!

 

如果说os.path含着金钥匙是因为它爸叫os,那a.shit又算老几,凭什么和os.path享受一样的待遇?

经过我精心构造的实验,不用a.py文件,而用一个空目录a代替,在python里import a.shit时,用strace偷偷的录下它的可耻行径,发现python居然先尝试找名为a的package(打开a目录找__init__.py)未果之后又尝试找各种形式文件名的名为a的module。

最后的结论是:虽然os.path它爸叫os,但其实即使它爸不叫os,也照样能成功import进来,根源在于import命令并不是像文档所说的,对 import A.B.C这种形式,坚持了A.B必须为package的原则,而是宽进(语言行为)严出(文档叙述),言行不一。

这样不好。

Posted in 默认分类 | Tagged , , | Leave a comment

我团年会2014

我是在2013年底开始接触这事的。当时钟sir找到我们组同事说想搞个直播,给来不了总部的同事们看;因为我和CDN服务商联系比较多,就把这活儿揽过来了。这期间经历了经费问题、场地和供应商考察、采购谈判、几轮试播(还发现了服务商的一次故障),直至最终正式播出。播放器设在一个限制了权限的wiki页里,由销售支持部在每个分支机构指定一名同事负责给大家播放。

2014年2月20日,我从IT部领了网线、NAT路由器、AP,从我们组拿了交换机,交付年会组待运。21日上午,我从五道口第一次用了快的打车,支付了一元钱到北京大学,以舞台旁边的机房为中心,向化妆室、百年讲堂前厅、观众席最后排分别拉了一条长线。下午,八台取票机运输到了前厅。22日上午,在化妆室安装了AP,在前厅安装了交换机,连接了取票机,在舞台机房安装了NAT路由器并把其放在音箱上用于覆盖观众区提供WiFi;直播服务商搭手把观众区网线贴在地上,并连接了视频信号开始上传。因为网线钳子的问题,取票机一直未能成功上网,一直到12点20分才修复,随后就开门放人进场,真的是好险。后来NAT掉地上了,导致观众区无WiFi,工作人员都没法上网了,于是把化妆室AP挪过来。

照例,签名照相,但今年的拍立得似乎有些感光不足。年会节目期间因为时常要开电脑检查直播情况,其实也没好好看。后来收到钟sir的通报感谢邮件,他老人家以为忘记写我了,又单独发邮件把直播这几个人夸了一通,哈哈哈。28日拷贝了原始录像,可以再回味一下。

我最喜欢的是西游那个小品,和《最初的梦想》歌曲连唱。

 

这一年,我团拥有了超过一半的市场占有率,八分之一的中国电影票房销售额,并开始扩展业务到酒店、外卖等。今天在微博看到“O2O行业今年将迎来决战之年,3大团购网都开展 年会KlCK OFF大会。美团的口号是"安心、成长平天下",点评的口号是"抢美团、争上市",糯米的囗号是"瓦解美团,立争第二",去哪儿口号是"全线抗美,誓死奋战",目前都在全力备战,面对众多对手,美团显得更加从容平静⋯⋯”,觉得真是有意思。团购已在身后,对手们还在抗美,我们已心怀天下了。

希望公司能保持目前的成绩,及时调整架构和业务形态,使之适应进一步商业斗争。我的工作虽和前线的业务形态关系不大,但仍要自省努力,为前线业务提供稳定的技术后盾。

动摇时,要不忘初心。否定追求,就是否定自己。谨以此告诫自己。

Posted in 默认分类 | Tagged | Leave a comment

PHP——成也Web,败也Web

早年我并不知道Python写的Web应用是怎么部署的,总觉得像PHP、ASP一样,仅仅提供一个语言级别的执行模块,直接嵌入Web服务器运行,甚至于直接对外提供带扩展名的URL都是自然而然的事情。

前一阵学习了Python,总是如别人一样,不自觉的和PHP进行对比。随着学习的逐步深入,更发现PHP的发展受限于其Web出身,恐将来难成正经的通用开发语言。

先说说PHP从历史到今天分别是怎么运行的:

  • CGI SAPI:由Web服务器的请求处理进程fork+exec这个CGI,用环境变量单向传递Headers给应用程序,应用程序从stdin读request body,其stdout会被Web服务器作为response headers和body输出给客户端。Web服务器和PHP CGI的关系是父子进程间通信,当应用程序的响应速度较慢时(忙于计算、外部I/O等),会阻塞对应的Web服务器进程/线程;而且因为CGI进程的输入之一是环境变量,导致其只能一次性使用,需要承担频繁fork()的开销
  • Apache2Handler等Web服务器模块类SAPI:Apache2调用Handler,并向其传递server_context;Handler利用server_context读到Header、body等内容之后构造起PHP脚本的context,也就是$_SERVER之类,然后开始执行PHP脚本。而脚本执行的输出也直接被Web服务器收集。PHP和Web服务器在同一个进程内执行,处于完全从属的地位。Apache2Handler方式本来可以通过多线程等方式让Apache不受PHP阻塞,但由于PHP社区的坚持,目前常见的Apache2+PHP配置都是prefork MPM的,以至于性能相当一般
  • FastCGI SAPI:原理是把每次fork处理一个请求,变成一个不退出的循环,每循环一轮就处理一个请求;多进程listen在同一个socket上,实现并发。PHP-FPM是后来的一个民间补丁项目,提供了更好的进程管理和附加功能,处理完License问题之后,FPM合并入PHP主线。Web服务器和PHP的关系是网络通信的关系,可以分离到不同服务器上部署。Web服务器可以使用多线程或者I/O复用技术来处理别的请求,性能会>比前二者好很多。但FPM的实现仍然不够好。

PHP的各种扩展模块,大都是偏重于数据库、字符串处理等应用层面的功能,充分体现了其作为Web开发利器的特点;而对于I/O、POSIX基础功能,则关注较少。
Web开发之外的领域,用PHP写独立运行的服务器,并不是主流的用法。其依赖的pcntl、pthread等模块也是较晚加进来的,而且也没啥人用。用

  1. PEAR Net_Server(无人维护) 通用服务器框架
  2. PEAR HTTP2 协议解析库
  3. PEAR HTTP_Server(无人维护) HTTP服务器框架
  4. PECL pecl_HTTP(需要编译) HTTP服务器框架,我没编译出来……
    等几个模块,可以很容易的创作一个独立的HTTP静态文件或SOA服务;但如果想在其中运行一般的Web PHP脚本,就需要用PHP本身实现一个SAPI:
  • 输入方面是很容易仿制的,除了需要构造Predefined/Reserved Variables(感谢作者,$_SERVER等只是普通数组,只须填充内容即可)再写一下上传文件自动存盘的处理就差不多了
  • 输出方面就比较麻烦,因为“写”是动作,是对外部环境施加影响的。考虑到PHP深深的“假设stdout”情结,须使用output buffer机制收集输出内容,副作用是chunked输出的程序会丧失分段效果,变成缓冲输出;header()函数需要用pecl-apd扩展中的override_function()函数,但此扩展却无法兼容当前的ZendAPI,无法编译成功

传统上,协议解析是SAPI的工作,PHP的语言引擎部分从属于SAPI,以至于没积累出什么好用的协议解析库;而PHP书写的Web应用向来都是直接调用SAPI提供的函数,积习难改,以至于想用PHP本身来写Web服务器就须要去实现一个SAPI,但又会遭遇到这个语言本身的Web烙印太深、假设太多,以及不够“动态”的问题。
传统上,网络通信向来也不须由PHP来处理,以至于也没积累出什么好用的通信框架库。

最终,PHP成了一个Web only的开发语言。真可谓成也Web、败也Web。

一些新兴的PECL扩展提供了高性能I/O框架,比如swoole,但因为上述SAPI的问题,目前尚未出现像Python那样用PHP本身写的PHP Web服务器。

相比之下,不用写<%的Python语言,其发展道路就更加general purpose一些:

  1. 标准库中有os、multiprocess、threading、select等模块,一看就是面向系统编程而非仅仅针对Web开发
  2. 标准库中的SocketServer及其MixIn classes、HTTPServer等可用于写服务器;CGI模块可用于解析HTTP协议请求
  3. 标准库中的wsgiref是纯Python的。也就是说,用Python语言写一个WSGI Server很容易且是提倡的做法
  4. yield语法加入语言比较早,可以实现协程
    在Web应用方面,Python的WSGI接口已经基本统一江湖。WSGI不是通信协议,而是语言级别的调用约定(关于这个函数后面带几个什么样的参数的约定),而WSGI可以用纯Python实现,因此不会遇见用PHP实现SAPI的尴尬。由于Python没有像PHP那样深深的Web烙印(甚至早年在Web上的部署并不太方便)加上标准库中很早就带有各种基础模块,导向结果就是出现了很多优秀的高性能框架和服务器软件。现在流行的组合是用 gunicorn WSGI Server运行WSGI应用程序,管理多个worker充分利用多处理器,用gevent消除I/O等待时的浪费;对外提供HTTP服务,前面套一个nginx提供静态文件和访问控制、rewrite等功能。
Posted in 默认分类 | Tagged | 1 Comment

墨菲定律之多处保存必然会出现不一致——谈Linux上的时区问题

技术部的工作日报,原本是早晨9点发,脚本换了一台服务器运行之后变成17点了。算算时差也知道是时区问题。

检查了一下, /etc/timezone 内容误为 Etc/UTC,而 /etc/localtime 是从 /usr/share/zoneinfo/Asia/Shanghai 复制过来的,二者不一致。date命令使用 /etc/localtime 而 cron 按 /etc/timezone 文件执行,于是造成了执行时间不对的问题

另外需要注意的是,cron 只在开始运行时读取一次该文件,而每分钟唤醒时不再读取,所以改过文件之后还得重启该服务;又得注意的是,service cron stop 似乎并不会终止cron进程,所以……你懂的

以上就是墨菲定律之:多处保存,必然会出现不一致

Posted in 默认分类 | Tagged , | Leave a comment

六月台湾游

不知怎么的,突然就想去台湾了,于是4月底急吼吼的准备了户口本等资料,预约了东城分局出入境办理台湾通行证和护照。看了看日历,5月4日星期六,我不上班公安上班,就这天吧。结果交了申请之后直接告诉我5月31号再来取……期间去了两次都催不出来,直到拿到证件,看了签发日期,才知道异地办理的确不如在家办理快。不过咱不就是为了从北京出入境办个G个人旅游签注嘛!忍了。这期间先买了从北京到厦门的飞机票,也挺贵的,1371元呢!

下一步就是订票和办理入台许可。5月31日拿到证当天扫描完毕,把资料发给中青旅淘宝店,然后就是焦急的等待。6月5日,终于拿到了,才订了金门的住宿、金门到台北松山的机票。

大概的日程记录如下:

6月10日 北京-厦门 CA1809;厦门五通码头-金门水头码头 乘船;参观金门民防坑道、莒光楼、民国福建省政府,还驱车看了一眼八二三炮战纪念堂的外观

6月11日 金门马山观测所、翟山军用坑道;乘飞机去台北,当天去淡水渔人码头、情人桥游玩

6月12日 国父纪念馆、淡水红毛城、真理大学、淡江高中、台北故宫、中正纪念堂、台北101、饶河街观光夜市

6月13日 办了TR PASS Y火车票;去了北投温泉博物馆、露天温泉,又去朵儿咖啡馆喝杯咖啡,还去嵩山机场三层观景台看了一会儿飞机。下午去基隆,感觉太村了,吃了个夜市又回台北住,在基隆火车站拍了铁路0公里标志

6月14日 参观总统府,乘火车去看了暖暖火车站、平溪线小铁路放天灯,最后去了九份住下,出来吃饭时看了一下阿妹茶馆,也就是《千与千寻》的取景地

6月15日 参观黄金博物馆,淘了个金,然后去了野柳地质公园。穷酸的只剩下五六百块现金,看到7-ELEVEN特别激动,赶快补充了现金去吃了个螃蟹。夜间又回九份住,比昨天贵

6月16日 乘火车去了苏澳,泡了个坑人的冷泉。还在苏澳新火车站见到了Aroean,真是太巧了。经花莲到达台东,在花莲火车站广场拍了些照片,喝了一杯用本地瑞穗咖啡豆走的咖啡;路过池上站太晚了,没便当

6月17日 乘船去绿岛逛了一下,晚上回来在台东城区逛街,结果发现不太兴旺,而且公交车也很早就收车。和我一起等车的还有五个小姑娘,我表示可以拼车一起走。她们于是去7-ELEVEN用ibon机叫出租车,未果。好不容易街上拦了一辆出租车,本来想只上一半人,结果遇到彪司机了,五个小姑娘装后排座上,我坐前面,一车全拉走!于是我就请了车资,没让她们花钱。

6月18日 早晨在台东火车站看到宪兵服务台,我看了一眼,大兵就要给我发人才招募的广告。难道我暴露了?没理他,继续等车,坐到高雄,转捷运到桥头糖厂参观了一下,买了好多黑糖(其实就是红糖吗?)随后就开始下雨。转战西子湾,参观了打狗铁道故事馆(原高雄港火车站)、英国打狗领事馆官邸旧址,去了一趟旗津,吃了大碗冰,然后才开始找住宿。在火车站附近住下之后又乘地铁去了瑞丰夜市吃饭

6月19日 早晨捷运转高铁,直达桃园,然后在高铁站7-ELEVEN买了“我的美丽日记”面膜。说实话我真不值得她们为什么都喜欢这个品牌。随后转公交车时遇到不能刷卡的加班车,付现金到机场。面膜放在行李里,直挂北京;手里只拿相机和iPad,然后去免税店买了烟酒。吃饭时时间已经快到了,于是牛肉面只吃了牛肉我就跑了,结果发现还没开始登记,唉我的面啊!到香港机场,我主动报告我带了超量香烟,海关没为难我。在机场吃了个许留山,再去乘机的时候,手里的液体被要求托运,于是又花了50块钱打包费。到北京都夜里了,提了货就出来回家

过了几天,发现身份证、备用电池等东西丢失了。我觉得大概是丢在飞机上或者首都机场T2了。呵呵

 

这几天的体验,觉得台湾是个不紧张的地方,即使台北高雄这种大城市,也不像北京。各处景点的游客都很少,而且基本上都不要钱或者很便宜;吃饭也很便宜。他们那里大量依赖硬币,于是有了《听说》电影里吃夜市数了半天零钱的典故。台湾还很依赖机车(摩托车),红灯放绿的时候,噪音跟飞机起飞差不多。派出所厕所随便用、宪兵降旗可以紧密围观、路上垃圾桶很少主要是扔给7-ELEVEN。金融方面,高端洋气上档次的银行都受理人民币和银联业务,大部分商户也可以刷银联信用卡,算是被大陆经济入侵了吧。

Posted in 默认分类 | Tagged , , , , | 4 Comments

postfix 中一次查询多个 maps 需要注意的地方

今天遇到的一个情况,需要配置 postfix 完成下列功能:

  1. 对于特定域名的收件人地址,把信发给特定的服务器
  2. 其它的随机选择出口 IP 往外发送

这两个功能分别都很容易实现:

第一个用 transport_maps 的域后缀匹配功能

example.com smtp:chsMX.example.com

第二个在 main.cf 里创建多个指定 IP 地址的 smtp 出口,然后在 transport_maps 里查询一个 tcp 类型的外部服务,在该外部服务里用随机算法选择出口

但是,两个一起用的时候会出现问题。因为 postfix 会先拿完整的邮件地址去依次查询两个 maps ,第一个匹配不上,然后匹配第二个,成功后直接返回了,导致特殊的邮件域路由功能失效。解决方法是把第一个改为 pcre 或者 regexp 格式的查询表:

/.+@example.com/ smtp:chsMX.example.com

这样就可以确保需要特殊处理的邮件域匹配在第一个查询表上,而不会去查询第二个查询表。

Posted in 默认分类 | Tagged , | Leave a comment