顯示具有 Google app engine 標籤的文章。 顯示所有文章
顯示具有 Google app engine 標籤的文章。 顯示所有文章

2013年4月12日

動態提供網頁字型開發筆記 - fonten

我在做SharePoster的時候遇到一個問題,我想讓使用者可以使用不同的字型在canvas上面寫字,但是中文字型檔太大,直接載入瀏覽器會太久,所以如何動態提供字型給canvas作圖使用呢?

問題可以分成幾個部分:

1. 動態切割字型檔
   
     一個完整中文字型檔大概要5~20mb,假如我們只使用幾個中文字就要下載全部檔案很不划算,所以如果可以讓server提供一個根據需要的文字來提供瘦身過的字型檔,這個字型檔可能只有幾kb,是原來千分之一的大小,專門用來顯示特定的文字所需要的字型。

     實際上已經有一些open source project提供這樣的切割能力,像是FontForge (Python), Sfntly (Java)。



2. 根據所需要的文字要求字型檔
 
     一般比較正常的作法是這樣,第一次送post給server告訴server準備哪些字,換取一個hash token,如果這裡是使用jQuery cross-domain post,發post之前會先發一個options詢問server是否允許哪些method的cross-domain request,確認許可之後才會發post,client根據這個token組成一個url交給css的font-face,server端必須藉由Access-Control-Allow-Origin和Access-Control-Allow-Method兩個header來回應cross-domain的請求。

     這裡需要一些改進,我原本以為字型可以像圖片一樣使用javascript拿到字型的object,或許html5要可以,事實上是無法的,規則的制定者看來沒有這樣的需求,我們只能夠組成url交給css去處理,其實這樣造成了request的浪費,比較好的狀態應該一次request就能夠拿到字型,所以在實作上我加了另一種方法,當需求文字少的時候,在client端組成font url就直接較給css處理,這樣就少了options和post這兩個request,只剩下css會發出的get request,但是換來的限制是url長度大概要在2000以下比較安全(不管舊版IE的話至少也要在4000以下)也就是encode 之前大概200個中文字比較保險。

     然後我們用一個jQuery plugin把這些方法包起來。



3. 使用字型

     還有一個問題,什麼時候可以使用字型了?

     字型載入需要時間,而且我們沒有任何獲得css font request的callback或類似onload事件的方法,如果在字型載入之前使用該字型,我們只會得到瀏覽器備用的字型(fallback font),不過或許我們可以利用這個機制來測試字型是否載入了,無法拿到event就polling吧,當字型載入的時候文字寬度和fallback字型的寬度會不同,就用這樣來測試字型是否載入了。

     這個方法也把它包在jQuery plugin裡面。


綜合以上這是一個我目前正在開發的開源項目fonten,他同時包含一個可上傳字型的server和一組API以及一個比較方便的jQuery plugin。

fonten on Github



2013年2月13日

在 virtualenv 環境使用Google App Engine

在Mac上使用python virtualenv建立GAE project
1.建立workspace
mkdir app 2.建立virtualenv
cd app virtualenv --python=python2.7 --no-site-packages venv 3.帶入GAE環境
vi venv/lib/python2.7/site-packages/gae.pth 以Mac環境為例 /usr/local/google_appengine/lib/ /usr/local/google_appengine/lib/antlr3 /usr/local/google_appengine/lib/argparse /usr/local/google_appengine/lib/cacerts /usr/local/google_appengine/lib/cherrypy /usr/local/google_appengine/lib/concurrent /usr/local/google_appengine/lib/django-1.5 /usr/local/google_appengine/lib/enum /usr/local/google_appengine/lib/fancy_urllib /usr/local/google_appengine/lib/google-api-python-client /usr/local/google_appengine/lib/graphy /usr/local/google_appengine/lib/grizzled /usr/local/google_appengine/lib/httplib2 /usr/local/google_appengine/lib/ipaddr /usr/local/google_appengine/lib/jinja2-2.6 /usr/local/google_appengine/lib/markupsafe-0.15 /usr/local/google_appengine/lib/mox /usr/local/google_appengine/lib/oauth2 /usr/local/google_appengine/lib/prettytable /usr/local/google_appengine/lib/protorpc /usr/local/google_appengine/lib/PyAMF-0.6.1 /usr/local/google_appengine/lib/python-gflags /usr/local/google_appengine/lib/setuptools-0.6c11 /usr/local/google_appengine/lib/simplejson /usr/local/google_appengine/lib/sqlcmd /usr/local/google_appengine/lib/webapp2-2.5.2 /usr/local/google_appengine/lib/webob-1.2.3 /usr/local/google_appengine/lib/yaml-3.10 可以使用以下指令稍作修正 find /usr/local/google_appengine/lib/ -type d -maxdepth 1 4.安裝需要的模組

