OpenERP 负载平衡

OpenERP 7.0 带来了许多新特性,架构上也有许多改进。其中可配置 worker 参数,可使 OpenERP 运行在多进程模式,突破GIL的限制,有效利用了现代多核CPU的性能。但默认情况下,OpenERP 只能运行于一台服务器,对于提供SAAS服务或并发很大的情况下,单台服务器的性能是有限的。本文介绍实现 OpenERP 负载平衡的方法和原理。

一、架构

┌──────────────────────────────────────────────┐
│                   Nginx                      │
└──────────────────────────────────────────────┘
        /              |                \
┌────────────┐   ┌────────────┐    ┌────────────┐
│ OE Server  │   │ OE Server  │    │ OE Server  │
└────────────┘   └────────────┘    └────────────┘
         \             |                /
┌───────────────────────────────────────────────┐
│                Redis Server                   │
└───────────────────────────────────────────────┘

注:实现负载平衡的关键点在于 cache 和 session 共享。

二、Web 服务器配置

WEB 服务器选择 Nginx + upstream 配置,可参考 “使用Nginx Upstream 部署 OpenERP ” http://my.oschina.net/wangbuke/blog/67450 。

默认情况下,nginx 采用轮询的方式,将请求分发到多个 OE Server 里。建议改为 ip_hash 方式,如:

upstream bakend {
     ip_hash;
     server 192.168.0.11:8069;
     server 192.168.0.12:8069;
}

三、OpenERP 的 Session 和 Cache 处理

3.1 OpenERP Web Session 处理

OpenERP 中的Session 处理默认用FilesystemSessionStore,使用文件系统存储用户 session 。如 openerp/addons/web/http.py

1
2
3
4
5
6
class Root(object):

    def __init__(self):

        self.session_store = werkzeug.contrib.sessions.FilesystemSessionStore(path)
        self.session_lock = threading.Lock()

那么我们只要将OpenERP 中的SessionStore,改为 RedisSessionStore,RedisSessionStore 可参考https://gist.github.com/1451947 。

修改方法,可以直接修改 http.py 文件。 或是和我一样,重写一个库,重载 session_context 方法,这样可以不修改OpenERP的源文件,方便以后升级。

3.2 OpenERP LRU Cache 处理

openerp/tools/cache.py 中 ormcache 和 ormcache_multi 是 OpenERP 中非常重要的缓存类。OpenERP ORM 大部分的方法调用都会经过 @tools.ormcache 或 @ormcache_multi 修饰。经过修饰后,结果会被缓存,这个缓存是存放于内存中。 这个就是OE在加载一次数据后,第二次会明显快很多的原因。还有,通过web 界面翻译OE术语不能实时生效,也是因为缓存没有更新。

可以修改ormcache 和 ormcache_multi 类,以使用 redis 缓存。关键代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    def lookup(self, self2, cr, *args):
        key = args[self.skiparg-2:]
        key = '%s:%s' % (self.method.__name__, str(key))
        #key = md5(key).hexdigest()
        hash_name = self.db_key_template % cr.dbname
        value = self.redis.hget(hash_name, key)
        if value:
            self.stat_hit += 1
            return loads(value)
        else:
            self.stat_miss += 1
            value = self.method(self2, cr, *args)
            self.redis.hset(hash_name, key, dumps(value, HIGHEST_PROTOCOL))
            self.redis.expire(hash_name, self.timeout)
            return value

缓存的值使用 cPickle 序列化后,将每个键值对存放于 redis 的 哈希表中。

3.3 auth_openid 模块

auth_openid模块也使用文件系统存储用户登录凭证。如:

1
2
3
class OpenIDController(openerp.addons.web.http.Controller):

    _store = filestore.FileOpenIDStore(_storedir)

如果您启用了这个模块,那么这里也需要修改为存储在redis中。如果没有启用此模块,则无需理会。

相关实现可参考,https://github.com/bbangert/openid-redis/blob/master/openidredis/init.py

四、OpenERP Cron 处理

