Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare a Scribd company logo
合久必分,分久必合
      洪强宁
  QCon Beijing 2012
美好时代
代码结构
                     book
         models
                    group
          views

shire   templates   doumail

                       .
         scripts       .
                       .
          tests
部署方式
                                  memcached


      nginx              shire      mysql


                                   beansdb
server_name 9.douban.com;
rewrite (.*) /ninetaps/$1 last;
然而


• 时代在前进
• 产品在扩张
• 代码在膨胀
shire项目Python源文件数与代码行数
              源文件数                        代码行数

4000                                                     500000



3000                                                     375000



2000                                                     250000



1000                                                     125000



   0                                                          0
       2006   2007   2008   2009   2010    2011   2012
问题浮现
• 难以掌控全局
 • 新人上手变慢
 • 新需求实现变困难
• 代码质量下降
• 代码耦合度变高
• 难以实现不同产品不同节奏
首页宕了?




 电影那边做了个改动……
解决方案:分
自发选择

• 新项目想使用新技术
 • m.douban.com: Pylons
 • 内部管理系统: Django
自然选择

• 产品拆分
 • book站、movie站、alphatown...
• 建立独立服务的需求
 • IP定位服务
 • 小豆服务
如何分?


•库
• 服务
库

• 性能无损耗
• 升级发布麻烦
• 依赖注入
服务

• 升级发布方便
• 客户端依赖轻
• 性能损耗
• 额外的故障点
• 开发环境搭建复杂
适合服务的场景

• 需要分开部署
• 需要独立维护
• 需要错误隔离
• 需要节省资源
• 跨语言/跨平台
重新调整主站代码结构

• 按照产品线切分包
• 定义包接口
• 公共代码单独建包
• 限制提交权限
• 基础代码独立成 douban-corelib 库
新代码结构
                 community    models

                   book       views

                   movie     templates
  shire
                     .        scripts
                     .
                  corelib      tests
douban-corelib
部署方式调整


• 建立多个app server实例
• nginx 分发到不同后端
shire.main   memcached


nginx    shire.fm      mysql


        alphatown     beansdb

            .
            .         services
            .
开发方式调整
分带来的问题
重复开发

• web框架
• 测试框架和持续集成
• 日志处理
• 开发环境
• 上线脚本
管理混乱
• 资源申请随意
• 权限不能统⼀一管理
• 出现资源竞争情况
• 监控方式随意、缺失、不⼀一致、不可控
• 配置管理不可靠
• 对服务的调用方式千差万别,难以控制
历史经验未能最大化应用


• 服务软件参数配置
• fail over 处理
不能同步进化


• 代码复用率下降
⼀一个应用想使用另⼀一
 个应用的代码麻烦

• 修改 sys.path
• 依赖代码变更后需要重启,否则可能出
 现诡异问题
解决方案:合
需求
•   整合最基础的框架

•   创建新项目无痛化
•   统⼀一部署方式
•   统⼀一监控

•   统⼀一资源管理
•   以API形式提供基础设施使用接口
•   依赖管理

•   提供统⼀一的开发、测试、调试环境
•   同时尽量少的限制应用开发者
私有云


• DAE (Douban App Engine)
PaaS

• IaaS - Infrastructure as a Service (EC2)
• PaaS - Platform as a Service (GAE)
• SaaS - Software as a Service (Gmail)
合久必分,分久必合
面向内部开发者

• 强调功能和性能
• 安全性可以放宽
 • 主要防范无心做错事
 • 但也需要有完善的操作权限和操作日
  志
为百至千级别的应用设计


• 权限隔离直接使用UNIX用户权限
• 对应用区分优先级别
 • 资源紧张时优先保证高优先级应用
开发语言支持

• Python
• 支持Python的C扩展
 • Python/C API
 • Cython/Pyrex
• 未来会支持其他语言(如 go)
依赖管理和隔离

• virtualenv + pip
 • 每个app有自己独立的virtualenv
• dae install
 • 是 pip install 的封装,更新 pip-req.txt
示例
$ dae create daetest
$ dae install web.py
$ vim app.py

import web

urls = ('/', 'index')

class index:
    def GET(self):
        return "Hello, DAE"

app = web.application(urls, globals()).wsgifunc()

$ dae serve
$ dae deploy


open http://daetest.dapps.douban.com
app.yaml
• 应用配置中心
• wsgi apps
• daemons
• cron
• services
• protected_files
用API形式提供基础设施功能
•   mysql
•   memcache
•   beansdb
•   filesystem storage (MooseFS)
•   task queue
•   scheduled task
•   user login
•   dpark
•   每个app拥有独立的namespace
整合已有技术经验
•   LVS
•   nginx
•   deploy 流程
•   thrift
•   onimaru - error collector based on django-sentry
•   scribe
•   puppet
•   监控系统
尝试新技术

• gunicorn -- a fast wsgi server
• gevent -- coroutine library based on
  greenlet and libev
• websocket support
• mesos
worker
                   gunicorn
                    (app A)   worker
         gateway
                   gunicorn   worker
                    (app B)
                              worker
        Node
nginx


        Node
项目间代码调用


•库
• 服务
库
• setuptools (setup.py)
• DAE系统记录下安装的版本(利用 pip
 freeze)

• 部署时保证服务器上版本⼀一致(利用 pip
 install -r)

• 提供更新通知机制,向库使用者通知代
 码更新
依赖库版本
    • 自动记录在 pip-req.txt 中
    • PyPI上发布的软件:发布版本
    • 代码仓库中的软件:revision
-e hg+http://hghub.dapps.douban.com/douban-
corelib@fb367759be2e1b37c77701d59be6514a3b39837e#egg=DoubanCoreLib
distribute==0.6.19
web.py==0.36
wsgiref==0.1.2
服务
•   DAE Service
•   thrift 接口定义
•   在 app.yaml 中定义实现代码入口
•   gunicorn gevent worker
•   用DNS实现服务寻址和权重
    •   直接定位到服务提供者
    •   未来会使用zookeeper实现路由推送

•   在客户端实现fail over、异常处理
•   与DAE集成
user.thrift
 struct UserProfile {
       1: i32 uid,
       2: string name,
       3: string blurb
 }
 service UserStorage {
       void store(1: UserProfile user),
       UserProfile retrieve(1: i32 uid)
 }

app.yaml
 services:
 - interface: user.UserStorage
   handler: user.handler:UserStorageHandler


handler.py
 class UserStorageHandler(object):
     def store(self, user):
         ...
     def retrieve(self, uid):
         ...
DAE Service 客户端
$ dae service gen_client


from daetest_client import UserStorage
user = UserStorage.retrieve(1)



在客户端可进行超时、重试、调用失败时
的默认值等配置
服务治理


• The next big issue
• Done is better than perfect
合久必分,分久必合
合久必分,分久必合
合久必分,分久必合
分分合合
  app   app      app   app

          Platform

  app   app      app   app


分:应用专心于应用自身的逻辑
合:平台成为应用和基础设施之间的纽带
⼀一点感想
• 分要疾风骤雨
• 合要和风细雨
• 作为平台开发者,需要从分的过程中观
 察合的需求

• 平台的可靠性和稳定性非常重要
• 好用的才会有人用
Q &A
你也可以通过下列方式找到我:
http://www.douban.com/people/hongqn/
hongqn@douban.com
twitter: @hongqn
新浪微博: @hongqn
Thanks

More Related Content

合久必分,分久必合