2013年1月16日

Python 2.7 on Google App Engine (Google IO 2012)




1. python 2.7 環境相容 python 2.5語法
2. WSGI instead of CGI
3. numpy, PIL, jinja2, json, lxml, markupsafe, PyAMF, pycrypto, webapp2, webob 和一些重要python library在python 2.7環境已經支援(還是沒有requests!)
4. ndb, new datastore 自動 memory cache, 可以同時做不同entities atomic transaction
5. 得益於python 2.7本身威能,cPickle, cStringIO 等整體效能增加
6. 同一個instance可以處理一個以上的request(concurrent request),而不是建立新的instance, 在yaml裡建立threadsafe即可使用



7. StructureProperty 有點類似mongodb可以儲存任意結構,還是可以做index(cost和top level index相同),和 ReferenceProperty 做關連不同(join 2 logical entities)。

2012年11月13日

處理Google App Engine Transaction Collision

使用Google App Engine以來比較麻煩的就是先天上的限制,曾經遇過比較雞屎的缺點像是
1000筆查詢結果(已改善)、django版本問題、資料結構貧乏、沒有Quota Alarm、對於負面表列的query非常薄弱之外,還有就是transaction collision問題

Transaction Collision問題標準解法通常是用shard,分片儲存來處理大量更新請求,這在於一開始設計資料結構就能洞悉哪些entity將來會需要大量更新,不太精實,尤其後來使用HA後,shard還不能在同一個entity group中,這樣要直接取用或是做query都會變得比較麻煩,也不適合已經不想去修改以前自己留下來的屎的心境。

Transaction Collision問題也可以使用retry,這個方法最簡單,但是對於一次請求要更新不同entity group的情況來說比較麻煩,要自己處理rollback,而且retry對於整體情況沒有減緩作用,比較適合當輔助效果。

Transaction Collision問題也可以使用bulk update,把原本會發生碰撞的request做結合,用記憶體合併請求一次更新,最後再用task queue確保正確性,這樣一來可以減少絕大多數的資料庫更新次數,碰撞發生微乎其微,更可以減少datastore operation節省美金。






2012年6月10日

使用 AWS 筆記 (一) 選擇Amazon EC2


Amazon EC2還沒用之前感覺非常困難,一直沒有機會使用(逃避)

背景是這樣:

GAE (python) 我使用了一年多,漲價之後就沒有太大優勢,具有環境的特殊性限制,以及環境綁定的寫作方式,我目前把他定位成一個運算工具,而不是一個適合放完整大型網站的地方,但是用來做crawler, simple task worker, cron jobs等工作仍然是我的首選,開發時間短,而且免費quota足夠做非常多事情。

Heroku 簡單容易上手,而且支援算是完整,預設git版本控制簡直美妙,add-ons生態系經營的相當好,目前缺點就是貴以及不夠快(亞洲),網站每慢0.1秒就會損失1%的使用者,還有看log的速度我無法接受,花錢也無法解決的問題是個難題,但是如果要做mvp,或是專案時間緊迫要上線,Heroku是首選。

