分类目录归档:编程

MongoDB介绍以及Python的相关库

MongoDB是一个高性能,开源,无模式的文档型数据库,是当前NoSql数据库中比较热门的一种。MongoDB提供了比较丰富的数据库查询接口,是目前最接近关系数据库的NoSql数据库。
近两年MongoDB的发展速度非常的快,不少公司已经将MongoDB应用到实际产品中。在这些公司中最著名的应当是foursquare,国内的淘宝等公司也部分使用了MongoDB。MongoDB更完整的应用列表可以在MongoDB的Production Deployments找到。
技术人员普遍有追新的爱好,看到一个不错的东西就想在自己的项目中用少。在对MongoDB做了些了解后,感觉使用MongoDB作为普通web应用的主数据库或许并不是一个很好的主意。

  • MongoDB的优势是速度以及海量数据的支持,另外一个有点就是schemeless。真正需要用到schemeless的地方似乎并不是太多。目前很多 MongoDB 封装,也都增加了scheme的定义功能,基本上放弃了schemeless特性。另外如果过度的schemeless,日子久了后可能自己都搞不清楚自己到底在数据库里放了什么东西。
  • MongoDB的特性决定了某些关系数据库很容易做的操作在MongoDB中会很不容易实现(比如多表关联查询等,而且据说分页性能也不怎么样?)。为配合MongoDB,在构架设计乃至产品功能需求方面都需要做些调整。
  • MongoDB的另外一个问题是太费内存,在内存不够大的时候性能很可能还不如mysql。所以有人称MongoDB是有钱人用的东西。
  • 可能大多人都不太会有机会遇到真正需要MongoDB的海量数据。

在V2EX上发了一个关于MongoDB的帖子(有谁在用 MongoDB 体验怎么样),引来不少关于MongoDB的吐槽。不是说MongoDB不够优秀。MongoDB有着自己特定的应用场景,如果只是为了尝鲜而贸然使用,可能并不会得到预想的效果。
下面简单的介绍一下MongoDB相关的一些Python库:

  • PyMongo MongoDB的Python接口开发包。PyMongo提供了最原始的MongoDB访问接口,其他的Python MongoDB库基本上都是基于该库进行开发的。
  • MongoEngine 为MongoDB提供了类似Django ORM的API。支持定义Scheme定义,同时提供DynamicDocument类用于支持schemeless。MongoEngine内置了Django提供支持。如果你之前使用过Django,MongoEngine会让你觉得非常舒服。
  • MongoKit 和MongoEngine类似的一个库。个人更倾向于MongoEngine所以对MongoKit没有太多了解。

[django-ajax-validation]Django表单AJAX校验及提交的APP

项目地址https://github.com/vicalloy/django-ajax-validation
django-ajax-validation是一个使Django支持表单AJAX校验的第三方APP。我做了一些修改,增加了表单的AJAX提交以及twitter-bootstrap的支持。

安装

  • pip install git+git://github.com/vicalloy/django-ajax-validation.git
  • 在Django settings的INSTALLED_APPS中加上”ajax_validation”。

一个简单的使用范例

views.py

from ajax_validation.views import validate_form
from ajax_validation.utils import render_json_response
...
class TimelineForm(forms.ModelForm):
    class Meta:
        model = Book
def add_book(request):
    #创建表单并进行校验。返回表单以及校验结果。
    form, validate = validate_form(request, form_class=BookForm)
    if validate['valid']:#如果校验成功,执行保持操作
        book = form.save()
    return render_json_response(validate)//返回JSON

模板

进阶

django-ajax-validation的原始文档就写的非常糟糕,我也偷懒,所以想了解更多还是直接看代码吧。

Node.js相关知识