默认情况下,每个OpenERP Server 实例都会运行一个 cron 进程任务。这里建议只允许一个实例运行CRON。把OpenERP 7.0 的配置参数 max_cron_threads 设置为0 ,即可禁止cron。相关代码如下:

1
2
3
4
5
    def process_spawn(self):
        while len(self.workers_http) < self.population:
            self.worker_spawn(WorkerHTTP, self.workers_http)
        while len(self.workers_cron) < config['max_cron_threads']:
            self.worker_spawn(WorkerCron, self.workers_cron)

五、OpenERP Module RegistryManager 处理

OpenERP Module Registry 主要负责管理OE的对象。一般是安装或更新的模块时候,会根据定义来更新数据库。 在OE多进程模式下,OE会自动管理 Module Registry ,相关的更新信息会存放在数据库里。RegistryManager 会检测是否有更新,如有更新将会自动清除缓存并重新载入。相关代码如下:

1
2
3
4
5
6
7
8
    @classmethod
    def setup_multi_process_signaling(cls, cr):
        if not openerp.multi_process:
            return

    @classmethod
    def check_registry_signaling(cls, db_name):
        if openerp.multi_process and db_name in cls.registries:

这里,实际上无需做改动,上面只是说明情况。只需让OE运行在多进程模式即可(也就是配置 worker 参数)。

六、完成!

经过以上几个步骤,可以让OpenERP 运行于多台服务器,通过Redis 分布式缓存处理相关的 Cache 和 Session,从而实现 OpenERP 负载平衡。

注: 1、本文仅讨论 OpenERP 负载平衡部署方式,并不涉及 Postgresql 和 Redis 的负载平衡,相应的方法请自行搜索。 2、鉴于OpenERP SA 官方已不再维护 GTK 客户端,并没有对GTK客户端的情况进行完整测试。

0条评论

OpenERP 自动编码去BOM(可用excel编辑)

openerp-web-import-chardet

作者:wangbuke@gmail.com

源码托管地址: https://github.com/buke/openerp-web-import-chardet

OE apps 下载地址: http://apps.openerp.com/addon/8098

功能:

自动检测OpenERP 导入的CSV文件编码 自动移除UTF8文件的BOM。安装完之后,就可以直接用EXCEL WPS等编辑好的CSV文件,导入到OpenERP中。

支持编码:

  • ASCII, UTF-8
  • Big5, GBK, GB2312, HZ-GB, HZ-GB-2312 (简体/繁体中文)
  • EUC-JP, SHIFT_JIS, ISO-2022-JP (日文)
  • EUC-KR, ISO-2022-KR (韩文)
  • KOI8-R, MacCyrillic, IBM855, IBM866, ISO-8859-5, windows-1251 (斯拉夫文)
  • ISO-8859-2, windows-1250 (匈牙利文)
  • ISO-8859-5, windows-1251 (保加利亚文)
  • windows-1252 (英文)
  • ISO-8859-7, windows-1253 (希腊文)
  • ISO-8859-8, windows-1255 (希伯来文)
  • TIS-620 (泰文)

依赖模块:

python chardet (本模块已内含chardet-1.1。如果系统安装了新版本,则使用您安装的新版本.)

0条评论

OpenERP PyChart 中文报表模块(支持CJK语言)

OpenERP PyChart Unicode Report (Support CJK Font)

作者:wangbuke@gmail.com

源码托管地址:https://github.com/buke/openerp-pychart-unicode-report

OpenERP 官方APP下载地址: http://apps.openerp.com/addon/8009

支持pychart中文报表,如“库存预测”、“工作中心负载” 等报表。

模块原理

让pychart 生成svg 文件,然后用cairosvg 模块生成PDF报表。

依赖模块

python-cairo python-cairosvg

Debian/Ubuntu安装方法: $ su apt-get install python-cairo python-cairosvg

安装与设置

1、安装字体

复制您所用的字体文件,如simsun.ttc 到系统目录下。

debian/ubuntu: $ sudo cp simsun.ttc /usr/share/fonts

windows : C:> copy simsun.ttc c:/windows/fonts