Linode 有考慮過但還是不能滿足這次的需求,我們的目標是百萬使用者,也達到過這樣的目標(not slashdotted),所以scalability是一個實際會發生的問題,加上我們規劃將來後端分散式處理資料的可擴充性,VPS在這方面是比較不足的,或許AWS一年優惠用完,又生不出使用者的時候我們可以考慮躲進來。

AWS 我逼不得已來到了 IAAS 這一層(我學網頁當初只是想寫前端javascript阿,什麼時候下到這層了! ),Amazon EC2目前無人能出其右,先花一個小時翻過一遍神人Hank Lin的AWS雲端企業實戰聖經,內容很多很詳細很值得購買,只是寫的時間比較早,如果有2012版我會更推薦,之後又大概看了Python and AWS Cookbook,裡面主要是講用boto (python)這個工具來建立和控制Amazon的許多Cloud Service,這和使用powershell來控制Vmware Virtual Machine有異曲同工之妙,先放著以後會用到。

使用AWS第一個問題就是名詞縮寫太多了,節錄wiki資料來對照使用,看起來跟vmare提供的服務差不多,但是真正使用起來我相信有非常長的路要走...

List of AWS products

  • Amazon AWS Authentication, an implicit service, the authentication infrastructure used to authenticate access to the various services.
  • Amazon CloudFront, a content delivery network (CDN) for distributing objects to so-called "edge locations" near the requester.
  • Amazon CloudWatch, provides monitoring for AWS cloud resources and applications, starting with EC2.
  • Amazon DevPay, currently in limited beta version, is a billing and account management system for applications that developers have built atop Amazon Web Services.
  • Amazon Elastic Beanstalk provides quick deployment and management of applications in the cloud.
  • Amazon Elastic Block Store (EBS) provides persistent block-level storage volumes for EC2.
  • Amazon Elastic Compute Cloud (EC2) provides scalable virtual private servers using Xen.
  • Amazon Elastic MapReduce allows businesses, researchers, data analysts, and developers to easily and cheaply process vast amounts of data. It uses a hosted Hadoop framework running on the web-scale infrastructure of EC2 and Amazon S3.
  • Amazon ElastiCache provides in-memory caching for web applications.
  • Amazon Flexible Payments Service (FPS) provides an interface for micropayments.
  • Amazon Fulfillment Web Service provides a programmatic web service for sellers to ship items to and from Amazon using Fulfillment by Amazon.
  • Amazon Historical Pricing provides access to Amazon's historical sales data from its affiliates. (It appears that this service has been discontinued.)
  • Amazon Mechanical Turk (Mturk) manages small units of work distributed among many humans.
  • Amazon Product Advertising API formerly known as Amazon Associates Web Service (A2S) and Amazon E-Commerce Service (ECS), provides access to Amazon's product data and electronic commerce functionality.
  • Amazon Relational Database Service (RDS) provides a scalable database server with MySQL and Oracle support.
  • Amazon Route 53 provides a highly available and scalable Domain Name System (DNS) web service.
  • Amazon CloudSearch, currently in limited beta version, provides basic full text search and indexing of textual content.
  • Amazon Simple Email Service (SES) provides bulk and transactional email sending.
  • Amazon Simple Storage Service (S3) provides Web Service based storage.
  • Amazon Simple Queue Service (SQS) provides a hosted message queue for web applications.
  • Amazon Simple Notification Service (SNS) provides a hosted multiprotocol "push" messaging for web applications.
  • Amazon Simple Workflow (SWF) is a workflow service for building scalable, resilient applications.
  • Amazon SimpleDB, allows developers to run queries on structured data. It operates in concert with EC2 and S3 to provide "the core functionality of a database."
  • Amazon Virtual Private Cloud (VPC) creates a logically isolated set of Amazon EC2 instances which can be connected to an existing network using a VPN connection.
  • AWS CloudFormation, create a collection of related AWS resources and provision them in an orderly and predictable fashion.
  • AWS Import/Export, accelerates moving large amounts of data into and out of AWS using portable storage devices for transport.
  • AWS Management Console (AWS Console), A web-based point and click interface to manage and monitor the Amazon infrastructure suite including EC2, EBS, Amazon Elastic MapReduce, and Amazon CloudFront.
  • AWS Storage Gateway, an iSCSI block storage appliance with cloud-based backup.




