2010年11月30日星期二

MapReduce初探

MapReduce最近很热,是Google提出的一个软件架构,用来大规模的分布式计算。主要思想就是Map和Reduce:



  • Map是将一组键值对转换为一组新的键值对列表

  • Reduce则是根据相同的键,把其值通过一定的函数合并


本来这些概念也通俗易懂(难的地方,比如分布式、可靠性我还没有去深究),但是我也想实现一个简单的MapReduce却遇到了问题。此次实现简单的MapReduce,主要想用python的多线程、列表以及Queue等基本的一些结构和数据类型来实现,具体实现步骤:



  1. 通过parse,将原始数据转换成键值对

  2. 使用map将1)步生成的键值对转换成新的键值对

  3. 将map生成的map进行merge操作,首先对键进行排序,然后将相同键的键值对的值合并一个list

  4. 对list进行reduce


这次想通过python的多线程来模拟并行,通过Queue和自定义的SynchronizeDict来缓存中间数据。但是在实现代码的时候,我发现map worker和reduce worker并不能同时执行,因为reduce worker需要等待,只有当所有的map worker执行完毕,merge完毕,reduce worker才开始自己的工作,否则必然出现不完整的情况。代码实现见:https://github.com/yangjuven/MapReduce


重新读了下《MapReduce: Simplied Data Processing on Large Clusters》的3.1 Execution Overview,有段这样写到:



When a reduce worker has read all intermediate data, it sorts it by the intermediate keys so that all occurrences of the same key are grouped together.



也询问了Google's MapReduce in 98 Lines of Python的作者John Arley Burns。




Juven:

In you mapreduce example, the map workers and reduce workers can’t be processed in parallel. Because reduce workers must wait for the complete of map workers. How is the true MapReduce?

John Arley Burns:

Yes you are correct, the map and reduce steps cannot be in parallel. Instead, all maps run in parallel, then when all are finished, all reduce steps run, depending on algorithm in order, This is inherent to the map reduce algorithm. As you noticed, this limits parallelization. This is perhaps one reason Google has largely abandoned map reduce in favor of Bigtable-based processing, letting the database function as the point of control in the algorithms.



Resouces & References:



  1. MapReduce: Simplied Data Processing on Large Clusters

  2. Google's MapReduce in 98 Lines of Python


 



 


 

2010年11月17日星期三

Alias与WSGIScriptAlias

将在项目托管到igor中,由于Apache这样配置:



Alias /project_name/images/ /home/project/project_name/htdocs/images/
Alias /project_name/css/ /home/project/project_name/htdocs/css/
Alias /project_name/js/ /home/project/project_name/htdocs/js/
AliasMatch ^/project_name/(?!app/)(.*) /home/project/project_name/htdocs/$1
WSGIScriptAlias /project_name/app /home/project/project_name/wsgi_handler.py



就出现以下问题:



  1. http://domain/project_name/app

  2. http://domain/proejct_name/app/


链接1和链接2是不同的,链接1会指向到/home/project/htdocs/app,而链接2则会交由wsgi_handler.py来处理。但是实际上我们希望1和2是等价的。那么这个问题也有两种解决方案:


  1. 修改AliasMatch的正则表达式,修改成"/proect_name/((?!app).*|app(?!/).+)"

  2. 将WSGIScriptAlias 放到AliasMatch前面


方案1是可行的。方案2我原以为是可用性的,原因(from http://httpd.apache.org/docs/2.0/mod/mod_alias.html):





Aliases and Redirects occuring in different contexts are processed like other directives according to standard merging rules. But when multiple Aliases or Redirects occur in the same context (for example, in the same <VirtualHost> section) they are processed in a particular order.

First, all Redirects are processed before Aliases are processed, and therefore a request that matches a Redirect or RedirectMatch will never have Aliases applied. Second, the Aliases and Redirects are processed in the order they appear in the configuration files, with the first match taking precedence.





但是经过验证,不可行,我就怀疑 Alias和WSGIScriptAlias的优先级了,google了下,的确有人说Alias要比WSGIScriptAlias的优先级要高。在官方文档只找到这句话(from http://code.google.com/p/modwsgi/wiki/ConfigurationGuidelines)



 When listing the directives, list those for more specific URLs first. In practice this shouldn't actually be required as the Alias directive should take precedence over WSGIScriptAlias, but good practice all the same.

 
Do note though that if using Apache 1.3, the Alias directive will only take precedence over WSGIScriptAlias if the mod_wsgi module is loaded prior to the mod_alias module. To ensure this, the LoadModule/AddModule directives are used. For more details see section 'Alias Directives And Apache 1.3' in Installation Issues.


2010年11月12日星期五

GRANT与UPDATE mysql.user

上周服务器的项目都要开始托管,很多自己的项目都需要搬迁。在搬迁的时候,进行测试,由于服务器有变化,所以为了让数据库能够访问,就需要修改user的host。(以下都假设用户名为juven)。


当时的host是locahost,为了让所有机器都能访问,为了图简便,直接:


UPDATE msyql.user SET host = "%" WHERE user = "juven" AND host = "localhost"

(说明,这是在测试机上,如果在正式机不建议这样做,请将%改为真是ip)


修改之后,以为其他服务器可以直接连接,但是测试的时候还是不可以。觉得不能啊,登录验证和权限检查不就是依靠表mysql.user吗?查了资料后,才知道,需要使用


flush privileges

原因(来自 http://dev.mysql.com/doc/refman/5.1/en/adding-users.html):



it is necessary to use FLUSH PRIVILEGES to tell the server to reload the grant tables. Otherwise, the changes go unnoticed until you restart the server. With CREATE USER, FLUSH PRIVILEGES is unnecessary.



当时还遇到一个问题,当我执行GRANT的语句会有以下报错:


mysql> grant select on db.* to juven@'%' identified by 'XXXX';
ERROR 1133 (42000): Can't find any matching row in the user table

 


这个问题的确比较诡异,现在才知道,在"traditional sql mode"下,如果没有指定密码或者密码为空,都会提示这个错误!可是我指定密码了啊!为何呢?也有仁兄遇到跟我一样的问题http://bugs.mysql.com/bug.php?id=7000


不过不管怎们说,msyql的错误提示太misread了!

2010年11月4日星期四

AJAX Cross Domain

今天下午忙了半天,才深刻ajax不能跨域带来的影响。众所周知,浏览器为了安全,禁止了ajax跨域。即使host相同,port不同,也一样禁止访问。为了能够ajax能够跨域访问,也有很多方法:



  • JSONP(JSON with padding)。这种方法利用的就是<script>标签的src属性可以引用跨域的文件,从而达到跨域访问js。

  • 在服务器端,写个cgi通过代理的形式来访问。

  • flash也是可以来帮助实现跨域。

  • 另外,如果根域名相同子域名不同,可在同一页面的不同iframe中通过设置相同的document.domain,也能实现js相互访问,从而跨域


我综合比较了下,觉得JSONP相对而言还是比较简单、完美的,jQuery也实现了比较好的封装:




  • $.getJSON(url, paramaters, callback),如果在调用时,url结尾加上"?callback=?"query string便可以实现JSONP的访问。

  • $.ajax(),在option中指定dataType为jsonp,便可以实现,也可以通过jsonp来指定query string的key,通过jsonpCallback指定调用函数的名称。


不过jsonp也是有缺点,如果调用的url返回的是xml就无能为力。不过如果返回结果类型能自己控制的,jsonp真的是一个很不错的ajax跨域解决方案。