关于 IMDB API(一)

IMDB API 已上线两个月,目前运行在 Linode 的一台1G内存的VPS上,十分稳定(可能是处理量小的原因——这个月只用了16G流量)。

我一直在网上收集关于 IMDB API 的一些评论,虽然她只是一个衍生品,不过我仍然关心她的使用者对她如何评价。

两个月的时间内,有15位网友报告了19个问题,收到10多封鼓励我继续做好的邮件,也被美国哈町大学的一位老师收录到课件中,整个过程都让人很愉悦。

今天看到了下面两个问题:

第一个问题来自 xbmc 论坛上的一则讨论

问题1

实际上这是个使用不当的问题,加上 limit 参数后,和官方的搜索接口几乎是一样的(包括排序)。

第二个问题来自 PPWeb项目组

问题2

这的确是一个问题,图片小的问题已经在 IMDB API 1.2.1 解决,使用了标准的340像素图像,至于提到的烂番茄数据,等忙完了1月份的考试,再来处理。

IMDB API 第一笔捐赠款

晚上回来登录了 IMDB API 的官推,收到了这样一条推文:


因为paypal的限制,捐赠虽然物理上失败了,但这却证明 IMDB API 已经获得了用户的肯定,可视为逻辑上成功了…… :mrgreen:

IMDB API 1.0 发布

IMDB API 1.0 三大更新:

  1. 所有 IMDB 信息全面支持中文译名检索,如:搜索“生化危机”,可以直接使用“生化危机”的作为关键词检索,而不需要使用他的英文名称;
  2. 新增 lang 参数,可以选择获取返回数据的语言,目前仅支持英文和中文两种语言;
  3. 同音字识别,如搜索“建国大业”时,错误的使用了“建国大爷”作为关键字,IMDB API仍然能够正确的返回结果;

官网地址:http://imdbapi.org/

IMDB API 发布

官网地址:imdbapi.org

IMDB API 是什么?

IMDB API 是一个轻量级的 Web 服务,提供一种 IMDB 数据的有效访问方式。虽然 IMDB 的数据可以在官网上免费下载,但是却没有提供一个很好的 API 来检索这些信息。此 Web 服务旨在一定范围内解决这一问题。

IMDB API 的本质

IMDB API 包含一个 RESTful 接口、一个后台数据更新服务和一个监控服务。

RESTful 接口由三层模块组成:访问控制层(Access Control)、缓存层(Cached)和检索层(Search)。

* 访问控制层(Access Control)

检索请求首先由访问控制层接管,判断请求发起方在一个小时内发起的请求次数是否超过限制,超过限制返回 403 状态,未超过限制则允许请求到达下一层。

* 缓存层(Cached)

检索请求到达缓存层后,缓存层根据检索参数来获取 Memcached 中的数据,若缓存有数据,则直接返回结果,若缓存无数据,允许请求到达下一层。

* 检索层(Search)

检索请求到达检索层后,根据用户参数从数据库检索数据,返回的结果(无论有无数据)将自动被缓存层接管,存入 Memcached 中,同时将结果返回给请求方。

这三层最开始全部由 python 编写,运行在 uwsgi + gevent 上。后来考虑到读取缓存中的数据也要 uwsgi_pass 到 python 来处理,实在是有点不够优雅,同时也为了能最大程度利用  Nginx 的高效低能耗的非阻塞特性(虽然 gevent 也是非阻塞的),于是用 Lua 重构了访问控制层和缓存层,使它们完全运行在 Nginx 服务内部,使这它们成为完全脱耦的独立模块。

借着这个思路,本打算也将检索层重构到 Nginx 内部去运行,但是经过反复的压力测试(使用 ab),发现 uwsgi + gevent 组合的性能居然和运行在 Nginx 内部的性能不相上下,甚至还略胜一筹,着实出人意料,于是暂时放弃了这个想法。

数据同步

IMDB API 的数据目前可以在36-48小时内与官方数据完全同步一次,由于本地资源有限,该周期无法进一步提升。