下一篇 使用 AWS 筆記 (二) 建立EC2 instance










2012年4月27日

Python Tornado 初體驗

玩Python沒有造輪子問題,倒是常常有選輪子問題,Tornado是一個non-blocking, single-treaded Web framework,當時被收購且用來做facebook real-time framework,現在是一個開源專案,可以看看facebook連結中的benchmark就知道這個非同步框架處理request的威力了,有趣的是這個專案在friendfeed的時候是由前Google員工開發的,所以看起來跟Google App Engine有幾分神似,不只處理大量request有如神助,在template render上也比Django快上一個等級,不過這從來不是一般網頁慢的原因(通常是DB慢或是駕駛員本身程式問題),使用tornado只是爽度和虛榮心使然。 tornado使用python 2.7時需要安裝pycurl 7.18.2以上 pip install pycurl==7.19.0 pip install tornado 然後我們可以參考一些tornado的範例程式

2012年3月19日

Google App Engine with Jinja2 template

使用了Google App Engine python 2.7之後,我們發現webapp.template was deprecated,雖然webapp2的legacy support很好,但是我們還是來玩玩看新的東西吧 -- Jinja2,這是經過多方搜尋的結果決定的,其他template或框架的選擇有Django, Flask, Mako, WerkZeug等等,也考慮直接用string.Template),我用Google App Engine一直以來的心得就是『順著官方的意思走』,否則將來自己要維護更新的東西會越來越多,所以我選了Jinja2,速度接近Mako(其實模板速度從來不是重點),語法接近Django(有人抱怨吃太多記憶體),還有語法上許多貼心的改進

要注意
1.Autoescaping is not the Default

在GAE上使用Jinja2
app.yaml上設定

libraries:
- name: jinja2
version: "2.6"


Jinja的Environment是他的核心,所以先建立Environment再做render

import os
import jinja2

#setup environment for 'templates' folder
jinja_env = jinja2.Environment(
loader=jinja2.FileSystemLoader(
os.path.join(os.path.dirname(__file__), 'templates')))

jinja_env.get_template('index.html').render(data)


接下來看著文件就可以用了
Jinja2語法範例
Jinja2 filter

參考資料
Using Jinja2 Templates
Migrating to Python 2.7, part 2: Webapp and templates
Jinja2 for webapp2官方
Use Jinja2 template engine in webpy

2012年3月18日

Google App Engine Python 2.5 to 2.7升級

升級的原因主要是因為GAE Python 2.7支援Multithreading、Sandboxing,可支援更多非pure python lib,可單獨使用.pyc檔當作執行檔,支援像是jinja2, lxml, PIL, webapp2等,python 2.7更原生支援json比django.simplejson速度快上許多,我逐漸把開發重心轉移到client javascript上,所以可預期server會有許多json的運算工作。

需要修改的幾個容易忽略的部份:

1.必須使用High Replication
2.app.yaml中指定controller直接對應到python檔中的webapp2.WSGIApplication,不再使用google.appengine.ext.webapp的util.run_wsgi_app,也不再使用main()
3.原本headers有用unicode的部份要改成str

2011年11月14日

第一次被贊助

Google App Engine最近更新和漲價動作讓他更瞄準了企業級的用戶
我的開支也瞬間變成企業級的
在重新調整網站的演算法、增加cache、減少server instance等措施後仍然沒有太多的幫助
我只能暫時限制網站使用時間並且向使用者說明原因