简单的说Node.js是一个使用Javascript作为开发语言的web开发框架。凭借JS良好的用户基础以及Node.js的高性能等优势Node.js迅速的流行了起来。
此前我一直以为Node.js只是一个使用JS作为开发语言的类ROR开发框架。在对Node.js做过简单的了解后发现这确实是一个很酷的东西。如果有机会非常希望将系统的部分功能改由Node.js实现。
由于Node.js的资料已经不少,这里就不再多费唇舌。想对Node.js有更多了解可以参考下面的一些文档。

  • Node.js 究竟是什么 让你对哦Node.js有个总体概念。Node.js是什么,适合做什么,不适合做什么。
  • Node入门 一本(篇)免费的Node.js入门教程。可以用于了解Node.js一些基础使用以及相关概念。
  • Node.js官方文档(API文档) 可以看前几节,对Node.js的Global Objects有些了解。其他的东西可以用的时候再查。
  • 深入浅出Node.js InfoQ关于Node.js的系列文章。
  • Node Club@GitHub Node Club 是用 Node.js 和 MongoDB 开发的新型社区软件。这是一个开源项目,可以用于熟悉Node.js。简单的阅读过Node Club的代码,感觉用Node.js做传统WEB开发的体验并不是太好。
  • npm Node.js使用的包管理工具。在这里你可以找到很多优秀的JS库。很多JS库不但可以用于Node.js还可以直接用于前端。Node.js的社区非常活跃,第三方库的增长速度非常的快。在这些第三方库中不乏一些很有创意的东西。
    • express 构建在Node.js之上的WEB开发框架。
    • lesscoffee-script 这两个已经太出名了
    • jade 非常酷的一个JS模板语言,看上去有些类似zenCODE。
    • ejs 另一个JS模板语言。相比jade,ejs更适合普通人的使用习惯。
#jade
html
  body
    h1 User <em>#{name}</em>

题外话(About WebSocket&Django)
WebSocket的良好支持是Node.js的一大优势。WebSocket是HTML5里出来的新东西。WebSocket的实质是在浏览器与服务器间建立一个socket连接从而实现客户端与服务端的双向通信。由于Python的WSGI协议无法支持WebSocket,所以包括Django在内的大多WEB框架要支持WebSocket并不是一件容易的事(注:Evented Django这篇文章里有介绍如何使Django支持WebSocket,不过总的来说有些折腾)。Tornado和Node.js一样同为非阻塞的WEB服务框架不需要使用到WSGI,所以不存在这个问题。

web服务器的同步与异步

最近几年node.js和tornado的流行和他们采用的是非阻塞(异步)模式有很大的关系。传统的web服务器通常采用的是同步方式,服务器的每个进程/线程每次只能处理一个请求,在遇到高并发的情况时为即使处理请求必须创建足够多的进程/线程来处理每个请求。举个简单的例子,如果每个请求的处理时间为4秒,为了支持每秒100次请求,你必须为此创建4*100个进程。创建400个进程,这个成本无疑是有些太高了。
node.js和tornado等异步服务器在接收到用户请求后,先将请求放到后台处理,等处理完成后再处理结果返回给用户。node.js和tornado都采用了类似的事件机制,可以在一个进程里并行的处理多个用户请求。在遇到高并发的情况下不需要创建多个进程/线程就可以轻松应对。也真是因此许多人认为异步模式肯定比同步模式要强,异步模式肯定要更好。
Gunicorn是一个Python WSGI HTTP服务器,同时支持同步以及异步模式。Gunicorn默认采用的是同步模式,在它的Design一节中有关于同步以及异步模式的选择说明。前面讲到同步模式下为处理高并发需要创建大量的进程,但如果每次请求的处理时间都非常短就不会出现需要创建大量进程的情况。如前面的例子中,如果每次请求的处理时间为0.1秒,则只要创建0.1×100个进程即可支持每秒100次的请求。node.js、tornado的事件机制虽然要比创建进程和线程的成本要低的多,但也不是完全没有开销的。
最后总结下:
如果服务满足一下特点时可以考虑异步服务器,不然就不是很有必要了

  • 大量的并发请求
  • 每个请求处理的耗时都比较长

将LBForum、“似水流年”的部署环境切换到Gunicorn+Supervisor

Gunicorn 是一个Python WSGI UNIX的HTTP服务器。Gunicorn有着不错的性能以及稳定性。Gunicorn对WSGI、Django、Paster提供了很好的支持,使用起来非常的简单。
此前 LBForum似水流年 使用apache+wsgi的方式部署在webfaction上。为了给服务器节约些内存将部署方式切换到Gunicorn。不过似乎效果并不明显。除工作进程外,Gunicorn还会另外启动一个master进程用于管理子进程。master进程加一个子进程的内存耗用量加在一起大概在40M左右。
注:在一些评测里Gunicorn的性能并不是太好。Gunicorn支持多种 worker-class ,默认的worker-class使用的是同步模式。在将worker-class切换到gevent或tornado性能会好出不少。

SAE Storage for Django

DPress 修正后想着要部署一个在线的演示程序。问题是我自己虚拟主机的资源已经捉襟见肘,于是只能打SAE的主意了。
为保证文件上传功能的正常使用需要将Django默认的Storage实现替换为SAE的storage实现。SAE的官方并没有提供Django的storage实现,需要自己另外实现。在github:gist上有人贴出了SAE Storage for Django的实现(SAE Storage for Django)。github:gist上的这个SAE Storage实现有些bug,我修正后的版本见saestorage
注:

  • SAE Storage单节点的最大容量为2G(注:SAE Storage 服务限制)。这对于一些小站点来说是没什么问题,但如果是一个大型的商业站点这必然会有些不便。难道你需要配置一个storage列表,让程序自行去寻找可用的storage?
  • SAE Storage似乎不太稳定,上传的文件经常会打不开。