在 Tengine 基础上手动集成 Openresty 的所有组件

喜欢 Openresty 的编程性和其提倡的“让你的 Web 服务直接跑在 Nginx 服务的内部”,但同时我又非常喜欢 Tengine 所提供的新特性,是否还有人跟我有一样的纠结呢?

Openresty 集成了许多第三方的模块来增强 Nginx 的可编程性,通过它开发人员能够很方便的安装它们,如果你是一个懒人可以直接使用 Openresty 提供的便利。但如果你也和我一样对 Tengine 情有独钟,同时又想具备 Openresty 那样强大的可编程性,还有一点小勤快的话,请继续往下读,我将提供一个基于 Tengine 手动集成 Openresty 所有组件的安装过程。

Continue reading “在 Tengine 基础上手动集成 Openresty 的所有组件” »

近况@2012-9-12

这篇文章本应该昨天写的,但是因为 WordPress 发布文章的问题推迟到了今天。

工作

对于自己的发展方向迷茫了很久,年龄不大不小,是否坚持这个行业一直也很纠结。但最近从一些国内的前辈身上看到了许多,同时也坚定了很多。

这个行业很有魅力,放弃!舍不得。相信很多仍然坚持写代码的前辈,很多都经历过我这个阶段。

做一个独立程序员,这个想法由来已久,这和自己的性格有关:不喜欢拘束的工作环境和按时上下班的限制。

做一个独立程序员,但不是现在,你至少需要有已经在产生收入的产品来维持你的生计,这个目标我锁定在两年后。

学习

最近又开始回重大上自习了,准备来年的各种考试,向媳妇承诺的5年内拿到研究生学历的承诺一定要实现。

项目

最近有一个小应用会上线,暂时叫它 IMDB API。该应用用于对 IMDb.com 的数据进行检索。

做这个应用的想法源自自己的另外一个项目(暂时叫它猫克斯),该项目中正好需要一个检索影片 IMDb 信息的接口,但是网上没找到合适的,要么被官网威胁着关了,要么获取的数据字段不够丰富。

于是乎,我产生了自己在官网提供的文本数据的基础上实现一个,目前正在数据处理过程中,预计能在下周内完成并上线,本应用使用域名:imdbapi.org 。

由于数据是全英文的,所以前期未考虑国内的开发者(主要是备案不让过 :neutral: ),仅针对国外用户的使用做了优化,如:

  • 采用国外的CDN来加速应用的访问;
  • 检索分词支持同一单词的不同时态的识别;
  • ……

尽管如此也对中文用户的使用做了少量优化,如:华语电影支持直接输入中文进行检索等,对国内用户的支持,会在有一定国内用户的基础后进行。

当产品上线后,会专门写一篇更详细的文章来介绍该应用。

爱情

最后来谈谈感情方面,和媳妇的小家10月份开始装修,以前吊儿郎当的生活几乎完全收敛了。媳妇的脾气不好,爱生气,不过没关系,我爱你,老婆。

WordPress 新建文章和页面,“发布”按钮变“提请审批”问题解决

前几天更换了博客的主机,昨天想发布新文章时,发现原本应该是发布按钮的地方变成了“提请审批”,看了一下用户权限是管理员,没问题。

Google了半天,网上全是SAE平台的问题,另外一个是因为 mysql 服务没有数据库目录权限造成的,这些都不符合我的情况,实在没有办法打算重装 WordPress。

重装 WordPress 时,到安装数据库一步,提示一整页的 SQL 错误,其中第一条提示“Invalid default value ‘user_registered’”(文字大概类似这样),看了一下它执行的SQL,原来这个字段的默认值是设置的“0000-00-00 00:00:00”,而我当初在安装 mysql 时,设置了较严格的模式:

sql_mode = NO_ZERO_DATE,NO_ZERO_IN_DATE,TRADITIONAL

