Codebits 2014
SNAKES ON THE CLOUD
Índice
1. MEO Cloud - apresentação
2. Backend
3. Desktop apps
4. API pública
5. Q/A
MEO Cloud
• Serviço de alojamento e sincronização de ficheiros
• Clientes desktop para Windows, OSX e Linux (inc RPI)
• Clientes mobile para iOS, Android, Windows Phone
• Cifra client-side (beta)
• Tráfego mobile gratuito na rede PT
• Music player
• Upload2Me
Backend
Ideia inicial
1. Enviar ficheiros
2. Receber ficheiros
3. ????
4. Profit!!!
Arquitectura inicial
• Metadata:
• BD relacional (MySQL)
• Ficheiros:
• Filesystem distribuído (GlusterFS)
• Web app:
• Nginx + Apache (mod_wsgi) + Python (Django)
Boneco
Desafios desenvolvimento
• Pedidos buffered
• Muitos pedidos lentos em simultâneo
• Green threads
• Modelo event-driven
• Expor servidor aplicacional
Desafios desenvolvimento
• Sincronização de alterações eficiente (deltas)
• Objectos (ficheiros) potencialmente grandes
• librsync
• dividir ficheiros em blocos <= 4MB
Desafios desenvolvimento
• Grande volume de dados (e metadados)
• Resiliência a falhas
• Sistemas escaláveis na horizontal
• Sem SPOF
Desafios desenvolvimento
• Deduplicação de dados
• Hashes dos blocos
Desafios desenvolvimento
• Segurança da informação
• Cifra em todos os passos
Tecnologias usadas
• Python + gevent + Django + M2Crypto
• Cassandra
• Solr
• Zookeeper
• Swift
• uWSGI
• Nginx
• SAPO Broker
• Memcached
Diagrama
requirements.txt
• Django
• uWSGI
• gevent
• greenlet
• oauthlib
• M2Crypto
• duplicity
Core
requirements.txt
• SAPO-Broker
• requests
• pycassa
• kazoo
• python-memcached
Serviços
requirements.txt
• Pillow
• mutagen
• pybloomfiltermmap
• progressbar
• defusedxml
• dm.xmlsec.binding
• objgraph
• Jinja2
Utils
Desafios pós-lançamento
• Solução criada de raiz usando tecnologia recente
(bleeding edge)
• uWSGI - http parser, connector https, Gevent loop engine,
cache distribuído de sessões SSL
• Pycassa - connection pool && long-lived applications
• Solr - SolrCloud
Desafios pós-lançamento
• Schema Cassandra
• normalização vs desnormalização
• tombstones && slice queries
Desafios pós-lançamento
• Swift
• PUT && Rename VS store local
Desafios pós-lançamento
• Python GC
• objgraph
Desafios pós-lançamento
• Processamento não cooperativo ou CPU bound
• Muitos stacktraces, muito debugging
Alguns números…
• 60% imagens, 20% música, 10% vídeos
• 1,2M uploads/dia - 4,8MB tamanho médio
• 310K downloads/dia - 35MB tamanho médio
• Compressão - BZip2 (12,4%) - Zlib (11,7%)
Desktop Apps
Desafios
• Codebase comum entre Windows, OS X e Linux
• Sincronização transparente em background (daemon
que reage a eventos de rede e filesystem)
• Efficiente (RAM, CPU, Disco, Rede, Bateria)
• Robusta/Fiável -> Just works
• De longe, o maior desafio
• A vossa ajuda é preciosa. Really
Python 2.7 (custom) + C
Because awesome
Because speed
Tecnologias usadas
• GUI Windows: C++, Win32 API [Jorge Cruz]
• GUI OS X: Objective-C, Cocoa [Paulo Andrade]
• CLI Linux: Python, gevent [Francisco Vieira]
• GUI Linux: Python, GTK [Ivo Nunes]
Tecnologias usadas
Core de sincronização
Lessons Learned
Tratamento de erros
Tratamento de erros
POSIX Win32
Tratamento de erros
Erros do Windows: It’s over 9000!
Tratamento de erros
• Não podemos pedir ao utilizador “Tente novamente mais tarde”.
• Manter estado:
• O que é que falhou?
• Porque é que falhou?
• Já avisámos o utilizador?
• Quando é podemos voltar a tentar?
• O problema já está resolvido?
• Se é para rebentar, fazê-lo ASAP!
Sistema de Ficheiros
• Surpresas do Python em Windows (para quem vem do Unix)
• rename() se ficheiro de destino já existe, erro
• open(<path>, ‘rb’) abertura em modo exclusivo -> várias aplicações
partem
• readlink() (suporte para symlinks em Windows) não existe
• Tesourinhos: PROGRA~1 -> Usar GetLongPathNameW()
• OS X e Linux
• Pop quiz: link(file1, file2); rename(file1, file2). O que acontece?
Hint: é diferente de mv file1 file2
Nomes de ficheiros
Unicode Normalization
NFC, NFD, NFKC, NFKD
Nomes de ficheiros
(pequeno guia para manter a sanidade mental)
• Em Windows, utilizar paths Unicode e “Long Path Names”, e.g.
u’?C:file.txt' (>= Windows Vista)
• Em OS X, filesystem utiliza NFD
>>> unicodedata.normalize('NFC', u'João').encode('utf-8')
'Joxc3xa3o'
>>> unicodedata.normalize('NFD', u'João').encode('utf-8')
'Joaxccx83o'
• Em Linux, vale tudo :(
Rede
(Much love for pycurl and pyuv)
• Reutilizar ligações para reduzir overhead handshake TCP e SSL
• Transferências simultâneas
• Mitigar overhead relacionado com disk seeks, deltas rsync, etc.
• Minimizar efeito “dente de serra” do TCP quando a latência ou
packet loss são elevados
• Enviar apenas o que foi modificado (deltas rsync)
• SSL/TLS: garantir que os certificados são mesmo validados. Bonus
points: Certificate Pinning
• Tratar timeouts, resets, stalls, outros.
CPU
• “O Python é lento” -> ineficiente, battery hog?
• “O Python não consegue usar mais que um
processador em simultâneo” o “drama” do GIL
(Global Interpreter Lock)”
CPU
• O core é IO-bound (filesystem e rede)
• Tarefas que usam mais CPU implementadas em C:
• Crypto (block hashes, cifra client-side, SSL)
• deltas rsync
• sqlite (Row objects are cool)
CPU
• Na verdade, o GIL é liberto em muitos casos:
• Quando há IO (rede, filesystem)
• Quando os módulos querem :)
The GIL is free
• Cython
• Quando em dúvida, profile stuff: cProfile, logs (!), etc.
CPU
10x mais rápido :)
Memória
6 lessons from Dropbox, on http://highscalability.com/
Memória
:(
malloc(…)
free(obj1)
free(obj3)
Memória
To the moon!
Memória
• Melhorou muito a partir do Python 3.4 (issue #11849)
• Fizemos backport do novo memory allocator
(mmap/VirtualAlloc based) para o nossa versão do Python
• Exemplo: Quanta RAM precisamos para sincronizar?:
• 148.887 ficheiros (100.000 ficheiros aleatórios de 10KB +
Linux 3.14 source tree):
• Ficheiro 50GB (much data)
Memória
MB 100k ficheiros kernel tree
ficheiro 50 GB
force reclaim
50 MB RAM
API Pública
API Pública
• Autenticação:
• OAuth 1.0a
• OAuth 2.0
• Documentação:
• https://meocloud.pt/developers
• Superset da API REST da Dropbox
• 40+ operações
Exemplos
• Long-polling para notificação de alterações
• Key-Value store por user e por aplicação
• Download de pasta como zip
• Thumbnails
• …
• 95% da funcionalidade do web site
Use case(s)
• Cameras + Long polling = motion sensor
• CopyRef + Proximidade = instant transfers
• Upload 2 me = transferências anónimas
Perguntas?
Obrigado

MEO Cloud - Python Lisbon Meetup

  • 1.
  • 2.
    Índice 1. MEO Cloud- apresentação 2. Backend 3. Desktop apps 4. API pública 5. Q/A
  • 3.
    MEO Cloud • Serviçode alojamento e sincronização de ficheiros • Clientes desktop para Windows, OSX e Linux (inc RPI) • Clientes mobile para iOS, Android, Windows Phone • Cifra client-side (beta) • Tráfego mobile gratuito na rede PT • Music player • Upload2Me
  • 4.
  • 5.
    Ideia inicial 1. Enviarficheiros 2. Receber ficheiros 3. ???? 4. Profit!!!
  • 6.
    Arquitectura inicial • Metadata: •BD relacional (MySQL) • Ficheiros: • Filesystem distribuído (GlusterFS) • Web app: • Nginx + Apache (mod_wsgi) + Python (Django)
  • 7.
  • 8.
    Desafios desenvolvimento • Pedidosbuffered • Muitos pedidos lentos em simultâneo • Green threads • Modelo event-driven • Expor servidor aplicacional
  • 9.
    Desafios desenvolvimento • Sincronizaçãode alterações eficiente (deltas) • Objectos (ficheiros) potencialmente grandes • librsync • dividir ficheiros em blocos <= 4MB
  • 10.
    Desafios desenvolvimento • Grandevolume de dados (e metadados) • Resiliência a falhas • Sistemas escaláveis na horizontal • Sem SPOF
  • 11.
    Desafios desenvolvimento • Deduplicaçãode dados • Hashes dos blocos
  • 12.
    Desafios desenvolvimento • Segurançada informação • Cifra em todos os passos
  • 13.
    Tecnologias usadas • Python+ gevent + Django + M2Crypto • Cassandra • Solr • Zookeeper • Swift • uWSGI • Nginx • SAPO Broker • Memcached
  • 14.
  • 15.
    requirements.txt • Django • uWSGI •gevent • greenlet • oauthlib • M2Crypto • duplicity Core
  • 16.
    requirements.txt • SAPO-Broker • requests •pycassa • kazoo • python-memcached Serviços
  • 17.
    requirements.txt • Pillow • mutagen •pybloomfiltermmap • progressbar • defusedxml • dm.xmlsec.binding • objgraph • Jinja2 Utils
  • 18.
    Desafios pós-lançamento • Soluçãocriada de raiz usando tecnologia recente (bleeding edge) • uWSGI - http parser, connector https, Gevent loop engine, cache distribuído de sessões SSL • Pycassa - connection pool && long-lived applications • Solr - SolrCloud
  • 19.
    Desafios pós-lançamento • SchemaCassandra • normalização vs desnormalização • tombstones && slice queries
  • 20.
    Desafios pós-lançamento • Swift •PUT && Rename VS store local
  • 21.
  • 22.
    Desafios pós-lançamento • Processamentonão cooperativo ou CPU bound • Muitos stacktraces, muito debugging
  • 23.
    Alguns números… • 60%imagens, 20% música, 10% vídeos • 1,2M uploads/dia - 4,8MB tamanho médio • 310K downloads/dia - 35MB tamanho médio • Compressão - BZip2 (12,4%) - Zlib (11,7%)
  • 24.
  • 25.
    Desafios • Codebase comumentre Windows, OS X e Linux • Sincronização transparente em background (daemon que reage a eventos de rede e filesystem) • Efficiente (RAM, CPU, Disco, Rede, Bateria) • Robusta/Fiável -> Just works • De longe, o maior desafio • A vossa ajuda é preciosa. Really
  • 26.
    Python 2.7 (custom)+ C Because awesome Because speed
  • 27.
    Tecnologias usadas • GUIWindows: C++, Win32 API [Jorge Cruz] • GUI OS X: Objective-C, Cocoa [Paulo Andrade] • CLI Linux: Python, gevent [Francisco Vieira] • GUI Linux: Python, GTK [Ivo Nunes]
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
    Tratamento de erros Errosdo Windows: It’s over 9000!
  • 33.
    Tratamento de erros •Não podemos pedir ao utilizador “Tente novamente mais tarde”. • Manter estado: • O que é que falhou? • Porque é que falhou? • Já avisámos o utilizador? • Quando é podemos voltar a tentar? • O problema já está resolvido? • Se é para rebentar, fazê-lo ASAP!
  • 34.
    Sistema de Ficheiros •Surpresas do Python em Windows (para quem vem do Unix) • rename() se ficheiro de destino já existe, erro • open(<path>, ‘rb’) abertura em modo exclusivo -> várias aplicações partem • readlink() (suporte para symlinks em Windows) não existe • Tesourinhos: PROGRA~1 -> Usar GetLongPathNameW() • OS X e Linux • Pop quiz: link(file1, file2); rename(file1, file2). O que acontece? Hint: é diferente de mv file1 file2
  • 35.
    Nomes de ficheiros UnicodeNormalization NFC, NFD, NFKC, NFKD
  • 36.
    Nomes de ficheiros (pequenoguia para manter a sanidade mental) • Em Windows, utilizar paths Unicode e “Long Path Names”, e.g. u’?C:file.txt' (>= Windows Vista) • Em OS X, filesystem utiliza NFD >>> unicodedata.normalize('NFC', u'João').encode('utf-8') 'Joxc3xa3o' >>> unicodedata.normalize('NFD', u'João').encode('utf-8') 'Joaxccx83o' • Em Linux, vale tudo :(
  • 37.
    Rede (Much love forpycurl and pyuv) • Reutilizar ligações para reduzir overhead handshake TCP e SSL • Transferências simultâneas • Mitigar overhead relacionado com disk seeks, deltas rsync, etc. • Minimizar efeito “dente de serra” do TCP quando a latência ou packet loss são elevados • Enviar apenas o que foi modificado (deltas rsync) • SSL/TLS: garantir que os certificados são mesmo validados. Bonus points: Certificate Pinning • Tratar timeouts, resets, stalls, outros.
  • 38.
    CPU • “O Pythoné lento” -> ineficiente, battery hog? • “O Python não consegue usar mais que um processador em simultâneo” o “drama” do GIL (Global Interpreter Lock)”
  • 39.
    CPU • O coreé IO-bound (filesystem e rede) • Tarefas que usam mais CPU implementadas em C: • Crypto (block hashes, cifra client-side, SSL) • deltas rsync • sqlite (Row objects are cool)
  • 40.
    CPU • Na verdade,o GIL é liberto em muitos casos: • Quando há IO (rede, filesystem) • Quando os módulos querem :) The GIL is free
  • 41.
    • Cython • Quandoem dúvida, profile stuff: cProfile, logs (!), etc. CPU 10x mais rápido :)
  • 42.
    Memória 6 lessons fromDropbox, on http://highscalability.com/
  • 43.
  • 44.
  • 45.
    Memória • Melhorou muitoa partir do Python 3.4 (issue #11849) • Fizemos backport do novo memory allocator (mmap/VirtualAlloc based) para o nossa versão do Python • Exemplo: Quanta RAM precisamos para sincronizar?: • 148.887 ficheiros (100.000 ficheiros aleatórios de 10KB + Linux 3.14 source tree): • Ficheiro 50GB (much data)
  • 46.
    Memória MB 100k ficheiroskernel tree ficheiro 50 GB force reclaim 50 MB RAM
  • 47.
  • 48.
    API Pública • Autenticação: •OAuth 1.0a • OAuth 2.0 • Documentação: • https://meocloud.pt/developers • Superset da API REST da Dropbox • 40+ operações
  • 49.
    Exemplos • Long-polling paranotificação de alterações • Key-Value store por user e por aplicação • Download de pasta como zip • Thumbnails • … • 95% da funcionalidade do web site
  • 50.
    Use case(s) • Cameras+ Long polling = motion sensor • CopyRef + Proximidade = instant transfers • Upload 2 me = transferências anónimas
  • 51.
  • 52.

Notas do Editor

  • #6 Feito por utilizadores ávidos da concorrência
  • #13 SSL entre clientes e os nossos servidores, e AES 128 em counter mode
  • #22 Objectos que têm referências para eles durante muito tempo, acabam por demorar muito mais tempo a ser coletados pelo GC quando finalmente deixam de ter.
  • #26 APIs diferentes: POSIX vs Win32. Filesystems diferentes ext4, NTFS, HFS, etc. APIs de eventos de fs diferentes. Sincronização: queríamos os ficheiros disponíveis offline: FUSE/WebDAV descartados
  • #27 Porquê Python? Desenvolvimento rápido Porquê C? Integração com sistemas operativos Desempenho Python 2.7 (alguns módulos ainda não são compatíveis com Python 3 - thrift) Custom stuff: assinaturas digitais, release buffers, bug fixes stat() (symlinks)
  • #30 Gostávamos de partilhar alguma coisas que aprendemos ao longo do desenvolvimento da app. Algumas delas são mais ou menos óbvias, outras apanharam-nos de surpresa. Esperamos que possam utilizar esta informação para melhorar as vossas aplicações :)
  • #31 Há muitos erros diferentes a lidar com o filesystem. Rede é relativamente fácil: timeouts e stalls -> libcurl dá-nos erros uniformes. Retry.
  • #32 Códigos de erros diferentes entre POSIX e Windows. Fomos surpreendidos por vários erros. errno 22?
  • #33 POSIX 30 e tal erros (para fs). Win32: over 9000 :)
  • #34 Point: Desenvolver uma camada de gestão de erros foi muito importante. Numa webapp, podemos safar-nos com o “tente mais tarde”. Aqui não. Lidar com erros vs esconder erros :)
  • #35 Short Path Names: MAX_PATH=260
  • #36 unicode tem várias formas. não é tão uniforme como seria esperado
  • #37 Caso real: ficheiros nfd-normalized no servidor, finder auto-refresh O que fizémos: escolher um formato interno e usá-lo (encode/decode).
  • #38 Não entrar nos subpontos! Error handling rede: é mais simples porque as libs de http dão erros uniformes
  • #39 Não queríamos que a app fosse pesada e usasse muito CPU.
  • #42 Cool stuff O GIL pode ser libertado a partir do Cython também É possível chamar código nativo (C) a partir do Cython sem overhead
  • #43 Versões alfa usavam > 1 GB de RAM para sincronizar 100.000 ficheiros A fragmentação em linguagens de scripting é complexa devido ao fraco controlo da gestão de memória
  • #44 Java resolve PyPy resolve
  • #45 Em vez de game over, o SO dá-nos mais memória
  • #46 - Módulos de eventos de filesystem não eram simpáticos (macfsevents) mmap evita o problema da fragmentação
  • #47 - Módulos de eventos de filesystem não eram simpáticos (macfsevents) mmap evita o problema da fragmentação
  • #49 Aplicações móveis usam esta API Praticamente tudo o que se faz no webclient pode ser feito através da API