“DPress”原地满血复活

GitHub地址: DPress(GitHub)
演示地址: DPress(SAE)

DPress 是我在2009用django写的一个博客系统。此后年久失修,已经跑不起来了。
这两天花了些时间将项目重新修整一下,现在项目又可以重新跑起来了。功能方面新版的DPress有了些变化。

  • 提供对 Markdown 的支持(也只支持Markdown)。
  • 使用 EpicEditor 实现Markdown的实时预览。
  • 使用 DISQUS 实现文章的评论功能。(注:既然已经有了这么好用的评论服务,为什么还要自己写代码呢)
  • 支持代码高亮度。相关的语法说明见:Fenced Code Blocks
  • 支持Tag
  • 支持RSS
  • 使用 Django FileBrowser 提供文件上传的支持。
  • 使用 flatpages 提供对About等自定义页面的管理。
  • 内置GOOGLE ANALYTICS的支持
  • 代码量非常的小
  • 模板和代码分离的比较清晰,要创建一套自己的模板会是一件比较容易的事。

已知bug:直接从网页复制文本时EpicEditor的编辑框内会自动的添加一些看不见的html标签,将导致文本显示不正常。需要粘贴文本时最好先将文本粘贴到写字板中,再重新复制粘贴。

WP7开发初体验 — WP7版“百度.ting”开发记录


项目地址: lb.ting(github)
如果你有WP7手机,可以下载XAP文件体验一下:lb.ting.xap

感觉已经有段时间没有接触过什么新技术了,或许也是想看看自己接触一项全新的技术需要多少时间来熟悉。近来想看看WP7开发。
上周在MSDN简单的看过一些WP7开发文章后决定动手做自己的地一个WP7应用。因为只是想简单的体验一下WP7开发,因此跳过系统学习的阶段直接动手。
这次想做的是百度.ting的WP7客户端。虽然虾米电台、豆瓣电台等电台网站/软件已经一大堆了,但百度.ting还是有自己的优势。百度电台的的音乐码率普遍为128k,比其他电台要好出不少。大多音乐电台支持直接手机访问,直接浏览器访问无法实现音乐的后台播放。
C#刚出时大家评价C#是Delphi和Java的杂交产物。我虽没什么C#的开发经验,但相信凭自己的Java与Delphi经验应付一般的C#代码还是没多少问题的。电台软件的功能以及技术点都不多,我很乐观的想周末在家宅个两天,折腾出地一个基础版本。显然,这个计划已经失败。接触一项新技术的遇到的问题远比我想象的要多,中间也走了不少弯路。
目前第一个初步可用的版本已经完成。我会将代码放到github上。我希望在接下来一段时间里对这个应用再进行一些优化,然后上线到WP7的商店。
下面的文章里会我记录下一些我遇到的问题。

准备工作,知识储备

微软在帮助文档方面做的非常的好,你可以很容易找到自己需要的资料。

开发过程中遇到的相关问题以及解决方案

百度.ting API

直接用FireBug对百度播放器的请求进行分析,可以很轻松的得到大部分API。这些API中唯独缺少电台列表的API。该问题最简单的解决方案是直接分析网页获取到电台列表,然后在程序里写死。另外还可以让程序对电台首页的html代码进行分析,从中提取电台列表。方案一,感觉有些傻。方案二实现起来又过麻烦。于是有了方案三。
百度.ting有官方的Android客户端,而Android程序是比较容易反编译的。使用 Dedexer 反编译后,得到相关API。Android客户端和web版本电台使用的并不是同一套API,而且从接口的参数类型上看服务端似乎用的是Java。

//主要接口
//获取频道列表
http://tingapi.ting.baidu.com/v1/restserver/ting?method=baidu.ting.radio.getCategoryList&format=json
//获取频道歌曲列表
http://tingapi.ting.baidu.com/v1/restserver/ting?method=baidu.ting.radio.getChannelSong&format=json
//获取专辑的歌曲列表
http://tingapi.ting.baidu.com/v1/restserver/ting?method=baidu.ting.radio.getArtistChannelSong&format=json
//获取歌曲的详细信息
http://ting.baidu.com/data/music/links?songIds=

JSON解析