然後我昨天收到第一筆贊助了 - 來自菲律賓
I adopt first donation from Joseph Bolos. Thank you Joseph Bolos.

網站廣告真的影響介面,也無法讓小開發者存活
而第一個贊助的10元美金,讓我暫時放棄了關站的想法
年紀大了真的很容易被感動

我今天又收到第二和第三筆小額贊助了 真的是感恩阿

2011年11月1日

GAE Unit Test

主要參考Local Unit Testing for Python
測試時會建立模擬的server,在記憶體中完成,不會更改到實際Dev環境或是DataStore
gaeunit - 用web呈現但未來似乎不易串接進CI,且目前沒有對測試頁面做權限控管

使用nosegae 0.1.9搭配gaetestbed - 目前已經慢慢整合到官方的SDK

安裝

$ sudo easy_install nose
$ sudo easy_install nosegae
$ sudo easy_install webtest
$ sudo easy_install gaetestbed


test檔
請以test為開頭,實際上是符合(?:^|[b_.-])[Tt]est
雖然文件說你可以使用--match來執行特定的test檔案 但是實際上測試就是會有ImportError

遇到ImportError問題的人非常多
有人test檔名有問題
有人webtest版本不正確
有人easy_install.pth預設路徑磁碟是小寫和abspath吐出來的大寫名稱不同
也有人沒有建立tests package(tests folder with empty __init__.py)

我自己是遇到google picasa API裡面一堆test檔有問題
使用--exclude和--ignore(文件說優先權最高) 但還是在第一次掃描的時後掃描到有問題
第一次掃描似乎無可避免
另外--gae-application這個參數也有問題,還是會找不到project
我認為這些東西原本應該是好的,但是因為太多外掛造成的Issue

找到比較穩的方法如下
在project root底下建立tests package
test file開頭使用test

project
|---- tests
|---- __init__.py
|---- test_file1.py
|---- test_file2.py

執行nosetests時,到project root下執行
避免使用--match, --exclude, --ignore, --gae-application來處理問題
可以使用-vv和--collect-only來debug

執行

nosetests --with-gae --gae-lib-root="/path/to/google_appengine" tests


之後就可以參考gaetestbed來寫test case

開始跑WebTestCase仍然遇到問題
如果python版本是2.4 2.5應該會遇到
ValueError: dictionary update sequence element #0 has length 1; 2 is required
如果python版本是2.6以上可能會有
AttributeError: 'unicode' object has no attribute 'items'

trace code發現webtest 1.3.2中app.py第1028行傳header給Cookie.py去做設定
這裡header已經是unicode,但是在Cookie.py中預期得到bytestring或是dict
我選擇對Cookie.py進行修正

if isinstance(rawdata, unicode):
rawdata = str(rawdata)


終於可以跑unit test了 好感動
有人可以教我oauth 2.0登入的web application如何做funcitonal unit test嗎?

額外名詞學習:
mock - 行為測試
stub - 結果測試

2011年10月13日

GAE update index error

GAE版本1.5.5

錯誤
Error: 500 Server Error
和
Error 400: --- begin server output ---
Cannot build indexes that are in state ERROR.

主因一開始是改寫GQL條件後,沒有先update index(或自動設定情況下local端先跑過query)就上傳到google server,第一個出現的錯誤是NeedIndexError,想更新index卻中了五月就說修好的issue,部份index卡在Error State,參考以下步驟自行解決

1. 備份index.yaml
2. 將index.yaml去掉有問題的index
3. 執行appcfg.py vacuum_indexes app_dir
4. 一直等,直到有問題的index被清除,可能需要數小時,也可能數小時之後無效,重新執行步驟3
5. 還原index.yaml 執行 appcfg.py update_indexes app_dir

2010年9月8日

GAE subquery