2、配置pychart 报表字体 默认使用宋体

修改openerp 配置文件 openerp-server.conf , 添加以下参数:

pychart_ttfont_name = Simsun

注:默认是宋体,如使用默认值则无需修改 conf 文件

祝你好运 ~

0条评论

开源模块 Openerp Web PDF Report Preview & Print 简介

Openerp Web PDF Report Preview & Print

下载地址: https://github.com/buke/openerp-web-pdf-preview-print

openerp 官方app下载 : http://apps.openerp.com/addon/7941

简介:

将OpenERP 的PDF报表打印下载功能,改为直接在浏览器中预览打印。

For IE, 需要安装 Adobe Reader。

For Firefox ,需要安装 Adobe Reader。

For Chrome, 神马都不用安装。

以上在windows 上测试通过。如果浏览器阻止了弹出窗口,请点允许弹出窗口。

系统要求:

OpenERP 6.1

0条评论

Taobao OpenERP Connector 简要说明

Taobao OpenERP Connector

项目托管地址:https://github.com/buke/openerp-taobao

作者: wangbuke@gmail.com

功能:

  1. 接受淘宝主动通知,自动添加、确认订单、发货等。
  2. 同步淘宝订单
  3. 导入淘宝产品, 同步库存
  4. 导入淘宝用户
  5. 自动评价,中差评预警
  6. 跟踪淘宝订单物流信息, 签收提醒
  7. …. 等等等 (懒的写了,自己发现吧)

系统要求:

  • OpenERP 6.1
  • beanstalkd
  • pycurl

安装说明:

1. 安装beanstalkd

1.1 linux 系统

debian/ubuntu: # apt-get install beanstalkd

redhat/centos: # yum install beanstalkd

安装完成之后,开启beanstalkd的持久化选项:

1
2
3
4
5
6
7
8
9
10
11
12
# vi /etc/default/beanstalkd

## Defaults for the beanstalkd init script, /etc/init.d/beanstalkd on
## Debian systems. Append ``-b /var/lib/beanstalkd'' for persistent
## storage.
BEANSTALKD_LISTEN_ADDR=0.0.0.0
BEANSTALKD_LISTEN_PORT=11300
#DAEMON_OPTS="-l $BEANSTALKD_LISTEN_ADDR -p $BEANSTALKD_LISTEN_PORT"
DAEMON_OPTS="-l $BEANSTALKD_LISTEN_ADDR -p $BEANSTALKD_LISTEN_PORT -b /var/lib/beanstalkd"

## Uncomment to enable startup during boot.
START=yes

1.2 windows 系统

beanstalkd 原生不能在windows 下运行,当然也有大牛用cgywin 编译了一个。请参考 http://software1987.de/2011/03/beanstalkd-unter-windows-mit-cygwin/ 。编译后的 beanstalkd 下载地址是 http://software1987.de/wp-content/uploads/2011/03/beanstalkd-1.4.6-cygwin.zip

下载解压后,打开 cmd.exe 运行

1
C:\beanstalkd\bin>beanstalkd.exe -l 127.0.0.1 -p 11300 -b C:\beanstalkd

注意上面的目录路径,根据您的实际情况修改。 -b 后面是目录,用于存放beanstalkd 持久化的文件。 上面是直接运行,当然您也可以创建快捷方式,或者用runasservice 工具封装成windows 的服务。

2. 安装pycurl

2.1 linux 系统

debian/ubuntu: # apt-get install python-pycurl

redhat/centos: # yum install python-pycurl

2.2 windows 系统

2.2.1 OpenERP - 源码安装

2.2.1.1 安装 python (如已经安装则跳过)

到 http://python.org/ 下载安装,不解释

2.2.1.2 安装 pycurl(如已经安装则跳过)

到 http://www.lfd.uci.edu/~gohlke/pythonlibs/#pycurl 下载对应版本的 pycurl 安装

2.2.2 OpenERP - all in one