问题找到,现在回想起来,之前在后台除了无法新建文章和页面外,其他内容的新建更新都没问题。这可能是文章和页面会自动保存草稿的原因,而自动保存草稿时插入默认值失败,获取不到 post_id ,因此才会出现我所遇到的灵异现象。

注释掉 mysql 的这条配置后,重启 mysql。哈哈!“提请审批”按钮又变回了那熟悉的“发布”了。 :mrgreen:

ubuntu 下安装 mongodb 无法启动的问题

按照官方文档中的方法在ubuntu下安装了 mongodb,但是无论如何启动都失败,查看了一下日志,提示了如下信息:

Unclean shutdown detected.

解决方法,只需要将数据目录(默认为 /var/lib/mongodb/mongod.lock)中的 mongod.lock 文件删除即可。

寻宝图的那些事儿

一直认为作为一个开发人员应该把自己的每个项目都当作自己的孩子一样悉心栽培,但是很多时候总是事与愿违。总有一些外来因素,要把你和你的“孩子”区别开来,使你不得不认为:他是别人的。

8年的从业经历中,绝大部分时间都是在为实现别人的梦想而编码,很少为自己做点什么。

首先,我要感谢@彭波VS,作为曾经的创业伙伴和现在的兄弟,你活跃的思维总能丰富我的业余生活。失败和多次夭折的想法,让我们明白,创意和执行力比起来,真的不算什么。

寻宝图是我的第一个 python 项目,让我处于实验阶段的“小媳妇儿”第一次站到外人面前,没有羞涩,只有无比地期待。

寻宝图基于 web.py 实现,由于第一次用 python 做 Web 开发,在代码管理上也不知道有什么合适的规范,于是按照自己的想法进行管理,代码文件目录树片段:

xunbaotu/
├── controllers/
│   ├── afflatus/
│   │   ├── __init__.py
│   │   ├── models.py
│   │   ├── views.py
│   │   ├── ...
│   ├── common/
│   │   ├── __init__.py
│   │   ├── models.py
│   │   ├── views.py
│   │   ├── ...
│   ├── discounts/
│   │   ├── __init__.py
│   │   ├── models.py
│   │   ├── views.py
│   │   ├── ...
│   ├── projects/
│   │   ├── __init__.py
│   │   ├── models.py
│   │   ├── views.py
│   │   ├── ...
│   ├── ...
├── static/
├── templates/

controller 按不同的实体分了目录,每个目录下都分别有一个 models.py 和 views.py,分别对应数据业务层(这里把数据层和业务层合成了一个)和表示层,这样做可能在 python 达人眼中有点可笑,不过这的确比较实用,同类代码更容易被查找。

数据库使用的我最喜欢的mysql,严格按照范式定义的数据结构,各表外键从属关系明确,这和我以往的习惯大不一样,毕竟在高并发应用中,违反范式的设计比比皆是,况且并不是所有的程序员都有幸能够从头设计一个项目。

Javascript 方面,作为一个“不要重复发明轮子”理论的拥护者,使用了大量 jQuery 社区中的智慧结晶——通常只选择那些轻量简洁的插件,根据自己的需求做适当修改。

CSS 方面,第一次如此亲密的接触样式兼容问题,以前过度依赖前台人员所留下的弊病暴露无遗,不过好在有惊无险(感谢@丽娟,@星哥)。

最后说说服务器方面,CentOS 和 Nginx 是必须的,但是最后决定尝试使用去年无意中发现的 Tengine ,主要看重它能将多个静态文件请求合并为一个请求的功能,再加上淘宝的金字招牌,忍不住试用了一下。Web Server 使用的 spawn-fcgi

寻宝图目前还处于开发阶段,离正式发布第一个版本还有大概20%的工作量。最后借用@寻宝图旅游情报的话作为结束:“不稳定,不美观,甚至不完整,但寻宝图开始了”。

Nagios 插件(一):监控 MogileFS 插件

使用本插件,必须先安装并设置好 NRPE 。

一、插件(mogilefs_check.py)