最初我希望JSON能被自动解析成LIST/MAP类型的结构,查了一轮并没有找到比较好的解决方案。在C#中JSON都需要和对象进行绑定。如果手动为所有JSON数据创建相关的数据类,无疑是意见很麻烦的时。我相信我并不是遇到该困扰的第一人。果然网上已经有不少C#的JSON工具。
json2csharp 只要你输入json,改网站会自动帮你生成相关的数据类。

配置文件的存储

大多应用程序都需要保存一些自定义的配置数据。在WP7.1后,本地数据的使用变得非常的简单。本地数据库的使用可以参考 如何使用 MVVM 为 Windows Phone 创建本地数据库应用程序
lb.ting最终方案中并没有使用本地数据库。我采用了直接将JSON数据持久化的做法进行数据存储。直接持久化JSON的方案在数据的可靠性比较差,且配置文件格式的修改会成问题。JSON持久化的方案胜在够简单。

后台音频播放

WP7不支持后台进程,为了保证音频的后台播放需要为应用创建对应的后台音频播放代理。按照通常的理解,动态更新播放列表是一个必须的功能。WP7的后台播放代理还就没有更新播放列表的API。在MSDN的例子中播放列表直接写死在程序里。
去网上转了一圈也并没有找到比较好的解决方案。网上的建议是将播放列表保存在数据库或本地文件中,通过创建一个“中间层”的方式同前台UI进行交互。lb.ting最终采用了将播放列表持久化到本地存储区的方案。

baidu图片获取

专辑封面在浏览器可以正常显示,客户端则无法显示专辑图片。怀疑是代码的问题,于是将图片源换为豆瓣,图片正常显示。一通折腾,发现是百度的防盗链引起。将图片的加载换为WebClient实现。

public static void SetImageUrl(Image img, Uri uri, Uri defaultUri)
{
    WebClient wc = new WebClient();
    wc.Headers["Referer"] = "http://www.baidu.com";
    BitmapImage bi = new BitmapImage();
    img.Source = bi;
    wc.OpenReadCompleted += (s, e) =>
    {
        try
        {
            bi.SetSource(e.Result);
        }
        catch (Exception)
        {
            //bi.UriSource = defaultUri;
        }
    };
    wc.OpenReadAsync(uri);
}

CSRF(Cross-site request forgery)以及django中的处理方法

CSRF(Cross-site request forgery) 中文名是跨站请求伪造。
简单的说是用户访问了安全的网站A(比如支付宝)并登录,之后用户又访问了问题网站B。网站B包含恶意代码,在访问网站B的时候,网站B的网页偷偷的向网站A发起post(get)请求进行转账操作。由于你已经登录过网站A,网站A误以为请求是用户自己发起的安全请求。在操作成功后你的钱啥的也不见了。
当前Django的处理方法:
在用户访问网站时为用户生成一个CSRF防范用的token并将token保存到cookie中。每次用户发起请求时需要将token的值作为表单字段一同提交。服务端对用户提交的token值同cookie中的token进行比较,如果相同则认为安全。
由于浏览器对cookie的访问有严格的限制,问题网站B无法访问到网站A的cookie无法正确的设置token。

sentry,异常记录的云托管平台

最近打算为公司的应用增加异常跟踪功能,所以又去看了看 sentry
sentry 最早是 disqus 发布的一个开源的django异常跟踪APP。一段时间没见发现sentry已经发展成了一个支持 Python、PHP、Node.js、Java 的异常跟踪中心,而且还推出了对于的云服务 getsentry.com
getsentry.com 按月收费,不同方案的区别在于日志的保存时间以及每日的记录事件数的配额。和大多云服务一样 getsentry.com 也提供免费方案,免费情况下每日有100个事件配额。 由于 getsentry.com 本身是一个开源产品,部署成本也不高。 getsentry.com 的服务是否真能让广大用户接受还很难说,但这个做法让人不得不佩服disqus的想象力,连一个异常跟踪平台也能做到这个程度。
sentry 作为一个开源项目有着不错的代码质量,sentry代码中有不少可以借鉴的东西。

  • tox 似乎越来越多的python项目有在使用tox。tox是一个python虚拟环境管理工具,主要用于为测试用例创建虚拟环境。tox可以为不同的python版本单独创建虚拟环境,以测试在不同python版本下的工作情况。
  • 实现了一个自己的BaseManager,增加get_from_cache方法。用缓存来加快查询速度。
  • twitter-bootstrap sentry也是用bootstrap作为前端框架。因为有对bootstrap做过一些调整,所以UI不至于太过bootstrap。
  • celery、nose、gunicorn……