all in one 的版本 在安装完以上步骤之外,还需要把 C:\Python26\Lib\site-packages 目录下的 curl 目录 和 pycurl.pyd 文件 复制到 C:\Program Files\OpenERP 6.1-20120717-233333\Server\server 目录中。(注意路径!,根据实际情况修改)不然下面的安装会提示找不到pycurl。

注意:我现在的all in one (OpenERP 6.1-20120717-233333\) python版本 2.6,所以使用all in one 版本的同学注意了,上面2步都要下载安装for python 2.6 版本的。 (通过看C:\Program Files\OpenERP 6.1-20120717-233333\Server\server\python26.dll这个文件的后缀可以知道python 版本)

3. 安装 Taobao OpenERP Connector 模块

这里和OE安装模块方法一样。首先到https://github.com/buke/openerp-taobao 下载,然后有2种方法:一种是把taobao 文件夹放到OpenERP 的 addon 目录下,第二种是把taobao 文件夹压缩为zip 文件,通过OE后台上传模块。

4. OpenERP conf 文件配置参数

Taobao OpenERP Connector 模块有几个默认配置参数如下:

1
2
3
4
5
beanstalkd_interface = localhost
beanstalkd_port = 11300
taobao_stream_service = True
taobao_stream_thread_limit = 1
taobao_worker_thread_limit = 4

上面是默认值,如果您不需要修改则不用放入OpenERP 启动的 conf中。反之,如果你需要修改 ,则将上面几个参数写在conf 文件中。

5. 关于淘宝 api 的几个问题

首先登陆 open.taobao.com 创建一个 C/S 架构 自用型应用,然后开通主动通知业务。

App Key : 自己找,不解释

App Secret: 自己找,不解释

App SessionKey: 获取方法

  1. 先访问 http://my.open.taobao.com/auth/authorize.htm?appkey={appkey}获得授权码
  2. 再访问 http://container.open.taobao.com/container?authcode={授权码},会得到类似如下的字符串top_appkey=1142&top_parameters=xxx&top_session=xxx&top_sign=xxx,字符串里面的top_session值即为SessionKey

根据淘宝文档说明,C/S应用的 SessionKey 有效期为一年,大家到时记得更新。

PS:

配置淘宝商店的时候出现报错的,请检查你们的淘宝应用权限 。必须是C/S架构的商家后台系统。淘宝规定请看 http://dev.open.taobao.com/bbs/read.php?tid=24315 自2012年7月12日起,“商家后台系统标签”的申请只允许商城店铺和集市三皇冠以上商家申请。

欢迎大家参与此项目,或者到https://github.com/buke/openerp-taobao 提需求、BUG等,也可以直接给我来信。谢谢~

0条评论

使用Nginx Upstream 部署 OpenERP

Openerp 6.1 使用werkzeug 作为web服务的框架,性能比之前的cherrypy 有了很大的改善。但无论是 werkzeug 还是cherrypy ,都不是专门的web服务器。通常的做法是在openerp 之前加一个 Nginx、Apache或其他服务器。下面介绍使用Nginx Upstream 部署openerp 的方法。

一 前提

此处假设您已经安装好 openerp ,并运行在 127.0.0.1:8069

二 安装Nginx

debian/ubuntu:

1
# apt-get install nginx

redhat/centos:

1
# yum install nginx

三 配置Nginx

1. 修改/etc/nginx/nginx.conf ,开启gzip 压缩

1
2
3
4
5
6
7
8
9
10
11
12
13
# vi /etc/nginx/nginx.conf

--------------nginx.conf 需修改内容节选--------------------------
        gzip on;
        gzip_disable "msie6";

        gzip_vary on;
        gzip_proxied any;
        gzip_comp_level 6;
        gzip_buffers 16 8k;
        gzip_http_version 1.1;
        #添加一个类型 application/javascript
        gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

吐槽一下,是否开启gzip,差别真不小。oe 首页加载的http://127.0.0.1/web/webclient/js 开启前文件大小是 1.4M , 开启后大小是350.6 KB (通过firebug 查看)。

2. 建立 openerp 配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# touch /etc/nginx/sites-enabled/openerp
# vi /etc/nginx/sites-enabled/openerp