#!/usr/bin/env python
# coding=utf-8

###############################################
#	nagios plugin
#
#	本插件用于检测MogileFS的工作状态(LITE)
#
#	@author Tianzhen(uimeet.com)
#	@version 0.12.521
###############################################

import os
import sys
import getopt
import re

# status re
STATUS_RE = re.compile(r'([\d\.\:\w\-]+) ... (OK|REQUEST FAILURE)')
def usage():
	print """
Usage: mogile_check.py [-h|--help] [-t|--trackers trackers] \
				[-m|--mogadm 'mogadm' path]

	"""
	sys.exit(3)

def check(inputs, output, prefix):
	"""
	通用的检查方法
	"""
	# 崩溃掉的部分
	ctris= []
	# 匹配的总数
	matches = 0
	while inputs:
		input = inputs.pop(0)
		if input == '\n':
			break

		match = re.search(STATUS_RE, input.strip())
		# 匹配失败
		if not match:
			break

		# 返回给 nagios 的消息
		# 只返回错误消息
		if match.group(2) == 'REQUEST FAILURE':
			ctris.append('[%s]' % match.group(1))

		matches += 1

	if ctris:
		# tracker
		output['msg'].append( '-(%s)- %s: REQUEST FAILURE!!!' % ( prefix, ','.join(ctris) ) )
		if matches == 1 or (matches > 1 and len(ctris) == matches):
			# tracker 全部坏掉了
			# 杯具地崩溃了
			output['status'] = max(output['status'], 2)
		else:
			# 不是全部坏掉,还有希望
			# 给个警告
			output['status'] = max(output['status'], 1)

	return output

def check_host(inputs, output):
	"""
	处理host的检查信息
	"""
	return check(inputs, output, 'HOST')

def check_tracker(inputs, output):
	"""
	处理tracker的检查信息
	"""
	return check(inputs, output, 'TRACKER')

try:
	options, args = getopt.getopt(sys.argv[1:],
			'ht:m:',
			['help','trackers=','mogadm=']
			)
except getopt.GetoptError:
	# 给出的参数无效
	usage()
	sys.exit(3)

# 表示 mogile 的tracker地址
argTrackers = None
# 表示 mogadm 路径
argMogadm = 'mogadm'

# 每个参数各归各位
for name, value in options:
	if name in ('-h', '--help'):
		usage()
	if name in ('-t', '--trackers'):
		argTrackers = value
	if name in ('-m', '--mogadm'):
		argMogadm = value

if not argTrackers:
	# trackers参数无效
	print 'Please most be specified "trackers".'
	sys.exit(3)

out = os.popen('%(mogadm)s --trackers=%(trackers)s check' % {
			'mogadm': argMogadm,
			'trackers': argTrackers,
		}).readlines()

ret = {'msg':[], 'status':0}
while out:
	o = out.pop(0)
	if o:
		# 去掉末尾的 ...\n 符号
		o = o[:-4]
	if o == 'Checking trackers':
		# trackers 状态检查
		check_tracker(out, ret)
	elif o == 'Checking hosts':
		# hosts 状态检查
		check_host(out, ret)
	elif o == 'Checking devices':
		# devices 状态检查
		# 本插件暂不包括 devices 的状态检查
		# 检查到这里时,直接退出
		break
	else:
		# 走到这里来了,那我也不知道该怎么处理
		# 直接跳过吧
		continue

	# 上面出现崩溃的话,没必要继续往下面检查了
	# 速度处理吧
	if ret['status'] == 2:
		break

out = None

if ret:
	# 返回值有效
	if ret['msg']:
		print ' - '.join(ret['msg'])
	else:
		print 'Everything is OK.'

	sys.exit(ret['status'])
else:
	# 返回值无效
	# 给出警告信息,这可能是因为配置的原因引起
	print '未能正确配置插件,状态信息获取失败'
	sys.exit(1)

二、监控服务器的相关设置

Continue reading “Nagios 插件(一):监控 MogileFS 插件” »