最近有一個需求是檢查某一個清單成員是否位於另一個清單之中
原本的作法很直覺的使用一個迴圈跑GQL查詢where member IN somelist
做簡單測試的時候也沒什麼問題
但是跑實際資料的時候會發生
BadArgumentError: Cannot satisfy query -- too many subqueries (max: 30, got 390). 
Probable cause: too many IN/!= filters in query.
由於GQL實做不等式比對其實是跑多個subquery子查詢 然後把結果聯集在一起
但是從錯誤訊息看起來subquery的上限是30個, 在此情況也就是somelist最多只能有30個項目!
只能查30個能做什麼事情 拿來查是不是冠酉的相好都不夠了
不知道這個功能原本設計用來做什麼 還是我誤用了這個功能嗎

2010年8月8日

Google App Engine Note

1. GqlQuery目前1.3.5版可以做某個屬性對一個ListProperty的不等式查詢(如!=, IN) 但是Query的filter()只能做屬性對單一值的不等式查詢,這是不太一樣的地方,而且不等於的查詢實際上是拆成大於和小於兩個查詢之後取"聯集",這點在我的case裡面非常的不直覺也非常不好用,整體說起來,用GQL比較適合正向表列搜尋,對於ListProperty很難去搜尋"除此條件之外"的實體

2. 目前的dev版本的appserver一次只能對應一個http connection, 所以如果背景有同時在跑一些ajax的東西的話有可能會接到錯誤訊息(10053, 'Software caused connection abort'),如Facebook Javascript SDK

3.自己用single sign-on開發網頁的時候遇到怎麼有時後點fb:login無法登入,還會得到"FB.login() called when user is already connected."的錯誤訊息,檢查之後才發現Facebook給的cookie怎麼好像過期不見了,但是新的cookie又沒有被Javascript SDK抓下來,這是因為localhost在外部是看不到的,可以用一些工具來輔助或是等deploy之後再測試

2010年7月27日

ListProperty in Google App Engine

今天看到一個實在非常棒的教學
http://code.google.com/intl/zh-TW/events/io/2009/sessions/BuildingScalableComplexApps.html

我在建立應用程式的時候一直覺得List Property是很重要的特色
因為他的讀取和寫入都是平行式處理 一次修改全部的值也不會變得特別慢

但是限制很多
比如說擁有不用很多個的多重值的實體就可以讓實體的index爆掉
因為在big table中儲存的索引數量是「每個屬性值排列」的總數
另一點單一實體不能超過1MB的限制也讓我想服務大量的facebook使用者感到力不從心
還有一個是在影片中提到的serialize&desecrialize的時間也不盡離想
往往我們會用list來做query但是我們關心的是其他屬性的內容
這些serialize和deserialize的時間是沒有必要的花費

所以可以把list屬性獨立出另一個實體為原實體的child
搜尋完之後再用parent()方法找出我們關心的內容
雖然單一list有5000筆的限制 但是可以使用多個child指向同一個parent
這樣一來上面的問題全部都解決了 速度也快了好幾倍

2010年7月19日

Facebook/Google app engine 開發筆記

1. facebook-python-sdk-2da0f67的oauth直接使用OAuth 2.0對https://graph.facebook.com/oauth/access_token?要求token以外,其他example是使用Javascript SDK來取得權限,然後使用facebook.py來控制cookie和一些簡單的object的操作,所以要確認facebook.py能夠被應用程式找到,並且html標籤屬性需要添加xmlns:fb="http://www.facebook.com/2008/fbml"使IE8能把xfbml給render出來,Chrome和Firefox則不需要(why?)

2.使用localhost來開發測試(Connect URL和Canvas Callback),在IE8中會遇到"API Error Code: 100""Error Message: next is not owned by the application."的問題,困擾好久,正式上傳之後反而沒有這個問題,另外在html檔中<!DOCTYPE>也要清楚定義讓IE8看的懂才行