O documento descreve o serviço de armazenamento na nuvem MEO Cloud, incluindo sua arquitetura backend, aplicativos de desktop e API pública. A arquitetura backend usa Cassandra para armazenamento de metadados e Swift para armazenamento de arquivos. Os aplicativos de desktop são desenvolvidos para Windows, macOS e Linux usando Python, C++ e Objective-C. A API pública oferece mais de 40 operações para acesso aos dados do usuário.
3. 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
25. 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
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
36. 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 :(
37. 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.
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
• Quando em dúvida, profile stuff: cProfile, logs (!), etc.
CPU
10x mais rápido :)
45. 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)
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 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
50. Use case(s)
• Cameras + Long polling = motion sensor
• CopyRef + Proximidade = instant transfers
• Upload 2 me = transferências anónimas
SSL entre clientes e os nossos servidores, e AES 128 em counter mode
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.
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
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)
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 :)
Há muitos erros diferentes a lidar com o filesystem.
Rede é relativamente fácil: timeouts e stalls -> libcurl dá-nos erros uniformes. Retry.
Códigos de erros diferentes entre POSIX e Windows.
Fomos surpreendidos por vários erros. errno 22?
POSIX 30 e tal erros (para fs). Win32: over 9000 :)
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 :)
Short Path Names: MAX_PATH=260
unicode tem várias formas. não é tão uniforme como seria esperado
Caso real: ficheiros nfd-normalized no servidor, finder auto-refresh
O que fizémos: escolher um formato interno e usá-lo (encode/decode).
Não entrar nos subpontos!
Error handling rede: é mais simples porque as libs de http dão erros uniformes
Não queríamos que a app fosse pesada e usasse muito CPU.
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
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
Java resolve
PyPy resolve
Em vez de game over, o SO dá-nos mais memória
- Módulos de eventos de filesystem não eram simpáticos (macfsevents)
mmap evita o problema da fragmentação
- Módulos de eventos de filesystem não eram simpáticos (macfsevents)
mmap evita o problema da fragmentação
Aplicações móveis usam esta API
Praticamente tudo o que se faz no webclient pode ser feito através da API