--------------------openerp 文件内容---------------------------

proxy_temp_path /tmp/nginx_proxy_temp;
proxy_cache_path  /tmp/nginx_proxy_cache levels=1:2  keys_zone=oecache:100m inactive=3d max_size=1000m;

proxy_buffer_size     32k;              #设置代理服务器(nginx)保存用户头信息的缓冲区大小
proxy_buffers         4 32k;            #proxy_buffers缓冲区,网页平均在32k以下的话,这样设置
proxy_busy_buffers_size  64k;           #高负荷下缓冲大小(proxy_buffers*2)
proxy_temp_file_write_size  64k;       #设定缓存文件夹大小,大于这个值,将从upstream服务器传

proxy_connect_timeout      60;
proxy_send_timeout         60;
proxy_read_timeout         3000;

upstream oeserver{
        server 127.0.0.1:8069;
}

server {

        server_name  www.example.com;

        root /var/www/openerp-6.1-1/openerp/addons;

        location /{

                proxy_cache              oecache;
                #proxy_cache_key "$host$request_uri$request_body";
                proxy_cache_key $host$request_uri$request_body;
                proxy_cache_valid  200 304 1d;
                proxy_cache_valid  any   1d;

                proxy_next_upstream http_502 http_504 error timeout invalid_header;
                proxy_pass_header Set-Cookie;
                proxy_set_header   Host             $host;
                proxy_set_header   X-Real-IP        $remote_addr;
                proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
                proxy_redirect  off;

                proxy_pass http://oeserver;

                proxy_buffering on;
                proxy_cache_valid       1d;
                expires 1d;
        }

        location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
                proxy_buffering on;
                proxy_cache_valid       1d;
                expires 1d;
        }

}

完成 !

Nginx 此处仅仅是作为 openerp 的前端WEB服务器,Nginx 还有更大的作用是可以实现Openerp 的负载平衡。此处按下不表,呵呵

0条评论

Linux 下使用 Supervisor 管理源码启动的 OpenERP

从源码启动openerp,简单的做法是添加启动脚本到/etc/init.d/rc.local等,让openerp 随系统启动而运行。此类方法只在系统启动时运行,但万一程序在运行中崩溃,您可能要等到用户发现不能使用了,才去重启服务器。下面请出今天的主角: supervisor ( http://supervisord.org/)

Supervisor 是什么?

Supervisor is a client/server system that allows its users to monitor and control a number of processes on UNIX-like operating systems. Supervisor 是一个客户端/服务器系统,允许用户监控和控制类 Unix 操作系统上的进程数。

1、安装

debian/ubuntu

1
apt-get install supervisor

redhat/centos

1
yum install supervisor

2、建立openerp 的配置文件

1
2
# touch /etc/supervisor/conf.d/openerp.conf
# vi /etc/supervisor/conf.d/openerp.conf

openerp.conf 内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[program:openerp]
; openerp 启动脚本
command=python /var/www/openerp-6.1-1/openerp-server -c /var/www/openerp-6.1-1/openerp-server.conf
; openerp 目录
directory=/var/www/openerp-6.1-1/
; 是否随系统启动
autostart=true
; 自动重启
autorestart=true
; 启动时间,如果超过这个时间oe还没有挂,则视为已经启动
startsecs=3
; 启动用户
user=www-data
redirect_stderr=true
; log 文件
stdout_logfile=/var/www/openerp-6.1-1/openerp-server.log
stdout_logfile_maxbytes=500MB
stdout_logfile_backups=50
stdout_capture_maxbytes=1MB
stdout_events_enabled=false
loglevel=warn

3、 完成!

重启系统试试看openerp 是否已经启动。也可以想办法把openerp 搞崩溃,试试supervisor 能不能及时将openerp 重启

4、 常用命令

1
2
3
4
5
6
# supervisorctl 
openerp                          RUNNING    pid 9454, uptime 4:43:34
supervisor> start openerp  #启动
supervisor> stop openerp   #停止
supervisor> restart openerp #重启
supervisor> status openerp #查看状态
0条评论