<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;DkcGQ3c9cCp7ImA9WhRUFEQ.&quot;"><id>tag:blogger.com,1999:blog-9735843</id><updated>2012-01-25T20:20:22.968+08:00</updated><category term="Connection Pool" /><category term="心情記事" /><category term="GAE" /><category term="喔~鋼普拉" /><category term="Jetty" /><category term="阿殺不魯" /><category term="程式語言" /><category term="Android" /><category term="java" /><category term="電影、戲劇" /><category term="敗~敗家啦" /><category term="Cassandra" /><title>老涂的咁仔店</title><subtitle type="html">&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;記載生活點滴、敗家記事、程式撰寫...etc</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://cloudtu.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://cloudtu.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Cloud Tu</name><uri>https://profiles.google.com/103480569436521613170</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-d8rzsEF047s/AAAAAAAAAAI/AAAAAAAAAbA/AXih8jz304M/s512-c/photo.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>369</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/blogspot/pvDgV" /><feedburner:info uri="blogspot/pvdgv" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;DUYBR349fCp7ImA9WhRVGEs.&quot;"><id>tag:blogger.com,1999:blog-9735843.post-5695417139444050659</id><published>2012-01-18T14:12:00.000+08:00</published><updated>2012-01-18T14:12:36.064+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-18T14:12:36.064+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="Cassandra" /><title>Cassandra的cqlsh安裝步驟</title><content type="html">這篇的說明是以Cassandra 1.0.6版為基準，早期版本可能沒有cqlsh功能。此外，在系統中已先自行建立testks keyspace，並在裡面建了employee columnfamily。&lt;br /&gt;
&lt;br /&gt;
cqlsh功能簡述如下&lt;br /&gt;
在Cassandra 1.x版後，除了cassandra-cli之外，在 &lt;span style="color: #274e13;"&gt;/cassandra_install_folder/bin&lt;/span&gt; 裡多了個cqlsh的指令。該指令跟cassandra-cli一樣是個client端工具，可用來連線至server端進行資料維護與查詢。cqlsh有個很大的好處，那就是「支援CQL語法操作」，要查資料時比用cassandra-cli來的輕鬆；但是...也有個很大的問題，cqlsh是在python之上執行，如果OS本身沒裝python，cqlsh就變成看的到吃不到的功能。至於要怎麼安裝?官網完全沒跟你講，也就是說...如果你完全不懂python，你根本連裝都不會裝，更不用提怎麼用了...囧rz&lt;br /&gt;
&lt;br /&gt;
安裝cqlsh可參考下列步驟&lt;br /&gt;
===========================================================================&lt;br /&gt;
Ubuntu linux平台的安裝方式如下&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;利用synaptic安裝python 2.7。安裝完成後執行下面這行指令可以看到python顯示2.7的版本號。&lt;br /&gt;&lt;span style="color: #274e13;"&gt;python -V&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt; 利用synaptic安裝python-setuptools，python-setuptools必需是給python 2.7使用的版本。&lt;br /&gt;&lt;br /&gt;如果想自行手動安裝python-setuptools，則是可以至&lt;a href="http://pypi.python.org/pypi/setuptools#downloads" target="_blank"&gt;官網&lt;/a&gt;下載 setuptools-0.6c11-py2.7.egg，並執行下面這行指令進行安裝。&lt;br /&gt;&lt;span style="color: #274e13;"&gt;sudo sh setuptools-0.6c11-py2.7.egg&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;python-setuptools安裝完成後，執行下面這行指令可看到easy_install指令的相關說明。&lt;br /&gt;&lt;span style="color: #274e13;"&gt;easy_install -h&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;接著執行下面這行指令，將cql模組裝到python。&lt;br /&gt;&lt;span style="color: #274e13;"&gt;sudo easy_install cql&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
完成上述的步驟後就可以使用cqlsh的功能了，cqlsh基本操作簡述如下。&lt;br /&gt;
1.執行下面這行指令，可查看cqlsh使用說明。&lt;br /&gt;
&lt;div style="color: #274e13;"&gt;
cqlsh -h&lt;/div&gt;
&lt;br /&gt;
2.如果Cassandra不需帳號密碼就可登入，可執行下面這行指令登入系統。&lt;br /&gt;
&lt;span style="color: #274e13;"&gt;cqlsh 127.0.0.1 9160 &lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
3.如果Cassandra要帳號密碼才可以登入，可執行下面這行指令登入系統。&lt;br /&gt;
&lt;span style="color: #274e13;"&gt;cqlsh -u admin -p adminpwd 127.0.0.1 9160&lt;/span&gt; &lt;br /&gt;
&lt;br /&gt;
4.登入系統後可以利用CQL語法進行各項操作。&lt;br /&gt;
&lt;pre class="brush: text"&gt;cloudtu@cloudtu-VirtualBox:~/cassandra-1.0.6-1/bin$ ./cqlsh 127.0.0.1 9160
Connected to Test Cluster at 127.0.0.1:9160.
[cqlsh 2.0.0 | Cassandra 1.0.6 | CQL spec 2.0.0 | Thrift protocol 19.19.0]
Use HELP for help.
cqlsh&amp;gt; use testks;
cqlsh:testks&amp;gt; select * from employee;
 KEY | age | dept |     name |
   3 |   3 |   rd |  tester3 |
   6 |   6 |  mis |  tester6 |
   5 |   5 |   rd |  tester5 |
  19 |  19 |   rd | tester19 |
  10 |  10 |  mis | tester10 |
   8 |   8 |  mis |  tester8 |
   2 |   2 |  mis |  tester2 |
  16 |  16 |  mis | tester16 |
  13 |  13 |   rd | tester13 |
   1 |   1 |   rd |  tester1 |
  12 |  12 |  mis | tester12 |
   9 |   9 |   rd |  tester9 |
  14 |  14 |  mis | tester14 |
   4 |   4 |  mis |  tester4 |
  15 |  15 |   rd | tester15 |
  11 |  11 |   rd | tester11 |
  20 |  20 |  mis | tester20 |
  18 |  18 |  mis | tester18 |
   7 |   7 |   rd |  tester7 |
  17 |  17 |   rd | tester17 |

cqlsh:testks&amp;gt; quit;
cloudtu@cloudtu-VirtualBox:~/cassandra-1.0.6-1/bin$ 
&lt;/pre&gt;
===========================================================================&lt;br /&gt;
Win7 X64平台的安裝方式如下 &lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;至&lt;a href="http://python.org/getit/" target="_blank"&gt;官網&lt;/a&gt;下載python 2.7 x64版本進行安裝，安裝目錄設到 &lt;span style="color: #274e13;"&gt;C:\Python\Python27&lt;/span&gt;。&lt;/li&gt;
&lt;li&gt;在環境變數的Path參數裡加入python.exe所在目錄(e.g. Path=C:\Python\Python27;...etc)&lt;br /&gt;&lt;br /&gt;安裝完成後執行下面這行指令可以看到python顯示2.7的版本號。&lt;br /&gt;&lt;span style="color: #274e13;"&gt;python -V&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt; 至&lt;a href="http://pypi.python.org/pypi/setuptools#windows" target="_blank"&gt;官網&lt;/a&gt;下載ez_setup.py，執行下面這行指令安裝python-setuptools。&lt;br /&gt;&lt;span style="color: #274e13;"&gt;python ez_setup.py&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;python-setuptools安裝完成後，切換到 &lt;span style="color: #274e13;"&gt;C:\Python\Python27\Scripts&lt;/span&gt;，執行下面這行指令可看到easy_install指令的相關說明。&lt;br /&gt;&lt;span style="color: #274e13;"&gt;easy_install -h&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;接著執行下面這行指令，將cql模組裝到python。&lt;br /&gt;&lt;span style="color: #274e13;"&gt;easy_install cql&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
完成上述的步驟後就可以使用cqlsh的功能了，cqlsh基本操作簡述如下。&lt;br /&gt;
1.執行下面這行指令，可查看cqlsh使用說明。&lt;br /&gt;
&lt;div style="color: #274e13;"&gt;
python cqlsh -h&lt;/div&gt;
&lt;br /&gt;
2.如果Cassandra不需帳號密碼就可登入，可執行下面這行指令登入系統。&lt;br /&gt;
&lt;span style="color: #274e13;"&gt;python cqlsh 127.0.0.1 9160 &lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
3.如果Cassandra要帳號密碼才可以登入，可執行下面這行指令登入系統。&lt;br /&gt;
&lt;span style="color: #274e13;"&gt;python cqlsh -u admin -p adminpwd 127.0.0.1 9160&lt;/span&gt; &lt;br /&gt;
&lt;br /&gt;
4.登入系統後可以利用CQL語法進行各項操作。&lt;br /&gt;
&lt;pre class="brush: text"&gt;Z:\apache-cassandra-1.0.6\bin&amp;gt;python cqlsh 127.0.0.1 9160
Connected to Test Cluster at 127.0.0.1:9160.
[cqlsh 2.0.0 | Cassandra 1.0.6 | CQL spec 2.0.0 | Thrift protocol 19.19.0]
Use HELP for help.
cqlsh&amp;gt; use testks;
cqlsh:testks&amp;gt; select * from employee;
 KEY | age | dept |     name |
   3 |   3 |   rd |  tester3 |
   6 |   6 |  mis |  tester6 |
   5 |   5 |   rd |  tester5 |
  19 |  19 |   rd | tester19 |
  10 |  10 |  mis | tester10 |
   8 |   8 |  mis |  tester8 |
   2 |   2 |  mis |  tester2 |
  16 |  16 |  mis | tester16 |
  13 |  13 |   rd | tester13 |
   1 |   1 |   rd |  tester1 |
  12 |  12 |  mis | tester12 |
   9 |   9 |   rd |  tester9 |
  14 |  14 |  mis | tester14 |
   4 |   4 |  mis |  tester4 |
  15 |  15 |   rd | tester15 |
  11 |  11 |   rd | tester11 |
  20 |  20 |  mis | tester20 |
  18 |  18 |  mis | tester18 |
   7 |   7 |   rd |  tester7 |
  17 |  17 |   rd | tester17 |

cqlsh:testks&amp;gt; quit;

Z:\apache-cassandra-1.0.6\bin&amp;gt;
&lt;/pre&gt;
===========================================================================&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9735843-5695417139444050659?l=cloudtu.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/pvDgV/~4/wkttTi_cmd8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://cloudtu.blogspot.com/feeds/5695417139444050659/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=9735843&amp;postID=5695417139444050659" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/5695417139444050659?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/5695417139444050659?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/pvDgV/~3/wkttTi_cmd8/cassandracqlsh.html" title="Cassandra的cqlsh安裝步驟" /><author><name>Cloud Tu</name><uri>https://profiles.google.com/103480569436521613170</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-d8rzsEF047s/AAAAAAAAAAI/AAAAAAAAAbA/AXih8jz304M/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://cloudtu.blogspot.com/2012/01/cassandracqlsh.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEcMQX04fSp7ImA9WhRWFks.&quot;"><id>tag:blogger.com,1999:blog-9735843.post-1932904176193668864</id><published>2012-01-04T14:49:00.001+08:00</published><updated>2012-01-04T16:34:40.335+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-04T16:34:40.335+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="Cassandra" /><title>Cassandra的Snitch、ReplicationStrategy功能與關聯</title><content type="html">這篇的說明是以Cassandra 1.x版為基準，早期版本可能不是這樣。&lt;br /&gt;
&lt;br /&gt;
接著...進入正題，先來個名詞解釋!&lt;br /&gt;
&lt;br /&gt;
Snitch：用來設定cassandra ring裡的node怎麼分群。如果所有node都在同個網段時(e.g. 172.16.0.x)這部份可用預設SimpleSnitch設定不需修改，如果各個node分布的硬體在多個dc(datacenter)或是多個rank，而且各個node的網段又完全不同的話，這部份就要改設定，不然cassandra ring可能會串不起來。半官方解說在&lt;a href="http://www.datastax.com/docs/1.0/cluster_architecture/replication#about-snitches" target="_blank"&gt;這裡&lt;/a&gt;。可以設定的值有下列儿種&lt;br /&gt;
* SimpleSnitch&lt;br /&gt;
* DseSimpleSnitch&lt;br /&gt;
* RackInferringSnitch&lt;br /&gt;
* PropertyFileSnitch&lt;br /&gt;
* EC2Snitch&lt;br /&gt;
* EC2MultiRegionSnitch&lt;br /&gt;
&lt;br /&gt;
Replication Strategy：根據Snitch設定值的不同，當建立新keyspace時所需對應設定的參數。半官方解說在&lt;a href="http://www.datastax.com/docs/1.0/configuration/storage_configuration#placement-strategy" target="_blank"&gt;這裡&lt;/a&gt;。可以設定的值有下列儿種&lt;br /&gt;
* SimpleStrategy&lt;br /&gt;
* NetworkTopologyStrategy&lt;br /&gt;
&lt;br /&gt;
看完上面這堆後，真的知道它是怎麼一回事的，應該沒多少人。覺的文件像在講外星語是很正常的，所以接下來直接來看實作吧。看完實作後再回頭來看前面的名詞解釋，就會了解是怎麼一回事了。&lt;br /&gt;
&lt;br /&gt;
實作的機器有下面二台&lt;br /&gt;
Cassandra Server1：172.16.0.157&lt;br /&gt;
Cassandra Server2：172.16.0.220&lt;br /&gt;
&lt;br /&gt;
因為Snitch跟Replication Strategy要搭配才會發生效用，然後這二台機器又在同個網段(172.16.0.X)，所以可以用最簡單也是最常用的搭配組合「SimpleSnitch + SimpleStrategy」。官方文件中最常見的介紹方式也是這個組合。&lt;br /&gt;
&lt;br /&gt;
===========================================================================&lt;br /&gt;
SimpleSnitch + SimpleStrategy設定方式&lt;br /&gt;
1.修改二個node的cassandra.yaml的設定&lt;br /&gt;
&lt;pre class="brush: text"&gt;endpoint_snitch: org.apache.cassandra.locator.SimpleSnitch&lt;/pre&gt;
2.用nodetool進行測試，會發現結果中的dc被命名為datacenter1，rank則是rack1，這二個部份無法手動調整&lt;br /&gt;
&lt;pre class="brush: text"&gt;loudtu@cloudtu-VirtualBox:~/cassandra-1.0.6-1/bin$ ./nodetool -h 127.0.0.1 ring
Address         DC          Rack        Status State   Load            Owns    Token                                       
                                                                               85070591730234615865843651857942052864      
172.16.0.220    datacenter1 rack1       Up     Normal  123.46 KB       50.00%  0                                           
172.16.0.157    datacenter1 rack1       Up     Normal  111.73 KB       50.00%  85070591730234615865843651857942052864
&lt;/pre&gt;
3.建立新的keyspace。配合SimpleSnitch，有其對應的SimpleStrategy語法。範列中{replication_factor:2}指的是&lt;span style="color: #274e13;"&gt;{replication_factor:number_of_replicas}&lt;/span&gt;&lt;br /&gt;
&lt;pre class="brush: text"&gt;create keyspace testks
    with strategy_options=[{replication_factor:2}]
    and placement_strategy = 'org.apache.cassandra.locator.SimpleStrategy';
&lt;/pre&gt;
===========================================================================&lt;br /&gt;
&lt;br /&gt;
如果多個node的IP是跨不同網段(e.g. "110.82.155.1"、"110.82.156.1")，這時可以用「RackInferringSnitch+NetworkTopologyStrategy」的組合。半官方的範例在&lt;a href="http://www.datastax.com/docs/1.0/install/cluster_init#initializing-a-multi-node-or-multi-data-center-cluster" target="_blank"&gt;這裡&lt;/a&gt;。雖然說一般是跨網段時才要這樣設定，但是在同個網段內也是可以這樣設定，只是node會被分配在同個datacenter或是rank。&lt;br /&gt;
&lt;br /&gt;
===========================================================================&lt;br /&gt;
RackInferringSnitch + NetworkTopologyStrategy設定方式&lt;br /&gt;
1.修改二個node的cassandra.yaml的設定&lt;br /&gt;
&lt;pre class="brush: text"&gt;endpoint_snitch: org.apache.cassandra.locator.RackInferringSnitch&lt;/pre&gt;
2.用nodetool進行測試，會發現結果中的dc被命名為16，rank則是0，這二個部份無法手動調整。但是這個命名是有規則的，相關規則可參照&lt;a href="http://www.datastax.com/docs/1.0/cluster_architecture/replication#rackinferringsnitch" target="_blank"&gt;這裡&lt;/a&gt;的說明。&lt;br /&gt;
&lt;pre class="brush: text"&gt;cloudtu@cloudtu-VirtualBox:~/cassandra-1.0.6-1/bin$ ./nodetool -h 127.0.0.1 ring
Address         DC          Rack        Status State   Load            Owns    Token                                       
                                                                               85070591730234615865843651857942052864      
172.16.0.220    16          0           Up     Normal  107.69 KB       50.00%  0                                           
172.16.0.157    16          0           Up     Normal  111.83 KB       50.00%  85070591730234615865843651857942052864 
&lt;/pre&gt;
3.建立新的keyspace。配合RackInferringSnitch，有其對應的NetworkTopologyStrategy語法。範列中{16:2}指的是&lt;span style="color: #274e13;"&gt;{datacenter_name:number_of_replicas}&lt;/span&gt;&lt;br /&gt;
&lt;pre class="brush: text"&gt;create keyspace testks
    with strategy_options=[{16:2}]
    and placement_strategy = 'org.apache.cassandra.locator.NetworkTopologyStrategy';
&lt;/pre&gt;
===========================================================================&lt;br /&gt;
&lt;br /&gt;
如果「RackInferringSnitch+NetworkTopologyStrategy」的組合還是無法滿足實務上的需求，想要更有彈性，則是可以考慮「PropertyFileSnitch + NetworkTopologyStrategy」的組合。半官方的範例在&lt;a href="http://www.datastax.com/docs/1.0/cluster_architecture/cluster_planning#configuring-the-propertyfilesnitch" target="_blank"&gt;這裡&lt;/a&gt;。在這種組合的設定裡，連dc、rank的名字都可以自己設定。&lt;br /&gt;
&lt;br /&gt;
===========================================================================&lt;br /&gt;
PropertyFileSnitch + NetworkTopologyStrategy設定方式&lt;br /&gt;
1.修改二個node的cassandra.yaml的設定 &lt;br /&gt;
&lt;pre class="brush: text"&gt;endpoint_snitch: org.apache.cassandra.locator.PropertyFileSnitch&lt;/pre&gt;
2.因為設定成PropertyFileSnitch，所以接著必需到二個node的cassandra-topology.properties設定所有node的IP與其相對應的dc與rank。&lt;br /&gt;
&lt;pre class="brush: text"&gt;# Data Center One
172.16.0.157=DC1:RAC1

# Data Center Two
172.16.0.220=DC2:RAC1

# default for unknown nodes
default=DC1:RAC1
&lt;/pre&gt;
&lt;br /&gt;
3.用nodetool進行測試，會發現結果中的dc與rank的名稱是來自於cassandra-topology.properties裡的設定。&lt;br /&gt;
&lt;pre class="brush: text"&gt;cloudtu@cloudtu-VirtualBox:~/cassandra-1.0.6-1/bin$ ./nodetool -h 127.0.0.1 ring
Address         DC          Rack        Status State   Load            Owns    Token                                       
                                                                               85070591730234615865843651857942052864      
172.16.0.220    DC2         RAC1        Up     Normal  150.59 KB       50.00%  0                                           
172.16.0.157    DC1         RAC1        Up     Normal  155.01 KB       50.00%  85070591730234615865843651857942052864
&lt;/pre&gt;
4.建立新的keyspace。配合PropertyFileSnitch，有其對應的NetworkTopologyStrategy語法。範列中{DC1:1,DC2:1}指的是&lt;span style="color: #274e13;"&gt;{datacenter_name:number_of_replicas}&lt;/span&gt;。本範例中有多個dc，所以設定值之間必需用「,」隔開。&lt;br /&gt;
&lt;pre class="brush: text"&gt;create keyspace testks
    with strategy_options=[{DC1:1,DC2:1}]
    and placement_strategy = 'org.apache.cassandra.locator.NetworkTopologyStrategy';
&lt;/pre&gt;
===========================================================================&lt;br /&gt;
&lt;br /&gt;
把這些範例看完後，想必對Snitch與Replication Strategy比較有感覺了。簡單來說，cassandra ring裡有多個node，但是多個node到底是分布在哪個dc、哪個rank，這部份在cassandra裡有可能無法自動判定(e.g. 不同網段的node可能會分布在多個dc、多個rank，也可能這些不同網段的node其實是在同個dc、同個rank)，所以才衍生了必需設定Snitch的議題。又因為你設定了Snitch等於是你自行幫這堆node進行了分群的動作，所以必需在keyspace建立時，自行指定資料之後要存到哪個dc、那個rank裡。而Replication Strategy就是在做這件事。&lt;br /&gt;
&lt;br /&gt;
在了解這個前因後果後，再回到最前面把名詞解釋的部份再看一次，如此一來就會真的了解這二個名詞是在講啥東東，為何二者之間的關聯會這麼的密切。&lt;br /&gt;
&lt;br /&gt;
補充說明：Snitch的設定，除了文中實作的SimpleSnitch、 RackInferringSnitch、PropertyFileSnitch這三個最常見的設定外；如果是把cassandra放在Amazon的EC2上，則是需要設成EC2Snitch或EC2MultiRegionSnitch，這部份如果有實際需求的話，可以參考半官方的&lt;a href="http://www.datastax.com/docs/1.0/cluster_architecture/replication#ec2snitch" target="_blank"&gt;文件&lt;/a&gt;，了解如何設定。&lt;br /&gt;
&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9735843-1932904176193668864?l=cloudtu.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/pvDgV/~4/GNvagBHO2L8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://cloudtu.blogspot.com/feeds/1932904176193668864/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=9735843&amp;postID=1932904176193668864" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/1932904176193668864?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/1932904176193668864?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/pvDgV/~3/GNvagBHO2L8/cassandrasnitchreplicationstrategy.html" title="Cassandra的Snitch、ReplicationStrategy功能與關聯" /><author><name>Cloud Tu</name><uri>https://profiles.google.com/103480569436521613170</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-d8rzsEF047s/AAAAAAAAAAI/AAAAAAAAAbA/AXih8jz304M/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://cloudtu.blogspot.com/2012/01/cassandrasnitchreplicationstrategy.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkANQnc7fyp7ImA9WhRWFEQ.&quot;"><id>tag:blogger.com,1999:blog-9735843.post-713846761878028494</id><published>2012-01-02T17:45:00.001+08:00</published><updated>2012-01-02T18:06:33.907+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-02T18:06:33.907+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="Cassandra" /><title>快速重新初始化Cassandra節點的方法</title><content type="html">如果遇到Cassandra 1.0.6版的節點整個爛掉，想要把它恢復成一開始的初始狀況(指什麼資料都沒有，而且system keyspace裡從未放過任何資料)，可以用下面這招偷吃步(要照下面的順序一步步來)。&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;查看cassandra.yaml裡"data_file_directories"、"commitlog_directory"、"saved_caches_directory"三個參數設定的目錄分別是指到哪，把這三個目錄砍掉。&lt;/li&gt;
&lt;li&gt;查看log4j-server.properties裡"log4j.appender.R.File"參數指到的檔案在哪，把該檔案刪除。&lt;/li&gt;
&lt;li&gt;至此，整個重置完成。如果想要重新啟動前改一些設定(e.g. initial_token...etc)，此時先進行設定。&lt;/li&gt;
&lt;li&gt;上面步驟完成後，啟動Cassandra，整個系統就完成了初始化的動作。當然...這時會缺一堆之前存放的舊資料，如果有必要的話可以用nodetool指令來進行相關修復動作。&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9735843-713846761878028494?l=cloudtu.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/pvDgV/~4/yBVmR3LoexM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://cloudtu.blogspot.com/feeds/713846761878028494/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=9735843&amp;postID=713846761878028494" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/713846761878028494?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/713846761878028494?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/pvDgV/~3/yBVmR3LoexM/cassandra.html" title="快速重新初始化Cassandra節點的方法" /><author><name>Cloud Tu</name><uri>https://profiles.google.com/103480569436521613170</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-d8rzsEF047s/AAAAAAAAAAI/AAAAAAAAAbA/AXih8jz304M/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://cloudtu.blogspot.com/2012/01/cassandra.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUEFSH8zeSp7ImA9WhRWFEQ.&quot;"><id>tag:blogger.com,1999:blog-9735843.post-6647220887344275804</id><published>2012-01-02T16:40:00.001+08:00</published><updated>2012-01-02T16:40:19.181+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-02T16:40:19.181+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="Cassandra" /><title>多個Cassandra節點跨firewall所需開啟的port</title><content type="html">如果你多個Cassandra節點都是躲在各自的firewall後面執行，要讓這些節點能正常運作，下面這些port必需開啟(這是指Cassandra 1.0.6版，其它早期版本的port不見得會相同)，不然Cassandra的ring會串不起來，相互間無法溝通。&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt; 7000：這是node間傳輸資料的TCP port。cassandra.yam裡的&lt;span style="color: #274e13;"&gt;storage_port: 7000&lt;/span&gt;就是這個設定。&lt;/li&gt;
&lt;li&gt;7001：這是node間利用SSL傳輸資料的port。cassandra.yam裡的&lt;span style="color: #274e13;"&gt;ssl_storage_port: 7001&lt;/span&gt;就是這個設定。如果沒用到SSL加密傳輸，這個port可以不開。&lt;/li&gt;
&lt;li&gt;9160：這是Client端Thrift API用到的port。cassandra.yam裡的&lt;span style="color: #274e13;"&gt;rpc_port: 9160&lt;/span&gt;就是這個設定。Cassandra-CLI、Hector API...etc這些client端查詢資料的工具都靠這個port連上Cassandra。&lt;/li&gt;
&lt;li&gt;7199：這是JMX用到的port。如果Cassandra建在Linux下，cassandra-env.sh裡的&lt;span style="color: #274e13;"&gt;JMX_PORT="7199"&lt;/span&gt;就是這個設定。如果你要讓nodetool這個admin工具可以remote admin cassandra，要開這個port。不過我是不建議開這個port，真的要管理還是連到server上操作會比較好，系統也比較安全。此外，就算是7199 port開了，遠端其實還是連不上Cassandra，這是因為JMX服務啟動時，除了7199之外，系統會動態隨機產生另一個需要用到的port，如果firewall沒把這個port也打開，是無法讓nodetool工具remote連上系統的。當然...這是有解的，解法在硬大&lt;strike&gt;濕&lt;/strike&gt;師的&lt;a href="http://www.javaworld.com.tw/roller/ingramchen/entry/2006_12_3_JconsoleRemoteManagement" target="_blank"&gt;這篇文章&lt;/a&gt;中，有興趣的可以去看看。&lt;/li&gt;
&lt;/ol&gt;
簡單來說，7000、9160一定要開，不然cassandra ring會串不起來，client端會無法存取server。7001、7199要不要開，就看個人需求來考量了...:)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9735843-6647220887344275804?l=cloudtu.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/pvDgV/~4/qK4YTt8X3hA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://cloudtu.blogspot.com/feeds/6647220887344275804/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=9735843&amp;postID=6647220887344275804" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/6647220887344275804?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/6647220887344275804?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/pvDgV/~3/qK4YTt8X3hA/cassandrafirewallport.html" title="多個Cassandra節點跨firewall所需開啟的port" /><author><name>Cloud Tu</name><uri>https://profiles.google.com/103480569436521613170</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-d8rzsEF047s/AAAAAAAAAAI/AAAAAAAAAbA/AXih8jz304M/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://cloudtu.blogspot.com/2012/01/cassandrafirewallport.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkAHRHgzcSp7ImA9WhRXFk4.&quot;"><id>tag:blogger.com,1999:blog-9735843.post-8957685767625577003</id><published>2011-12-23T16:30:00.000+08:00</published><updated>2011-12-23T16:58:55.689+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-23T16:58:55.689+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="程式語言" /><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><title>Android的Task、Activity Stack 心得筆記</title><content type="html">Task指一連串Activity記錄歷程(e.g. A activity -&amp;gt; B activity -&amp;gt; C activity -&amp;gt; A activity)。Task可以跨Application，也就是說不同Application的Activiy可能會在同個Task中(e.g. App1's A activity -&amp;gt; App1's B activity -&amp;gt; App2's X activity -&amp;gt; App1's B activity)。&lt;br /&gt;
&lt;br /&gt;
由Task的既念，衍生出Activity記錄歷程相關的議題。Activity記錄歷程存放在Activity Stack之中，又因為是Stack的結構，所以它的資料是LIFO(後進先出)。&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;Activity Stack中，每個Activity的存放順序與邏輯是由AndroidManifest.xml裡，Activity tag的"android:launchMode"屬性來設定。然後..."android:launchMode"屬性裡的設定值表示的意義很&lt;strike&gt;&lt;span style="font-size: large;"&gt;它媽的&lt;/span&gt;&lt;/strike&gt;難懂，官方原文的說明在&lt;a href="http://developer.android.com/guide/topics/manifest/activity-element.html#lmode" target="_blank"&gt;這裡&lt;/a&gt;，基本上看完你就知道怎麼回事，那真的是神人一個。&lt;br /&gt;
&lt;br /&gt;
直到我很好運的找到下面這超簡單清楚的佛心文之後，我終於真正了解"android:launchMode"屬性是怎麼一回事了(以前搞不太清楚前，只敢用standard跟singleTop，免的app出包)。&lt;br /&gt;
&lt;a href="http://slashgill.blogspot.com/2010/09/activity-androidlaunchmode1-standard.html" target="_blank"&gt;activity - android:launchMode(1) - standard介紹&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://slashgill.blogspot.com/2010/09/activity-androidlaunchmode2-singletop.html" target="_blank"&gt;activity - android:launchMode(2) - singleTop介紹&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://slashgill.blogspot.com/2010/09/activity-androidlaunchmode3-singletask.html" target="_blank"&gt;activity - android:launchMode(3) - singleTask介紹&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://slashgill.blogspot.com/2010/09/activity-androidlaunchmode4.html" target="_blank"&gt;activity - android:launchMode(4) - singleInstance介紹&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://slashgill.blogspot.com/2010/09/activity-androidlaunchmode5-onnewintent.html" target="_blank"&gt;activity - android:launchMode(5) - onNewIntent()目的&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Activity的"android:launchMode"屬性的四種設定值說明摘要如下&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;standard(預設值)：在每次被叫用時都產生新的instance。&lt;/li&gt;
&lt;li&gt;singleTop：如果是在Activity Stack的最頂層，被叫用時不產生新的instance，其它狀況下則會產生新的instance。&lt;/li&gt;
&lt;li&gt; singleTask：在目前這個Application所屬的Task中，只會存在一個instance。在這個instance未被清出Activity Stack前，若遇到重覆叫用，會一直reuse現有的instance。此外，從其它Activity跳轉到這個instance時，在Activity Stack這個instance之上的所有Activity都會被清掉(e.g. 執行"A(standard) -&amp;gt; B(standard) -&amp;gt; C(singleTask) -&amp;gt; D(standard) -&amp;gt; E(standard) -&amp;gt; C(singleTask)"的動作，執行後整個Activity Stack裡的資料從底端到頂端依序是"A、B、C"，"D、E"會被自動清掉)&lt;/li&gt;
&lt;li&gt;singleInstance：第一次被叫用時，產生新的instance，並把它放到新的Task，但是該Task只會存放這一個instance。在這個instance未被清出Activity Stack前，若遇到重覆叫用，會一直reuse現有的instance。&lt;/li&gt;
&lt;/ol&gt;
在某些狀況下，將Application的首頁Activity屬性設成singleTop、singleTask會非常實用。比較吃系統資源又需要一直reuse的Activity則是可以考慮設成singleInstance。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9735843-8957685767625577003?l=cloudtu.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/pvDgV/~4/upIptyjSBs0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://cloudtu.blogspot.com/feeds/8957685767625577003/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=9735843&amp;postID=8957685767625577003" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/8957685767625577003?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/8957685767625577003?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/pvDgV/~3/upIptyjSBs0/androidtaskactivity-stack.html" title="Android的Task、Activity Stack 心得筆記" /><author><name>Cloud Tu</name><uri>https://profiles.google.com/103480569436521613170</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-d8rzsEF047s/AAAAAAAAAAI/AAAAAAAAAbA/AXih8jz304M/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://cloudtu.blogspot.com/2011/12/androidtaskactivity-stack.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkEBRXg6cCp7ImA9WhRXFUs.&quot;"><id>tag:blogger.com,1999:blog-9735843.post-8874343319097604846</id><published>2011-12-22T15:50:00.001+08:00</published><updated>2011-12-22T21:30:54.618+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-22T21:30:54.618+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="程式語言" /><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><title>Android App的保護與破解攻防戰</title><content type="html">GTUG針對Android App上的保護與破解基本概念講的蠻清楚的，有興趣的可以參考下面這二個GTUG場子裡的影片。&lt;br /&gt;
&lt;br /&gt;
&lt;iframe allowfullscreen="" frameborder="0" height="315" src="http://www.youtube.com/embed/6CkrPy3tOG0" width="560"&gt;&lt;/iframe&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;iframe allowfullscreen="" frameborder="0" height="315" src="http://www.youtube.com/embed/vAlxp1H1IxA" width="560"&gt;&lt;/iframe&gt;&lt;br /&gt;
&lt;br /&gt;
在攻擊(破解)方面的流程大致是下面這樣&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt; 先想辦法root你的anroid手機，接著用adb(下面這行指令)把apk從手機裡給挖出來。&lt;br /&gt;&lt;code style="color: #274e13;"&gt;adb pull /data/app "your destination directory"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;利用apktool、dex2jar、jd-gui將程式反組譯(可參考&lt;a href="http://www.maxhis.info/androiding/android-apk-decompile/" target="_blank"&gt;這篇&lt;/a&gt;文章)&lt;/code&gt;，相關操作指令如下。&lt;br /&gt;&lt;span style="color: #274e13;"&gt;apktool d z:/yourapp.apk z:/yourapp&lt;/span&gt;&lt;br style="color: #274e13;" /&gt;&lt;span style="color: #274e13;"&gt;dex2jar classes.dex&lt;/span&gt;&lt;br style="color: #274e13;" /&gt;&lt;span style="color: #274e13;"&gt;jd-gui classes_dex2jar.jar&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
在防守(保護) 方面大致上有下列儿招&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;利用SDK裡的Progaurd來保護你的程式碼(可參考&lt;a href="http://www.maxhis.info/androiding/protect-apk-from-decompile/" target="_blank"&gt;這篇&lt;/a&gt;文章)。要讓Progaurd生效，記的要在eclipse裡的android project的project.properties最後一行加上下面這行設定檔。&lt;br /&gt;&lt;span style="color: #274e13;"&gt;&lt;br /&gt;proguard.config=proguard.cfg&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;註：我目前用SDK R16的版本，發現裡面附的Progaurd會出現異常，有不少人也跑到官方站台提到&lt;a href="http://code.google.com/p/android/issues/detail?id=18359" target="_blank"&gt;相同問題&lt;/a&gt;，我後來把Progaurd換成4.7版，並參考該issue討論串裡comment34的做法解決此項怪問題。&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #274e13;"&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;把核心程式碼用C/C++實作，讓人很難反組譯，然後java層利用&lt;a href="http://java.sun.com/docs/books/jni/html/jniTOC.html" target="_blank"&gt;jni&lt;/a&gt;跟這些so檔進行溝通。&lt;/li&gt;
&lt;li&gt;如果你的程式是client / server架構，把重要的核心資料放到server上，這樣就算client端的程式不幸被破解了也沒用，因為你可以在server端動手腳擋掉這些人。&lt;/li&gt;
&lt;li&gt;程式中要放好儿個保護點。&lt;/li&gt;
&lt;li&gt; 程式碼在設計時，不要一判斷到有人非法使用就強制退出程式，而是要讓程式還能跑，但是出現一些怪問題(e.g. delay 10 secs，跳到不相關的視窗...etc)，每個保護點出現的怪問題不要一樣，增加破解要浪費的時間。&lt;/li&gt;
&lt;/ol&gt;
最後...攻防很有趣，但是讓開發人員賺不到錢就不有趣了。所以...自己若是破解了什麼東西，請自high就好，就別亂丟到網路上了，這可是很沒品的事呀~~~&lt;br /&gt;
&lt;ol&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9735843-8874343319097604846?l=cloudtu.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/pvDgV/~4/RDmzew_-Zh4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://cloudtu.blogspot.com/feeds/8874343319097604846/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=9735843&amp;postID=8874343319097604846" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/8874343319097604846?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/8874343319097604846?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/pvDgV/~3/RDmzew_-Zh4/android-app.html" title="Android App的保護與破解攻防戰" /><author><name>Cloud Tu</name><uri>https://profiles.google.com/103480569436521613170</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-d8rzsEF047s/AAAAAAAAAAI/AAAAAAAAAbA/AXih8jz304M/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://img.youtube.com/vi/6CkrPy3tOG0/default.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://cloudtu.blogspot.com/2011/12/android-app.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEcMQH85fCp7ImA9WhRWFUs.&quot;"><id>tag:blogger.com,1999:blog-9735843.post-1121135621056196405</id><published>2011-12-12T16:58:00.000+08:00</published><updated>2012-01-03T11:41:21.124+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-03T11:41:21.124+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="程式語言" /><category scheme="http://www.blogger.com/atom/ns#" term="Cassandra" /><title>Cassandra心得筆記</title><content type="html">這儿個月斷斷續續的在摸Cassandra，目前有一些小心得，先記錄下來免的忘掉。不過...不確定這些Memo有沒有錯，如果有錯以後再來改吧...:)&lt;br /&gt;
&lt;br /&gt;
註：下列的Memo以1.x版為主，舊的0.8.x版資料多數已被我移除。部份內容來自於TWJUG裡，某大濕的經驗談&lt;strike&gt;(血淚控訴)&lt;/strike&gt;。&lt;br /&gt;
&lt;br /&gt;
======================================================================&lt;br /&gt;
無法分類項目&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;NoSQL = Not Only SQL&lt;/li&gt;
&lt;li&gt;Cassandra的資料操作與管理比GAE上的Datastore辛苦很多&lt;/li&gt;
&lt;li&gt;官方目前在開發&lt;a href="http://code.google.com/a/apache-extras.org/p/cassandra-jdbc/" target="_blank"&gt;JDBC driver for CQL&lt;/a&gt;。如果這東東成熟的話，我覺的會比Hector API還好用。不過Hector API也會持續的把CQL功能給整合進來。 &lt;/li&gt;
&lt;/ol&gt;
====================================================================== &lt;br /&gt;
資料結構項目&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;我覺的最重要的儿個keyworld如下&lt;br /&gt;Row key = Key = K&lt;br /&gt;Column name = Name = N&lt;br /&gt;Column value = Value = V&lt;/li&gt;
&lt;li&gt;儲存的資料中，除了Row key會自動建Index之外，Column value不自動建立Index；但是可以利用Secondary Index機制自行建立Column value的index。&lt;/li&gt;
&lt;li&gt;在Column Family建立時，由裡面的comparator參數值決定了Column name的資料型別；由裡面的validation_class參數值決定了Row key、Column value的資料型別。&lt;/li&gt;
&lt;li&gt;儲存資料的排序是依Row key、Column name自動排序，排序的規則跟Column family建立時設定的comparator有關聯，不是依Column value自動排序!!! &lt;/li&gt;
&lt;/ol&gt;
====================================================================== &lt;br /&gt;
資料建置與維護&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;一個Cassandra系統一般會設置多個Node，每個Node會各有一個識別用的UUID來識別彼此，此UUID在Cassandra中被稱
為Token。多個Token(或說多個Node)的排列方式在邏輯上是一個環狀的結構被稱為Token 
ring。每個Token有各自的勢力範圍(e.g. 
row1~3可存放在token1，row4~6可存放在token2)，這個範圍被稱為Partition。勢力範圍的判斷邏輯由
Partitioner來決定(在cassandra.yaml裡設定)，常用的有RandomPartitioner、
ByteOrderedPartitioner二種；如果希望Row 
key要依序排序，要設成ByteOrderedPartitioner。這個條列項目的明細說明可參考&lt;a href="http://www.datastax.com/docs/1.0/cluster_architecture/partitioning" target="_blank"&gt;這份文件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;在Keyspace建立時，除了指定RF(ReplicationFactor：每筆資料要存放到儿個節點)之外，必需指定存放資料節點的選擇策略。一般常用策略有SimpleStrategy、NetworkTopologyStrategy，不同策略會導致資料分布方式有所不同，詳細說明可參
考&lt;a href="http://www.datastax.com/docs/1.0/cluster_architecture/replication" target="_blank"&gt;這份文件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;當系統有多個節點時，記的要遵守下面這規則，確保存放資料的一致性&lt;br /&gt;W(每次成功寫入資料存放節點的次數) + R(每次成功讀取資料存方節點的次數) &amp;gt; RF(ReplicationFactor：每筆資料要存放到儿個節點)&lt;/li&gt;
&lt;li&gt;當系統有多個節點時，較佳的資料存取策略有下述三種&lt;ul&gt;
&lt;li&gt;write all and read one&lt;/li&gt;
&lt;li&gt;write one and read all&lt;/li&gt;
&lt;li&gt;write quorum and read quorum&lt;br /&gt;(quorum公式 = RF/2 + 1)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;系統節點數不同，用的資料存取策略不同，我自己會用的方式如下&lt;ul&gt;
&lt;li&gt;一個節點：用什麼策略的效果都一樣。&lt;br /&gt;(只一個節點的話，還會想用Cassnadra嗎...=_=?)&lt;/li&gt;
&lt;li&gt;二個節點：RF設成2，資料存取策略用「write all and read one」。這樣設的好處是資料讀取較快，有一個節點掛了時，Cassandra還是可被讀取；缺點是只要一個節點掛了，資料就無法寫入了。&lt;/li&gt;
&lt;li&gt;三個節點(含以上)： RF設成3(或3以上)，資料存取策略可用「write all and read one」或是「write 
quorum and read quorum」。「write all and read 
one」的優缺在二個節點裡有提及，不在多述。使用「write quorum and read 
quorum」的好處是在少量節點掛掉時，系統還是可以正常的被讀寫。等到掛掉的節點恢復後，系統提供的「hinted 
handoff」機制會把資料回寫到掛掉的節點。&amp;nbsp;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Cassandra在執行寫入會比讀取來的快，寫入時會先直接寫到RAM裡面，然後再backend的把資料flush至硬碟。讀取時則是先到RAM裡存放的索引資料裡找出索引，再依找到的索引到硬碟裡把相關資料取出來。&lt;br /&gt;&lt;br /&gt;因為這特性，所以「write all and read one」存取策略對於少量寫入但是海量讀取的Application，有很大的優勢。 &lt;/li&gt;
&lt;li&gt;系統中最少要設定一個node為seed node。seed node有整個token 
ring的相關資訊，該node在啟動時不會去找整個token ring的資訊。反之，非 seed node則是啟動時會去跟seed 
node查詢整個token ring的資料。&lt;/li&gt;
&lt;li&gt;當有新的node要加入現行的系統中時，必需修改cassandra.yaml。&lt;strike&gt;將auto_bootstrap設成true(1.0版跟之後的版本已經將auto_bootstrap參數移除，這參數變成系統內部參數，在啟動時由系統自動判斷是否要啟用此功能)，&lt;/strike&gt;seeds參數裡需設定目前所有seed node的IP值。&lt;br /&gt;&lt;strike&gt;&lt;br /&gt;auto_bootstrap
設成true時，該node在第一次被啟動時會從seed node抓取整個token 
ring的設定，並把屬於自己partition的資料從其它node裡轉入。這個設定只在第一次啟動時生效，之後再次啟動時就不再做
auto_bootstrap動作。當auto_bootstrap設成true，而該node自身又扮演seed 
node角色時，auto_bootstrap設定會失效。&lt;/strike&gt;&lt;/li&gt;
&lt;li&gt;系統的每個node在第一次啟動時，如果不在cassandra.yaml裡的initial_token參數設定token值，系統會自動指派該值。但
是對於一開始就建置多個node的系統而言，自動指派的值不見的合適，可能會造成token 
ring裡，各自負責的partition大小差異很大(e.g. 建置4個node，但各自佔有整個token 
ring的partition卻是50%,25%,13%,12%)。要算出合適的token值可參考&lt;a href="http://blog.milford.io/2011/05/in-which-i-discourse-on-java-bloat-and-cassandra-node-balancing/" target="_blank"&gt;這篇&lt;/a&gt;文章。&lt;/li&gt;
&lt;li&gt;系統的token值一旦第一次啟動後就無法在cassandra.yaml中再次修改，因為相關資料已經進了system keyspace的LocationInfo column family，這時如果要改只能用nodetool下指令的方式來改。 &lt;/li&gt;
&lt;li&gt;系統中每個node所佔的partition大小差異很大時，可利用"nodetool...move...&lt;new token=""&gt;"指令來移動token，進而解決partition差異過大的問題。&lt;br /&gt;&lt;br /&gt;"nodetool...move...&lt;new token=""&gt;"指令的動作原理是「先把該node退出token ring，並把該node的資料分到其它node裡面」，接著「再將該node裡舊token值換成新的token值，並重新加入token ring」，在完成後「再到其它node把屬於新token該擁有的資料取回」。整個過程對效能有很大影響，在執行時要考量執行時機。&lt;/new&gt;&lt;/new&gt;&lt;/li&gt;
&lt;li&gt;在整個系統架構中，資料寫入的流程是"寫到Commitlog --&amp;gt; 寫到Memtable --&amp;gt; 
寫到SSTable"；資料讀出流程是"先讀RowCache--&amp;gt;再讀Memtable--&amp;gt;最後讀SSTable"。
(from TWJUG)&lt;/li&gt;
&lt;li&gt;每個Node的Partitioner設定，建議設成RandomPartitioner，這樣資料分佈在整個Ring裡會比較平均，不會特別集中在特定儿個Node。(from TWJUG)&lt;/li&gt;
&lt;li&gt;Replication 
Strategy在cassandra.yaml裡的endpoint_snitch參數中設定，一般用預設的SimpleSnitch。如果有多個
DataCenter時，有其它對應的參數值可供設置。(from TWJUG)&lt;/li&gt;
&lt;li&gt;整個Ring裡各Node的資料要維持一致性，分成寫與讀的二方可面的策略。實務建議是write quorum and read 
quorum，不建議write all and read one的原因是只要有一個Node掛掉這時就只剩下read功能正常而已。(from TWJUG)&lt;/li&gt;
&lt;li&gt;Consistency Repair功能中，分成寫與讀二方面的機制。&lt;br /&gt;&lt;br /&gt;寫入方面是靠Hinted 
Handoff來保証資料一定成功寫到所屬各個Node。實務上，Hinted 
Handoff可能會出包(1.0以前的版本會出包，官方聲稱這問題在1.0後已修正)，因為Hinted 
Handoff在某些機會下，有可能會寫入"它認為沒掛掉但事實上已掛掉的Node"，造成資料流失。&lt;br /&gt;&lt;br /&gt;讀取方面是靠Read 
Repair機制來確保所屬各個Node的資料正確無誤。在某些狀況下，Read的動作會導致先Write再Read的情況(e.g. 要從Node 
A,B,C取回同一份資料，執行時發現B的資料異常取不回來，這時Read 
Repair發生作用，把A或C取得的資料寫回至B，等整個修復完成後才會把Client端要取回的資料回傳)。(from TWJUG)&lt;/li&gt;
&lt;/ol&gt;
====================================================================== &lt;br /&gt;
Client端操作&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;目前操作Cassandra最方便的方式依序是&lt;br /&gt;
&lt;br /&gt;
CQL &amp;gt; Cassandra CLI &amp;gt; Hector API &amp;gt; Thrift API&lt;br /&gt;
&lt;br /&gt;
基
本上，除了CQL看來比較像是給人用的之外，其它的都不怎麼好用。CQL目前還在快速演進中，功能不完整但可以期待。寫Java 
code來叫用cassandra的話，目前大概就只能選擇Hector 
API。如果要直接在Console下Command操作，則是選擇Cassandra CLI。&amp;nbsp;&lt;/li&gt;
&lt;li&gt;利用Secondary Index機制進行資料查詢時，記的where condition裡的column field最少要包含一個"="，否則查詢會出錯。 &lt;/li&gt;
&lt;/ol&gt;
======================================================================&lt;br /&gt;
前人血淚控訴留下的相關經驗(這一段超重要)&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;不要在非官方(Oracle) JVM上建置Cassnadra系統。(from TWJUG)&lt;/li&gt;
&lt;li&gt;每個Node裡的CommitLog跟SSTable最好放在不同的Disk裡面。 (from TWJUG)&lt;/li&gt;
&lt;li&gt;JVM裡的heap size最好別超過16GB，不然可能會發生悲劇，系統在進行某些忙錄的運作時，可能整個當在那邊。(from TWJUG)&lt;/li&gt;
&lt;li&gt;Client端進行批次操作時，要注意每個批量的大小，每個批量過大可能會讓Server端發生timeout的問題，導致一直進行retry的動作。(from TWJUG)&lt;/li&gt;
&lt;li&gt;cassandra.yaml的partitioner參數設定不要用ByteOrderedPartitioner、OrderPreservingPartitioner。(from TWJUG)&lt;/li&gt;
&lt;li&gt;cassandra.yaml的initial_token參數一定要設，不要讓系統自動產生。系統產生的token會讓整個Ring裡，每個Partition的大小差異很大。(from TWJUG)&lt;/li&gt;
&lt;li&gt;SuperColumn未來會被CompositeColumn取代，不要再用SuperColumn了。(from TWJUG)&lt;/li&gt;
&lt;li&gt;Client端利用程式存取資料時，程式碼裡建議先實做寫的動作再實做讀的動作，這樣可避免Client端發生讀到舊資料的問題。(from TWJUG)&lt;/li&gt;
&lt;li&gt;Cassandra雖然在1.x版後支援windows系統，但是為了自己生命安全，請不要用它，還是乖乖的架在linux上吧，免的問題一大堆。(from TWJUG)&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9735843-1121135621056196405?l=cloudtu.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/pvDgV/~4/umBKk6hh95U" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://cloudtu.blogspot.com/feeds/1121135621056196405/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=9735843&amp;postID=1121135621056196405" title="1 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/1121135621056196405?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/1121135621056196405?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/pvDgV/~3/umBKk6hh95U/cassandra.html" title="Cassandra心得筆記" /><author><name>Cloud Tu</name><uri>https://profiles.google.com/103480569436521613170</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-d8rzsEF047s/AAAAAAAAAAI/AAAAAAAAAbA/AXih8jz304M/s512-c/photo.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://cloudtu.blogspot.com/2011/10/cassandra.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0ICQHYzfyp7ImA9WhRQFk0.&quot;"><id>tag:blogger.com,1999:blog-9735843.post-6915058056655508528</id><published>2011-12-11T20:05:00.001+08:00</published><updated>2011-12-11T20:12:41.887+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-11T20:12:41.887+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="程式語言" /><category scheme="http://www.blogger.com/atom/ns#" term="Cassandra" /><title>Cassandra in TWJUG 2011-12-10</title><content type="html">以下是 2011-12-10在TWJUG場子裡的Cassandra講題，當天講師提出不少自己實務上的經驗，有興趣的人可以參考看看。&lt;br /&gt;
&lt;br /&gt;
&lt;div id="__ss_10546548" style="width: 425px;"&gt;
&lt;b style="display: block; margin: 12px 0 4px;"&gt;&lt;a href="http://www.slideshare.net/jackychu/cassandra-10546548" target="_blank" title="Talk About Apache Cassandra"&gt;Talk About Apache Cassandra&lt;/a&gt;&lt;/b&gt; &lt;iframe frameborder="0" height="355" marginheight="0" marginwidth="0" scrolling="no" src="http://www.slideshare.net/slideshow/embed_code/10546548" width="425"&gt;&lt;/iframe&gt; &lt;br /&gt;
&lt;div style="padding: 5px 0 12px;"&gt;
View more &lt;a href="http://www.slideshare.net/" target="_blank"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/jackychu" target="_blank"&gt;Jacky Chu&lt;/a&gt; &lt;/div&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;iframe allowfullscreen="" frameborder="0" height="360" src="http://www.youtube.com/embed/MJWcKlZ8JWI" width="480"&gt;&lt;/iframe&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;iframe allowfullscreen="" frameborder="0" height="360" src="http://www.youtube.com/embed/en_kCwrHGhw" width="480"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9735843-6915058056655508528?l=cloudtu.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/pvDgV/~4/uq_zUgTU_i8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://cloudtu.blogspot.com/feeds/6915058056655508528/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=9735843&amp;postID=6915058056655508528" title="1 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/6915058056655508528?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/6915058056655508528?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/pvDgV/~3/uq_zUgTU_i8/cassandra-in-twjug-2011-12-10.html" title="Cassandra in TWJUG 2011-12-10" /><author><name>Cloud Tu</name><uri>https://profiles.google.com/103480569436521613170</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-d8rzsEF047s/AAAAAAAAAAI/AAAAAAAAAbA/AXih8jz304M/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://img.youtube.com/vi/MJWcKlZ8JWI/default.jpg" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://cloudtu.blogspot.com/2011/12/cassandra-in-twjug-2011-12-10.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEYCRnc4cCp7ImA9WhRQE04.&quot;"><id>tag:blogger.com,1999:blog-9735843.post-7959887417256112774</id><published>2011-12-08T15:40:00.001+08:00</published><updated>2011-12-08T16:16:07.938+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-08T16:16:07.938+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="程式語言" /><title>Java memory leak 簡略心得筆記</title><content type="html">有一定程度的java programmer應該都知道，雖然java沒有C的pointer，但是程式沒寫好還是會導致memory leak。跟C的memory leak不同之處在於，C是沒把locate的memory還給OS，java的memory leak則是無用的變數(或是該被GC的變數沒被GC)一直佔用memory，直到jvm消滅時才一口氣把memory還給OS。&lt;br /&gt;
&lt;br /&gt;
java memory leak的一整個前因後果可參照下面這篇文章&lt;br /&gt;
&lt;a href="http://olex.openlogic.com/wazi/2009/how-to-fix-memory-leaks-in-java/" target="_blank"&gt;How to Fix Memory Leaks in Java&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
要去追查java memory leak的方法有很多，stackoverflow&lt;a href="http://stackoverflow.com/questions/1638011/java-memory-leak" target="_blank"&gt;有篇文章&lt;/a&gt;蠻完整的，可供參考。簡單來說，追的流程如下&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt; 程式啟動時加入下面這類的參數，讓它在jvm炸掉時自動dump heap&lt;br /&gt;&lt;span style="color: #274e13;"&gt;-Xmx64m -XX:+HeapDumpOnOutOfMemoryError&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;如果是想在程式執行時手動dump heap則是經由jmap指令、jconsole工具、或是&lt;a href="http://www.eclipse.org/mat/" target="_blank"&gt;Eclipse Memory Analyzer&lt;/a&gt;這個plugin&lt;/li&gt;
&lt;li&gt;有了倒出來的heap後，就可以用jhat指令或是Eclipse Memory Analyzer來分析到底程式是哪裡出包，導致leak產生。&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
操作Eclipse Memory Analyzer來追leak，可以參考下面儿篇文章。&lt;br /&gt;
&lt;a href="http://blog.csdn.net/moneyice/article/details/2644503" target="_blank"&gt;使用 Eclipse Memory Analyzer 檢測內存洩漏問題&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://www.blogjava.net/rosen/archive/2010/05/21/321575.html" id="viewpost1_TitleUrl" target="_blank"&gt;使用Memory Analyzer tool(MAT)分析內存洩漏（一）&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://www.blogjava.net/rosen/archive/2010/06/13/323522.html" id="viewpost1_TitleUrl" target="_blank"&gt;使用Memory Analyzer tool(MAT)分析內存洩漏（二）&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
我自己通常是在Leak Hunter報表產生後，就依其內容去追leak原因。通常這樣就抓的到哪裡用了最多的memory，找到兇手。不過...有時會發現...其實你的程式就是要吃這麼多memory，你的List或Map object裡就是要放巨量的資料，根本不是啥memory leak。這時就只好放大jvm的max heap size，不然就是硬體加RAM才能解了(內心OS：這就是人蔘呀~~)。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9735843-7959887417256112774?l=cloudtu.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/pvDgV/~4/p_s9lTSs5h4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://cloudtu.blogspot.com/feeds/7959887417256112774/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=9735843&amp;postID=7959887417256112774" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/7959887417256112774?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/7959887417256112774?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/pvDgV/~3/p_s9lTSs5h4/java-memory-leak.html" title="Java memory leak 簡略心得筆記" /><author><name>Cloud Tu</name><uri>https://profiles.google.com/103480569436521613170</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-d8rzsEF047s/AAAAAAAAAAI/AAAAAAAAAbA/AXih8jz304M/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://cloudtu.blogspot.com/2011/12/java-memory-leak.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0cNRH05fCp7ImA9WhRQE08.&quot;"><id>tag:blogger.com,1999:blog-9735843.post-6774154411802494143</id><published>2011-12-08T14:34:00.001+08:00</published><updated>2011-12-08T15:24:55.324+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-08T15:24:55.324+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="程式語言" /><title>jps：Java Virtual Machine Process Status Tool</title><content type="html">在作業系統中查出目前正在執行的java process到底是哪個Main class啟動，其實有點麻煩。如果在linux裡用ps指令去查，只會看到命名為java的process跟其對應的PID，如果是在windows裡，把工作管理員叫出來看，也是只能看到命名為java的process跟其對應的PID。如果你的作業系統同時跑了好儿支獨立的java程式，這時麻煩就來了，你只會看到一堆java process，搞不清對應的程式到底是誰...Orz。&lt;br /&gt;
&lt;br /&gt;
解法當然是有，最簡單的方式就是用jconsole去查，它會秀出所有local端的java process、對應的PID、還有啟動它的Main class。執行時的畫面如下所示。&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-LrshhhHSpaU/TuBdM2JSE2I/AAAAAAAABR8/-ah1gnBYjH0/s1600/1.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="252" src="http://3.bp.blogspot.com/-LrshhhHSpaU/TuBdM2JSE2I/AAAAAAAABR8/-ah1gnBYjH0/s400/1.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div style="clear: both; text-align: left;"&gt;
&lt;/div&gt;
不過...在沒有裝x-window的linux上，這招就沒用啦。所以最省資源且最方便的方式應該是要用jdk內附的jps指令來查。jps的完整用法可以去官網查(&lt;a href="http://docs.oracle.com/javase/1.5.0/docs/tooldocs/share/jps.html" target="_blank"&gt;按此&lt;/a&gt;)。執行時的畫面如下所示。&lt;br /&gt;
&lt;pre class="brush: text"&gt;C:\Users\cloudtu&amp;gt;jps -l
1640 sun.tools.jps.Jps
6684 sun.tools.jconsole.JConsole
1752
6664 org.eclipse.jetty.start.Main
&lt;/pre&gt;
&lt;br /&gt;
如果你的程式(同個Main class)在同一時間只許可一個java process啟動它，寫程式去呼叫外部的jps指令來幫忙做這件事，則是一個很方便的作法。可參考下列實作程式碼。&lt;br /&gt;
&lt;pre class="brush: java"&gt;
public class OSUtil
{
 private static final Logger logger = Logger.getLogger(OSUtil.class); 
 
    private OSUtil()
    {        
    }
    
    /**
     * 執行作業系統中的Console command，並將執行結果轉換成字串回傳
     * 
     * @param cmdStr    Console command
     * 
     * @return 執行結果
     * 
  * @throws RuntimeException 
     */
    public static String execCmd(String cmdStr)
    {
        try
        {
            Process proc = Runtime.getRuntime().exec(cmdStr);
            InputStream is = proc.getInputStream();
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);
            String line = null;
            StringBuilder result = new StringBuilder();
            while ((line = br.readLine()) != null)
            {
                result.append(line + "\n");
            }
            br.close();
            
            return result.toString();
        }
        catch (Exception e)
        {
            throw new RuntimeException(e);
        }     
    }    
    
    /**
     * 利用JPS指令查詢特定的MainClass目前被啟動了儿個Java process
     * 
     * @param mainClass Main Class
     * 
     * @return Java process amount
     * 
     * @throws RuntimeException 
     */
    public static int queryJavaProcessAmount(Class mainClass){
     String jpsCmd = System.getProperty("java.home").replaceAll("\\\\", "/").replaceAll("jre", "") + "bin/jps -l"; //JPS指令的fully path
     logger.debug("jpsCmd : " + jpsCmd);
     
     String jpsExecuteResult = execCmd(jpsCmd);
     logger.debug("jpsExecuteResult : " + jpsExecuteResult);
     
     int javaProcessAmount = 0;
     int foundIndex = 0;
     String key = mainClass.getName();
     while(true){
      foundIndex = jpsExecuteResult.indexOf(key, foundIndex);
      if(foundIndex &gt;= 0){
       javaProcessAmount++;       
      }
      else{
       break;
      }
      
   if(foundIndex + key.length() &lt;= jpsExecuteResult.length() - 1){
    foundIndex = foundIndex + key.length();
   }
   else{
    break;
   }      
     }
     return javaProcessAmount;
    }    
}
&lt;/pre&gt;
&lt;br /&gt;
jps蠻好用的，不過有個地方要注意一下。我發現如果作業系統是windows，然後檔案格式又是早期的FAT或FAT32的話，jps指令會無法查出執行的java process所對應的PID是誰。不過...這年頭應該沒多少人把windows裝在這種格式之上了才對，所以踩到地雷的機會應該不大...:)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9735843-6774154411802494143?l=cloudtu.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/pvDgV/~4/Sd-KFGbqiSc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://cloudtu.blogspot.com/feeds/6774154411802494143/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=9735843&amp;postID=6774154411802494143" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/6774154411802494143?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/6774154411802494143?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/pvDgV/~3/Sd-KFGbqiSc/jpsjava-virtual-machine-process-status.html" title="jps：Java Virtual Machine Process Status Tool" /><author><name>Cloud Tu</name><uri>https://profiles.google.com/103480569436521613170</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-d8rzsEF047s/AAAAAAAAAAI/AAAAAAAAAbA/AXih8jz304M/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-LrshhhHSpaU/TuBdM2JSE2I/AAAAAAAABR8/-ah1gnBYjH0/s72-c/1.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://cloudtu.blogspot.com/2011/12/jpsjava-virtual-machine-process-status.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkYNSHo5eip7ImA9WhRQE08.&quot;"><id>tag:blogger.com,1999:blog-9735843.post-1803660039798515435</id><published>2011-12-08T11:38:00.001+08:00</published><updated>2011-12-08T12:56:39.422+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-08T12:56:39.422+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="程式語言" /><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><title>Eclipse plugins for Android Sources</title><content type="html">以前寫Android app，想把android.jar這個核心jar檔的source code給掛到eclipse project裡還蠻麻煩的，要自己用git去抓官方的andorid source，然後用一些有的沒的方式才可以把它掛到project裡。沒想到現在已經有這方面現成的plugin可用了，真是究干心。&lt;br /&gt;
&lt;br /&gt;
相關資訊在&lt;a href="http://code.google.com/p/adt-addons/" target="_blank"&gt;這裡&lt;/a&gt;，有需要的人可以照裡面寫的步驟去把它裝起來。其中比較重要的一些內容節錄如下。&lt;br /&gt;
&lt;br /&gt;
==================================================================  &lt;br /&gt;
Android Sources&lt;br /&gt;
&lt;br /&gt;
This plugin helps you to add source to android libraries in Eclipse.&lt;br /&gt;
&lt;br /&gt;
In ADT &amp;gt;=8.0.0 you can add Android sources to Android container for all your project with installing the Android source feature using &lt;a href="http://adt-addons.googlecode.com/svn/trunk/source/com.android.ide.eclipse.source.update/" target="_blank"&gt;http://adt-addons.googlecode.com/svn/trunk/source/com.android.ide.eclipse.source.update/&lt;/a&gt; update site After installing the Android source feature all your existing projects as well as new created projects which is targeted for Android 2.3.4, 2.3, 2.2, 2.1, 2.0.1, 1.6 and 1.5 will have attached the source jar.&lt;br /&gt;
&lt;br /&gt;
The plugin includes sources for the following API levels:&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; 10 - Android 2.3.4&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; 9 - Android 2.3&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; 8 - Android 2.2&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; 7 - Android 2.1&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; 6 - Android 2.0.1&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; 4 - Android 1.6&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; 3 - Android 1.5 &lt;br /&gt;
&lt;br /&gt;
The plugin is about 170 MB size.&lt;br /&gt;
==================================================================&lt;br /&gt;
&lt;br /&gt;
裝完後執行起來的screenshot像下面這樣。這真是個實用的好東東...:)&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-bkmmkSD7Nko/TuA3R4_0uRI/AAAAAAAABRk/bcxMU9Bitgw/s1600/1.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="153" src="http://3.bp.blogspot.com/-bkmmkSD7Nko/TuA3R4_0uRI/AAAAAAAABRk/bcxMU9Bitgw/s400/1.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-KXHUjEuFiq4/TuA3SQGnpXI/AAAAAAAABRs/cQwzGxwqkAo/s1600/2.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="102" src="http://4.bp.blogspot.com/-KXHUjEuFiq4/TuA3SQGnpXI/AAAAAAAABRs/cQwzGxwqkAo/s400/2.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-U0vzH5w1huM/TuA3T7Y9hEI/AAAAAAAABRw/L09S8ZbInpo/s1600/3.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="136" src="http://3.bp.blogspot.com/-U0vzH5w1huM/TuA3T7Y9hEI/AAAAAAAABRw/L09S8ZbInpo/s400/3.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9735843-1803660039798515435?l=cloudtu.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/pvDgV/~4/k1bVtNYpnDc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://cloudtu.blogspot.com/feeds/1803660039798515435/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=9735843&amp;postID=1803660039798515435" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/1803660039798515435?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/1803660039798515435?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/pvDgV/~3/k1bVtNYpnDc/eclipse-plugins-for-android-sources.html" title="Eclipse plugins for Android Sources" /><author><name>Cloud Tu</name><uri>https://profiles.google.com/103480569436521613170</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-d8rzsEF047s/AAAAAAAAAAI/AAAAAAAAAbA/AXih8jz304M/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-bkmmkSD7Nko/TuA3R4_0uRI/AAAAAAAABRk/bcxMU9Bitgw/s72-c/1.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://cloudtu.blogspot.com/2011/12/eclipse-plugins-for-android-sources.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkMER3w_eCp7ImA9WhRQEUs.&quot;"><id>tag:blogger.com,1999:blog-9735843.post-8268237712244631031</id><published>2011-12-06T14:16:00.001+08:00</published><updated>2011-12-06T16:33:26.240+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-06T16:33:26.240+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="程式語言" /><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><title>ADB經由VirtualBox上的USB Port存取Android硬體</title><content type="html">如果單純寫java層的Android App，當然是什麼平台都很方便。但是如果要在android上寫JNI這類的C&amp;lt;-&amp;gt;Java inteop的程式，可就麻煩了(至少在Windows平台很麻煩)。在Windows平台上只能用Cygwin，再怎樣都比用Linux上的GCC要麻煩，而且天曉得Gygwin會不會跟你噴什麼怪怪的Error。在不影響Widnows的前題下，最省事的方式應該就是用Virtualbox建一個VM，上面裝Linux，然後在這之上去連接Android硬體。儿年前我就有這想法了，但是當時我發現在VM上用ADB經由USB Port要去連Android硬體總是連不上，只好放棄這做法，乖乖的在硬碟上裝一個Linux來用...Orz&lt;br /&gt;
&lt;br /&gt;
這儿天試了一下近期版本的Virtualbox，發現這功能居然能Work了，真讓人開心。看來我可以把NB上的Linux給砍了，直接用VM上建的Linux就好...:P&lt;br /&gt;
&lt;br /&gt;
以下是ADB經由VirtualBox上的USB Port存取Android硬體的步驟&lt;br /&gt;
&lt;br /&gt;
1.Windows上安裝Android USB Driver&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;
&lt;a href="http://3.bp.blogspot.com/-ouPzPXZDYGA/Tt24z79tE9I/AAAAAAAABRM/htF2iBwGHiU/s1600/1.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-ouPzPXZDYGA/Tt24z79tE9I/AAAAAAAABRM/htF2iBwGHiU/s1600/1.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;
2. 在Virtualbox上面把Android硬體對應的USB Port開啟&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-rFLvQbX-1Y0/Tt27YvMHK5I/AAAAAAAABRU/mUPlrO3IDzY/s1600/2.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="192" src="http://2.bp.blogspot.com/-rFLvQbX-1Y0/Tt27YvMHK5I/AAAAAAAABRU/mUPlrO3IDzY/s400/2.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;
3.在VM裡的Linux執行lsusb指令，確認抓的到Android裝置&lt;/div&gt;
&lt;pre class="brush: text"&gt;cloudtu@cloudtu-VirtualBox:~$ lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 001 Device 002: ID 0502:3202 Acer, Inc. Liquid
Bus 002 Device 002: ID 80ee:0021 VirtualBox USB Tablet
&lt;/pre&gt;
&lt;br /&gt;
4.在VM裡的Linux安裝「Android SDK Platform-tools」&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-p4XO3hboYIU/Tt292DrrlMI/AAAAAAAABRc/Arlvovhq5AA/s1600/3.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="162" src="http://2.bp.blogspot.com/-p4XO3hboYIU/Tt292DrrlMI/AAAAAAAABRc/Arlvovhq5AA/s400/3.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;
5.在VM裡的Linux執行adb指令(第一次執行這個指令時要有root的權限才可以正常執行，所以要下sudo)，確認抓的到Android裝置&lt;/div&gt;
&lt;pre class="brush: text"&gt;cloudtu@cloudtu-VirtualBox:~/android-sdk-linux/platform-tools$ sudo ./adb devices
[sudo] password for cloudtu: 
* daemon not running. starting it now on port 5037 *
* daemon started successfully *
List of devices attached 
0000947457723221 device
&lt;/pre&gt;
&lt;br /&gt;
6.在VM裡的Linux執行logcat，如果看到android硬體裡的一堆訊息，就代表成功連上裝置了。&lt;br /&gt;
&lt;pre class="brush: text"&gt;cloudtu@cloudtu-VirtualBox:~/android-sdk-linux/platform-tools$ ./adb logcat
I/BackupManagerService(  113):     + com.android.providers.settings
I/BackupManagerService(  113): Backup enabled =&amp;gt; false
I/SystemServer(  113): AppWidget Service
D/TelephonyManager(  113): listen=android.telephony.PhoneStateListener$1@2fd2a4a0 event=1073742305
I/WindowManager(  113): SAFE MODE not enabled
D/SurfaceFlinger(  113): createConnection: cid=0x1
I/ActivityManager(  113): Config changed: { scale=1.0 imsi=0/0 loc=zh_TW touch=3 keys=1/1/2 nav=1/1 orien=1 layout=34}
&lt;/pre&gt;
&lt;br /&gt;
7.Reference document&lt;br /&gt;
&lt;a href="http://forum.xda-developers.com/showthread.php?t=570452g" target="_blank"&gt;http://forum.xda-developers.com/showthread.php?t=570452g&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://www.blogjava.net/brian/articles/316019.html" target="_blank"&gt;http://www.blogjava.net/brian/articles/316019.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9735843-8268237712244631031?l=cloudtu.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/pvDgV/~4/wIGJED7wIOo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://cloudtu.blogspot.com/feeds/8268237712244631031/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=9735843&amp;postID=8268237712244631031" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/8268237712244631031?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/8268237712244631031?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/pvDgV/~3/wIGJED7wIOo/adbvirtualboxusb-portandroid.html" title="ADB經由VirtualBox上的USB Port存取Android硬體" /><author><name>Cloud Tu</name><uri>https://profiles.google.com/103480569436521613170</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-d8rzsEF047s/AAAAAAAAAAI/AAAAAAAAAbA/AXih8jz304M/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-ouPzPXZDYGA/Tt24z79tE9I/AAAAAAAABRM/htF2iBwGHiU/s72-c/1.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://cloudtu.blogspot.com/2011/12/adbvirtualboxusb-portandroid.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkEGQ3s8fCp7ImA9WhRSGEs.&quot;"><id>tag:blogger.com,1999:blog-9735843.post-7510473699618206123</id><published>2011-11-21T17:19:00.000+08:00</published><updated>2011-11-21T17:43:42.574+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-21T17:43:42.574+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="程式語言" /><category scheme="http://www.blogger.com/atom/ns#" term="Jetty" /><title>Jetty使用心得筆記</title><content type="html">儿個月前試用了一陣子Jetty，當時對Jetty印象蠻好的。如果需要的是一個非常輕量或是可模組化設定的APServer，可以考慮這東東。不過...我自己用一陣子後還是換回Tomcat就是了...XD...這不是說Jetty不好，而是因為剛好Tomcat上有一些現成Webbase的APServer monitor工具，但是Jetty沒有。我又蠻需要這些工具，所以就還是換回Tomcat了。有時...好維護比高效來的重要呀...&amp;lt;(T_T)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
癈言結束，Jetty筆記(以7.4.5版本為基準)正文開始~~~&lt;br /&gt;
&lt;br /&gt;
==================================================================  &lt;br /&gt;
快速上手簡介&lt;br /&gt;
請參考JavaWorld@TW的&lt;a href="http://www.javaworld.com.tw/jute/post/view?bid=9&amp;amp;id=183376&amp;amp;tpg=1&amp;amp;ppg=1&amp;amp;sty=1&amp;amp;age=0#183376" target="_blank"&gt;這篇&lt;/a&gt;文章&lt;br /&gt;
==================================================================  &lt;br /&gt;
使用的好處，我個人覺的有這儿點&lt;br /&gt;
1.速度快&lt;br /&gt;
2.功能模組化，可以只啟用想要用的功能(e.g. 讓它只支援Servlet，不支援JSP)&lt;br /&gt;
3.還有很多，請上官網查詢&lt;br /&gt;
==================================================================  &lt;br /&gt;
Jetty比較重要的子目錄與相關說明如下&lt;br /&gt;
&lt;pre class="brush: text"&gt;Z:\JETTY-7.4.5
├─bin --&amp;gt; 存放Jetty的啟動批次檔(只有linux版的bash script)。此目錄等同於tomcat的/bin。
├─contexts --&amp;gt; 存放hot deploy相關設定檔(e.g. 如果有一個app叫test.war，可在這裡寫個test.xml設定檔，檔內可設定ContextPath相關設定。此目錄等同於tomcat的/conf。
├─contexts-available
├─etc --&amp;gt; 存放Jetty各功能模組的設定檔(e.g. jetty.xml、jetty-ssl.xml)，其中最重要的一個是jetty.xml，Jetty在啟動時一定要載入此設定檔。
├─lib
│  ├─annotations
│  ├─ext
│  ├─jndi
│  ├─jsp
│  ├─jta
│  └─policy
├─logs
├─overlays
│  ├─instances
│  ├─nodes
│  ├─templates
│  └─webapps
├─resources
└─webapps --&amp;gt; 存放各個webapp(war檔格式)的地方。此目錄等同於tomcat的/webapps。
&lt;/pre&gt;
================================================================== &lt;br /&gt;
Jetty啟動方式&lt;br /&gt;
1.Standalone：在Console下指令啟動&lt;br /&gt;
2.Embedded：寫JavaCode呼叫Jetty相關class來啟動(可參考&lt;a href="http://wiki.eclipse.org/Jetty/Tutorial/Embedding_Jetty" target="_blank"&gt;這裡&lt;/a&gt;的文件)&lt;br /&gt;
&lt;br /&gt;
Standalone方式啟動與關閉Jetty &lt;br /&gt;
&lt;pre class="brush: text"&gt;啟動指令：java -jar start.jar
關閉指令：直接按[Ctrl + C]
&lt;/pre&gt;
也可以用指定StopPort的方式來啟動與關閉Jetty，範例如下
&lt;br /&gt;
&lt;pre class="brush: text"&gt;啟動指令：java -DSTOP.PORT=8888 -DSTOP.KEY=jetty-password -jar start.jar
啟動指令：java -DSTOP.PORT=8888 -DSTOP.KEY=jetty-password -jar start.jar --stop

註："STOP.PORT"用來指定要停止Jetty時所用的port，"STOP.KEY"用來指定要停止Jetty時，所用的密碼
&lt;/pre&gt;
&lt;br /&gt;
輸入"java -jar start.jar --help"，可以得到Jetty在Console指令下的所有用法與參數說明。其中除了上述啟動與關閉Jetty的指令外，還有儿項比較有用的指令，分述如下。
&lt;br /&gt;
&lt;pre class="brush: text"&gt;"java -jar start.jar --list-options"指令：列出Jetty的"OPTIONS"參數可以設定的設定值清單
"java -jar start.jar --dry-run"指令：Print the command line that the start.jar generates,then exit. This may be used to generate command lines(不啟動Jetty，只列出啟動Jetty時，jvm實際上被呼叫的Consle指令)
&lt;/pre&gt;
================================================================== &lt;br /&gt;
"java -jar start.jar"指令的啟動流程如下&lt;br /&gt;
step1.載入/JettyInstallFolder/start.ini設定檔&lt;br /&gt;
step2.依據start.ini內容戴入各項Jetty設定&lt;br /&gt;
step3.載入/JettyInstallFolder/etc/webdefault.xml的設定供"所有"webapp使用&lt;br /&gt;
step4.載入各個webapp的web.xml設定&lt;br /&gt;
&lt;br /&gt;
start.ini的內容其實只是指定Jetty要戴入哪些功能模組(e.g. "etc/jetty.xml"、"etc/jetty-ssl.xml")，如果針對這些模組有客制化的需求，必需到各別模組設定檔中調整。&lt;br /&gt;
&lt;br /&gt;
webdefault.xml的設定值會在所有webapp啟動前被載入，如果有各別webapp在web.xml裡都一致的設定，可以將它移至此設定檔。&lt;br /&gt;
&lt;br /&gt;
jetty.xml裡比較重要的參數說明如下&lt;br /&gt;
&lt;pre class="brush: xml"&gt;&amp;lt;Call name="addConnector"&amp;gt;
  &amp;lt;Arg&amp;gt;
   &amp;lt;New class="org.eclipse.jetty.server.nio.SelectChannelConnector"&amp;gt;
  &amp;lt;!-- 指定http connection port --&amp;gt;
  &amp;lt;Set name="port"&amp;gt;&amp;lt;Property name="jetty.port" default="8080"/&amp;gt;&amp;lt;/Set&amp;gt;
  
  &amp;lt;!-- 指定connection time out的等待時間，單位為millisec --&amp;gt;
  &amp;lt;Set name="maxIdleTime"&amp;gt;43200000&amp;lt;/Set&amp;gt;
  
  &amp;lt;!-- 指定同一時間可以處理多少個request，同一時間要處理多個client的需求時，此值要加大。此值的設定跟CPU有關，CPU不夠力時，這個值不能設太大 --&amp;gt;
  &amp;lt;Set name="Acceptors"&amp;gt;2&amp;lt;/Set&amp;gt;
  
  &amp;lt;!-- 指定https connection port --&amp;gt;
  &amp;lt;Set name="confidentialPort"&amp;gt;8443&amp;lt;/Set&amp;gt;
   &amp;lt;/New&amp;gt;
  &amp;lt;/Arg&amp;gt;
&amp;lt;/Call&amp;gt;
&lt;/pre&gt;
&lt;br /&gt;
webdefault.xml裡比較重要的參數說明如下 &lt;br /&gt;
&lt;pre class="brush: text"&gt;acceptRanges      If true, range requests and responses are
                  supported

dirAllowed        If true, directory listings are returned if no
                  welcome file is found. Else 403 Forbidden.

welcomeServlets   If true, attempt to dispatch to welcome files
                  that are servlets, but only after no matching static
                  resources could be found. If false, then a welcome
                  file must exist on disk. If "exact", then exact
                  servlet matches are supported without an existing file.
                  Default is true.

                  This must be false if you want directory listings,
                  but have index.jsp in your welcome file list.

redirectWelcome   If true, welcome files are redirected rather than
                  forwarded to.

gzip              If set to true, then static content will be served as
                  gzip content encoded if a matching resource is
                  found ending with ".gz"

resourceBase      Set to replace the context resource base

resourceCache     If set, this is a context attribute name, which the servlet 
                  will use to look for a shared ResourceCache instance. 
                      
relativeResourceBase
                  Set with a pathname relative to the base of the
                  servlet context root. Useful for only serving static content out
                  of only specific subdirectories.

aliases           If True, aliases of resources are allowed (eg. symbolic
                  links and caps variations). May bypass security constraints.

maxCacheSize      The maximum total size of the cache or 0 for no cache.
maxCachedFileSize The maximum size of a file to cache
maxCachedFiles    The maximum number of files to cache

useFileMappedBuffer
                  If set to true, it will use mapped file buffer to serve static content
                  when using NIO connector. Setting this value to false means that
                  a direct buffer will be used instead of a mapped file buffer.
                  By default, this is set to true.

cacheControl      If set, all static content will have this value set as the cache-control
                  header.
&lt;/pre&gt;
&lt;br /&gt;
如果希望Jetty啟動時不要載入start.ini裡的設定，可以先刪除start.ini設定檔，並在啟動時指定明確的載入參數(e.g. "java -jar start.jar OPTIONS=Server,jsp,jmx etc/jetty.xml /etc/jetty-jmx.xml")，這樣就不會載入start.ini裡的設定。不過在start.ini設定檔中設好各項設定是比較方便的作法。 &lt;br /&gt;
==================================================================&lt;br /&gt;
Webapp若要deploy至Jetty，先將該webapp打包成war後，丟到webapps目錄裡即完成deploy動作(還有其它的方式，但是這是最簡單的方式)&lt;br /&gt;
&lt;br /&gt;
如果要把某個webapp當成Jetty的RootApp(代表"http://localhost:8080/"的url指到該webapp)，可將該webapp更名成root.war放至"webapp"目錄，並刪除"contexts"目錄裡的所有的檔案與子目錄。接著再重啟Jetty server，就會把root.war當成是RootApp。&lt;br /&gt;
==================================================================&lt;br /&gt;
Jetty在eclipse上有官方的plugin可供安裝(參考&lt;a href="http://wiki.eclipse.org/Jetty_WTP_Plugin" target="_blank"&gt;這份&lt;/a&gt;文件)。以前聽人說官方的效能很差，整合不好，很容易就當掉，多數人比較推"run-jetty-run"這個plugin；不過我自已試了官方最新版倒是沒有這些問題，覺的可以推薦給大家試試。&lt;br /&gt;
================================================================== &lt;br /&gt;
要限制Jetty使用的記憶體大小可以用下面的指令達成&lt;br /&gt;
java -Xms64m -Xmx128m -jar start.jar&lt;br /&gt;
==================================================================&lt;br /&gt;
使用JConsole來reomote monitor jetty有二種方式，分述如下&lt;br /&gt;
&lt;br /&gt;
&amp;lt;方式1&amp;gt;：使用JVM本身提供的JMX功能，步驟如下&lt;br /&gt;
&lt;br /&gt;
step1.利用文字編輯器撰寫一個 jmxremote.password 設定檔(參考下面範例內容)，並設定檔案的讀寫權限(在windows上執行的話，要確定硬碟的資料格式一定要是NTFS，FAT32格式是無法設定檔案權限的。此外，Windows上改檔案權限方式比較麻煩(可參考&lt;a href="http://download.oracle.com/javase/1,5.0/docs/guide/management/security-windows.html" target="_blank"&gt;這份&lt;/a&gt;文件)，在Linux上則是用chmod指令去改)&lt;br /&gt;
&lt;pre class="brush: text"&gt;user1 password1
&lt;/pre&gt;
&lt;br /&gt;
step2.利用文字編輯器撰寫一個 jmxremote.access 設定檔(參考下面範例內容)&lt;br /&gt;
&lt;pre class="brush: text"&gt;user1 readonly
&lt;/pre&gt;
&lt;br /&gt;
step3.Jetty在啟動時，利用下述的指令啟動JMX功能&lt;br /&gt;
&lt;pre class="brush: text"&gt;java ^
-Dcom.sun.management.jmxremote ^
-Djava.rmi.server.hostname=127.0.0.1 ^
-Dcom.sun.management.jmxremote.port=1099 ^
-Dcom.sun.management.jmxremote.ssl=false ^
-Dcom.sun.management.jmxremote.authenticate=true ^
-Dcom.sun.management.jmxremote.access.file=jmxremote.access ^
-Dcom.sun.management.jmxremote.password.file=jmxremote.password ^
-jar start.jar 
&lt;/pre&gt;
&lt;br /&gt;
step4.Jetty啟動後，可利用JConsle連進Jetty觀察系統狀況(Jconsole的連線設定範例如下)。&lt;br /&gt;
&lt;pre class="brush: text"&gt;url:127.0.0.1:1099
username:user1
password:password1
&lt;/pre&gt;
&lt;br /&gt;
硬&lt;strike&gt;大濕&lt;/strike&gt;大師有寫一篇&amp;lt;方式1&amp;gt;的相關文章，建議大家去&lt;a href="http://www.javaworld.com.tw/roller/ingramchen/entry/2006_12_3_JconsoleRemoteManagement" target="_blank"&gt;看一看&lt;/a&gt;，了解其中的一些細節&lt;br /&gt;
&lt;br /&gt;
&amp;lt;方式2&amp;gt;：使用Jetty提供的JMX功能，步驟如下&lt;br /&gt;
&lt;br /&gt;
step1.在start.ini內把jetty-jmx.xml設定檔啟用。在start.ini設定檔裡"Configuration files"設定區塊的第一行加進"etc/jetty-jmx.xml"(一定要放在這個區塊的第一行，不然JMX功能會失效)&lt;br /&gt;
&lt;br /&gt;
step2.在jetty-jmx.xml設定檔內把所有mark起來的功能unmark，啟用RMI功能。&lt;br /&gt;
&lt;br /&gt;
Jetty本身提供的功能無法設定以帳號、密碼方式來進行登入驗証，只要連上線就直接登入系統，使用上要小心。&lt;br /&gt;
==================================================================&lt;br /&gt;
&amp;nbsp;Jetty的TestRealm功能是用來設定使用者群組與權限，相關說明可參考&lt;a href="http://stackoverflow.com/questions/5323855/jetty-webserver-security" target="_blank"&gt;這裡&lt;/a&gt;&lt;br /&gt;
==================================================================&lt;br /&gt;
如果想對Jetty服務器架構及性能進行優化，可以參考之前我找到的&lt;a href="http://cloudtu.blogspot.com/2011/09/jetty.html" target="_blank"&gt;這份&lt;/a&gt;Slide&lt;br /&gt;
================================================================== &lt;br /&gt;
Jetty官網在&lt;a href="http://www.eclipse.org/jetty/" target="_blank"&gt;這裡&lt;/a&gt;&lt;br /&gt;
Jetty官方文件在&lt;a href="http://wiki.eclipse.org/Jetty" target="_blank"&gt;這裡&lt;/a&gt;&lt;br /&gt;
==================================================================&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9735843-7510473699618206123?l=cloudtu.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/pvDgV/~4/3XjvlEK-YJ0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://cloudtu.blogspot.com/feeds/7510473699618206123/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=9735843&amp;postID=7510473699618206123" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/7510473699618206123?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/7510473699618206123?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/pvDgV/~3/3XjvlEK-YJ0/jetty.html" title="Jetty使用心得筆記" /><author><name>Cloud Tu</name><uri>https://profiles.google.com/103480569436521613170</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-d8rzsEF047s/AAAAAAAAAAI/AAAAAAAAAbA/AXih8jz304M/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://cloudtu.blogspot.com/2011/11/jetty.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUEFSHw-fSp7ImA9WhRSE0g.&quot;"><id>tag:blogger.com,1999:blog-9735843.post-3337543888830873741</id><published>2011-11-15T16:50:00.000+08:00</published><updated>2011-11-15T19:46:59.255+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-15T19:46:59.255+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="程式語言" /><category scheme="http://www.blogger.com/atom/ns#" term="Cassandra" /><title>Cassandra Secondary indexes心得筆記</title><content type="html">這裡寫的Cassandra Secondary indexes功能是以1.0版為基準所驗証出來的結果。有些部份是以實際結果來反推它實作可能的方式，不知正確性為何。如果錯了，我之後再來修正吧...:P&lt;br /&gt;
&lt;br /&gt;
針對Cassandra的Secondary indexes功能，&lt;a href="http://www.datastax.com/docs/1.0/ddl/indexes#about-secondary-indexes" target="_blank"&gt;半官方文件&lt;/a&gt;是這麼說的&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;column上可建立index&lt;/li&gt;
&lt;li&gt; 建立index的column可以用"="進行查詢(e.g. get employee where dept = 'rd' ，dept的column有建index，所以可以用"="查詢)&lt;/li&gt;
&lt;li&gt;在查詢條件式中，最少要一個"="套用在有建立index的column，否則查詢會失敗&lt;/li&gt;
&lt;li&gt;column如果被建了index，它的column value不要有太多種可能性(e.g. country這個column name在我的系統中可能的值只'tw','us','jp'；這就很適合拿來建index，因為可能產生的值不多)&lt;/li&gt;
&lt;/ol&gt;
看完上述官方的論述後，應該還是搞不懂建了index後有啥好處，覺的官方是在講&lt;strike&gt;三小&lt;/strike&gt;外星語，會覺的index這功能很癈，只能作"="查詢，遜到爆了。&lt;br /&gt;
&lt;br /&gt;
當然...真相一定不是這樣的，不然這功能早就被罵翻天了。&lt;br /&gt;
&lt;br /&gt;
首先，先建立下述這個keyspace、column family，然後建立測試資料&lt;br /&gt;
&lt;pre class="brush: text"&gt;create keyspace testks
    with strategy_options=[{replication_factor:1}]
    and placement_strategy = 'org.apache.cassandra.locator.SimpleStrategy';

use testks;
 
create column family employee
    with comparator = UTF8Type
    and default_validation_class = UTF8Type
    and column_metadata = [
 {column_name : age,
     validation_class : LongType}, 
 {column_name : name,
     validation_class : UTF8Type}, 
 {column_name : dept,
     validation_class : UTF8Type,
     index_type : KEYS}  
    ]; 
&lt;/pre&gt;
&lt;pre class="brush: text"&gt;[default@testks] list employee;
Using default limit of 100
-------------------
RowKey: 3
=&amp;gt; (column=age, value=3, timestamp=1320997600912006)
=&amp;gt; (column=dept, value=rd, timestamp=1320997600913000)
=&amp;gt; (column=name, value=tester3, timestamp=1320997600912005)
-------------------
RowKey: 6
=&amp;gt; (column=age, value=6, timestamp=1320997600913008)
=&amp;gt; (column=dept, value=mis, timestamp=1320997600913009)
=&amp;gt; (column=name, value=tester6, timestamp=1320997600913007)
-------------------
RowKey: 5
=&amp;gt; (column=age, value=5, timestamp=1320997600913005)
=&amp;gt; (column=dept, value=rd, timestamp=1320997600913006)
=&amp;gt; (column=name, value=tester5, timestamp=1320997600913004)
-------------------
RowKey: 10
=&amp;gt; (column=age, value=10, timestamp=1320997600913020)
=&amp;gt; (column=dept, value=mis, timestamp=1320997600913021)
=&amp;gt; (column=name, value=tester10, timestamp=1320997600913019)
-------------------
RowKey: 8
=&amp;gt; (column=age, value=8, timestamp=1320997600913014)
=&amp;gt; (column=dept, value=mis, timestamp=1320997600913015)
=&amp;gt; (column=name, value=tester8, timestamp=1320997600913013)
-------------------
RowKey: 2
=&amp;gt; (column=age, value=2, timestamp=1320997600912003)
=&amp;gt; (column=dept, value=mis, timestamp=1320997600912004)
=&amp;gt; (column=name, value=tester2, timestamp=1320997600912002)
-------------------
RowKey: 1
=&amp;gt; (column=age, value=1, timestamp=1320997600912000)
=&amp;gt; (column=dept, value=rd, timestamp=1320997600912001)
=&amp;gt; (column=name, value=tester1, timestamp=1320997600897000)
-------------------
RowKey: 9
=&amp;gt; (column=age, value=9, timestamp=1320997600913017)
=&amp;gt; (column=dept, value=rd, timestamp=1320997600913018)
=&amp;gt; (column=name, value=tester9, timestamp=1320997600913016)
-------------------
RowKey: 4
=&amp;gt; (column=age, value=4, timestamp=1320997600913002)
=&amp;gt; (column=dept, value=mis, timestamp=1320997600913003)
=&amp;gt; (column=name, value=tester4, timestamp=1320997600913001)
-------------------
RowKey: 7
=&amp;gt; (column=age, value=7, timestamp=1320997600913011)
=&amp;gt; (column=dept, value=rd, timestamp=1320997600913012)
=&amp;gt; (column=name, value=tester7, timestamp=1320997600913010)

10 Rows Returned.
&lt;/pre&gt;
&lt;br /&gt;
以下是結合官方跟自己實際試驗過後得到的結論&lt;br /&gt;
1.只以一個欄位當查詢條件式，但該欄位沒建立index的話，無法直接用"=、&amp;gt;、&amp;lt;..."查詢&lt;br /&gt;
&lt;pre class="brush: text"&gt;[default@testks] get employee where age = 10;
No indexed columns present in index clause with operator EQ
[default@testks] get employee where age &amp;gt;= 10;
No indexed columns present in index clause with operator EQ
[default@testks] get employee where age &amp;lt;= 10;
No indexed columns present in index clause with operator EQ
&lt;/pre&gt;
&lt;br /&gt;
2.只以一個欄位當查詢條件式，但該欄位有建立index的話，只能用"="查詢&lt;br /&gt;
&lt;pre class="brush: text"&gt;[default@testks] get employee where dept = 'rd'; 
-------------------
RowKey: 3
=&amp;gt; (column=age, value=3, timestamp=1320997600912006)
=&amp;gt; (column=dept, value=rd, timestamp=1320997600913000)
=&amp;gt; (column=name, value=tester3, timestamp=1320997600912005)
-------------------
RowKey: 5
=&amp;gt; (column=age, value=5, timestamp=1320997600913005)
=&amp;gt; (column=dept, value=rd, timestamp=1320997600913006)
=&amp;gt; (column=name, value=tester5, timestamp=1320997600913004)
-------------------
RowKey: 1
=&amp;gt; (column=age, value=1, timestamp=1320997600912000)
=&amp;gt; (column=dept, value=rd, timestamp=1320997600912001)
=&amp;gt; (column=name, value=tester1, timestamp=1320997600897000)
-------------------
RowKey: 9
=&amp;gt; (column=age, value=9, timestamp=1320997600913017)
=&amp;gt; (column=dept, value=rd, timestamp=1320997600913018)
=&amp;gt; (column=name, value=tester9, timestamp=1320997600913016)
-------------------
RowKey: 7
=&amp;gt; (column=age, value=7, timestamp=1320997600913011)
=&amp;gt; (column=dept, value=rd, timestamp=1320997600913012)
=&amp;gt; (column=name, value=tester7, timestamp=1320997600913010)

5 Rows Returned.
[default@testks] get employee where dept &amp;gt;= 'rd';
No indexed columns present in index clause with operator EQ
[default@testks] get employee where dept &amp;lt;= 'rd';
No indexed columns present in index clause with operator EQ
&lt;/pre&gt;
&lt;br /&gt;
3.有多個欄位當查詢條件式；只要其中一個欄位有建立index，而且該欄位在查詢時是以"="條件進行查詢；其它欄位的查詢條件不管怎麼下，都不受限制("=、&amp;gt;、&amp;lt;..."都可以成功執行)。也就是說可以進行大家超想要的RangeQuery(e.g. age &amp;gt; 1 and age &amp;lt; 10)功能&lt;br /&gt;
&lt;pre class="brush: text"&gt;[default@testks] get employee where dept = 'rd' and age &amp;gt;=1 and age &amp;lt;=5 and name = 'tester5';
-------------------
RowKey: 5
=&amp;gt; (column=age, value=5, timestamp=1320997600913005)
=&amp;gt; (column=dept, value=rd, timestamp=1320997600913006)
=&amp;gt; (column=name, value=tester5, timestamp=1320997600913004)

1 Row Returned.
[default@testks] get employee where age &amp;gt;=1 and age &amp;lt;=5 and name = 'tester5' and dept = 'rd';
-------------------
RowKey: 5
=&amp;gt; (column=age, value=5, timestamp=1320997600913005)
=&amp;gt; (column=dept, value=rd, timestamp=1320997600913006)
=&amp;gt; (column=name, value=tester5, timestamp=1320997600913004)

1 Row Returned.
[default@testks] get employee where dept = 'rd' and age &amp;gt;=1 and age &amp;lt;=3;                     
-------------------
RowKey: 3
=&amp;gt; (column=age, value=3, timestamp=1320997600912006)
=&amp;gt; (column=dept, value=rd, timestamp=1320997600913000)
=&amp;gt; (column=name, value=tester3, timestamp=1320997600912005)
-------------------
RowKey: 1
=&amp;gt; (column=age, value=1, timestamp=1320997600912000)
=&amp;gt; (column=dept, value=rd, timestamp=1320997600912001)
=&amp;gt; (column=name, value=tester1, timestamp=1320997600897000)

2 Rows Returned.
&lt;/pre&gt;
&lt;br /&gt;
4.由第3點得証，&lt;span style="color: red;"&gt;查詢條件式如果出現多個欄位的查詢條件，只要其中一個有建立index，而且該欄位用"="查詢，其它欄位不建index也可以愛怎麼查就怎麼查&lt;/span&gt;。這部份的特性跟GoogleAppEnginge上的Datastore有很大的不同(Datastore裡，多個欄位的查詢條件要能成功，必需手動建立複合Key的索引，很麻煩)。&lt;br /&gt;
&lt;br /&gt;
"據說"(官方並未有文件說明)這類查詢在系統內的運作方式是先找出符合index欄位查詢條件的所有資料，接著用其它欄位的查詢條件做再次的篩選，所以才有辦法進行RangeQuery。但是這種查詢有個問題，那就是index欄位查詢條件查出的資料量不能太巨量，不然每次的查詢對系統而言應該會很吃Memory。&lt;br /&gt;
&lt;br /&gt;
5.column如果建了index，這個column的值不要有太多種，這有它的道理存在。因為值如果太多，會造成index資料檔變的非常巨大。如果將測試資料的age column也建了index，會發現它的index資料檔明顯比dept column的index資料檔要大很多(age的值有10種，1~10；dept的值只有2種，'mis','rd')&lt;br /&gt;
&lt;pre class="brush: text"&gt;employee.employee_age_idx-h-1-Data.db 741bytes
employee.employee_dept_idx-h-1-Data.db 266bytes
&lt;/pre&gt;
我不知道一個查詢條件中同時有好儿個欄位有建index是否對查詢(e.g "get employee where dept = 'rd' and age = 1"，dept與age都建立了index)有明顯的加速效果，但是可以很確定系統維護愈多的index，負擔會愈重。所以index適量就好，不是每個重要的欄位都一定要加index，有必要時再加就好。&lt;br /&gt;
&lt;br /&gt;
6.Secondary indexes功能可以讓你輕鬆實現RangeQuery的功能，請多善用這功能，會降低很多人工手動維謢index的負擔。不過...除了RangeQuery的功能外，想有Sorting的功能，Cassandra目前是辦不到的。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9735843-3337543888830873741?l=cloudtu.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/pvDgV/~4/-ctzzzLOy-M" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://cloudtu.blogspot.com/feeds/3337543888830873741/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=9735843&amp;postID=3337543888830873741" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/3337543888830873741?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/3337543888830873741?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/pvDgV/~3/-ctzzzLOy-M/cassandra-secondary-indexes.html" title="Cassandra Secondary indexes心得筆記" /><author><name>Cloud Tu</name><uri>https://profiles.google.com/103480569436521613170</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-d8rzsEF047s/AAAAAAAAAAI/AAAAAAAAAbA/AXih8jz304M/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://cloudtu.blogspot.com/2011/11/cassandra-secondary-indexes.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUMMRn04fSp7ImA9WhRTGE8.&quot;"><id>tag:blogger.com,1999:blog-9735843.post-8569727538174773447</id><published>2011-11-09T16:30:00.000+08:00</published><updated>2011-11-09T16:31:27.335+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-09T16:31:27.335+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="程式語言" /><category scheme="http://www.blogger.com/atom/ns#" term="Cassandra" /><title>Cassandra安裝筆記</title><content type="html">下述是以Cassandra 1.0為基準的安裝筆記，基本上不會有任何設置參數用途的說明，就單純只是Memo。&lt;br /&gt;
&lt;br /&gt;
Linux平台的安裝方式&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;解開cassandra binary tar file到特定目錄下 &lt;/li&gt;
&lt;li&gt;修改 cassandra_root/conf/cassandra-env.sh 設定檔裡下列所示參數值
&lt;pre class="brush: text"&gt;MAX_HEAP_SIZE="128M"
HEAP_NEWSIZE="32M"
JMX_PORT="7199"
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;修改 cassandra_root/conf/cassandra.yaml 設定檔裡下列所示參數值。initial_token參數的算法可以參考&lt;a href="http://cloudtu.blogspot.com/2011/11/cassandratoken.html" target="_blank"&gt;這篇&lt;/a&gt;文章
&lt;pre class="brush: text"&gt;cluster_name: 'Test Cluster'
initial_token: 0
data_file_directories:
&amp;nbsp;&amp;nbsp;&amp;nbsp; - /home/cloudtu/cassandra-1.0.0/data
commitlog_directory: /home/cloudtu/cassandra-1.0.0/commitlog
saved_caches_directory: /home/cloudtu/cassandra-1.0.0/saved_caches
seed_provider:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; - seeds: "127.0.0.1,127.0.0.2"
listen_address: 127.0.0.1
rpc_address: 127.0.0.1
rpc_port: 9160
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;修改 cassandra_root/conf/log4j-server.properties 設定檔裡下列所示參數值&lt;br /&gt;
&lt;pre class="brush: text"&gt;# rolling log file
log4j.appender.R.File=/home/cloudtu/cassandra-1.0.0/system.log
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;如果要讓cassandra有認証與授權功能，可參照&lt;a href="http://cloudtu.blogspot.com/2011/11/cassandra-authentication-and.html" target="_blank"&gt;這篇&lt;/a&gt;文章進行設定&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
Windows平台的安裝方式&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;解開cassandra binary tar file到特定目錄下 &lt;/li&gt;
&lt;li&gt;修改 cassandra_root\bin\cassandra.bat 設定檔裡下列所示參數值
&lt;pre class="brush: text"&gt;set JAVA_OPTS=-ea^
 -Xms32m^
 -Xmx128m^
 -Dcom.sun.management.jmxremote.port=7199^
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;修改 cassandra_root\conf\cassandra.yaml 設定檔裡下列所示參數值。initial_token參數的算法可以參考&lt;a href="http://cloudtu.blogspot.com/2011/11/cassandratoken.html" target="_blank"&gt;這篇&lt;/a&gt;文章
&lt;pre class="brush: text"&gt;cluster_name: 'Test Cluster'
initial_token: 0
data_file_directories:
&amp;nbsp;&amp;nbsp;&amp;nbsp; - d:\cassandra-1.0.0\data
commitlog_directory: d:\cassandra-1.0.0\commitlog
saved_caches_directory: d:\cassandra-1.0.0\saved_caches
seed_provider:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; - seeds: "127.0.0.1,127.0.0.2"
listen_address: 127.0.0.1
rpc_address: 127.0.0.1
rpc_port: 9160
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;修改 cassandra_root\conf\log4j-server.properties 設定檔裡下列所示參數值&lt;br /&gt;
&lt;pre class="brush: text"&gt;# rolling log file
log4j.appender.R.File=d:\cassandra-1.0.0\system.log
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;如果要讓cassandra有認証與授權功能，可參照&lt;a href="http://cloudtu.blogspot.com/2011/11/cassandra-authentication-and.html" target="_blank"&gt;這篇&lt;/a&gt;文章進行設定&lt;/li&gt;
&lt;li&gt;在console下執行"cassandra.bat install"指令可以將cassandra安裝成windows servcie，要移除此項service則是執行"cassandra.bat uninstall"指令&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9735843-8569727538174773447?l=cloudtu.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/pvDgV/~4/mFa5butJ-40" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://cloudtu.blogspot.com/feeds/8569727538174773447/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=9735843&amp;postID=8569727538174773447" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/8569727538174773447?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/8569727538174773447?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/pvDgV/~3/mFa5butJ-40/cassandra.html" title="Cassandra安裝筆記" /><author><name>Cloud Tu</name><uri>https://profiles.google.com/103480569436521613170</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-d8rzsEF047s/AAAAAAAAAAI/AAAAAAAAAbA/AXih8jz304M/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://cloudtu.blogspot.com/2011/11/cassandra.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0QCSXk_fip7ImA9WhRTFkg.&quot;"><id>tag:blogger.com,1999:blog-9735843.post-2991286480325943916</id><published>2011-11-07T16:42:00.001+08:00</published><updated>2011-11-07T16:42:48.746+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-07T16:42:48.746+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="程式語言" /><category scheme="http://www.blogger.com/atom/ns#" term="Cassandra" /><title>Cassandra的Token計算器</title><content type="html">在建立cassandra系統時，如果不去設定每個node裡cassandra.yaml設定檔的initial_token參數，新節點會被自動指派一個token值，但是自動指派的token值通常會造成每個node在整個ring裡的距離不相等，進而導致每個node負責的partition大小不相等。如果一開始就要讓partition相等，可以利用下面的這個Java版CassandraTokenCalc(這個Sample是網路上抄來的，不知道第儿手了，別問我來源跟演算法的根據是什麼...:P)來算出合適的token，然後手動指派initial_token參數值。&lt;br /&gt;
&lt;pre class="brush: java"&gt;public class CassandraTokenCalc {
 public static void main(String[] args) {
       String input = null;
       int nodeAmount = 0;
       try {
          System.out.print("Number of Cassandra Nodes: ");
          BufferedReader is = new BufferedReader(new InputStreamReader(System.in));
             input = is.readLine();
             nodeAmount = Integer.parseInt(input);
       }
       catch (NumberFormatException ex) {
          System.err.println("Not a valid number: " + input);
       }
       catch (IOException e) {
          System.err.println("Unexpected IO ERROR: " + e);
       }
       BigInteger tok = new BigInteger("170141183460469231731687303715884105728");
       for(int i=0; i&amp;lt;nodeAmount; i++){
          System.out.println("Node: " + i);
          System.out.println("initial_token: " + tok.multiply(BigInteger.valueOf(i)).divide(BigInteger.valueOf(nodeAmount)));
       }
 }
}
&lt;/pre&gt;
執行後的結果類似下面這樣&lt;br /&gt;
&lt;pre class="brush: text"&gt;Number of Cassandra Nodes: 3
Node: 0
initial_token: 0
Node: 1
initial_token: 56713727820156410577229101238628035242
Node: 2
initial_token: 113427455640312821154458202477256070485
&lt;/pre&gt;
&lt;br /&gt;
如果是現行已建置好的cassandra系統裡發現每個node所分配的partition不一致，可利用上面算出來的token值再配合 &lt;span style="color: #274e13;"&gt;nodetool...move...&lt;/span&gt; 指令來搬移現行的token，進而達到每個partition大小一致的目標。&lt;br /&gt;
&lt;br /&gt;
如果你對Python比較熟，可以參照&lt;a href="http://www.datastax.com/docs/1.0/install/cluster_init#token-gen-cassandra" target="_blank"&gt;這篇&lt;/a&gt;文章算出合適的token值。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9735843-2991286480325943916?l=cloudtu.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/pvDgV/~4/VRXNmJffmrY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://cloudtu.blogspot.com/feeds/2991286480325943916/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=9735843&amp;postID=2991286480325943916" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/2991286480325943916?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/2991286480325943916?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/pvDgV/~3/VRXNmJffmrY/cassandratoken.html" title="Cassandra的Token計算器" /><author><name>Cloud Tu</name><uri>https://profiles.google.com/103480569436521613170</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-d8rzsEF047s/AAAAAAAAAAI/AAAAAAAAAbA/AXih8jz304M/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://cloudtu.blogspot.com/2011/11/cassandratoken.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEMHSH48fSp7ImA9WhRVFkQ.&quot;"><id>tag:blogger.com,1999:blog-9735843.post-8211639854824700223</id><published>2011-11-04T17:30:00.000+08:00</published><updated>2012-01-16T14:47:19.075+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-16T14:47:19.075+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="程式語言" /><category scheme="http://www.blogger.com/atom/ns#" term="Cassandra" /><title>Cassandra authentication and authorization configuration</title><content type="html">Cassandra可以針對登入與授權進行設定，預設是不啟用此功能。也就是說在預設的狀況下，主機如果是放在Internet上，任何人只要知道你家Cassandra主機的IP與Port，就可以連進來逛大街...囧rz&lt;br /&gt;
&lt;br /&gt;
以下的Memo是1.0版本的設定方式，技術細節可以參考&lt;a href="http://www.datastax.com/docs/1.0/configuration/authentication" target="_blank"&gt;這份&lt;/a&gt;文件。&lt;span style="color: red;"&gt;目前1.0版的認証(authentication)功能正常，但是授權(authorization)功能異常，啟用授權功能後會導致存取資料時出現無存取權限的異常。&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
=================================================================================&lt;br /&gt;
Linux平台的設定方式&lt;br /&gt;
&lt;br /&gt;
1.因為1.0版裡面沒有&lt;span style="color: #274e13;"&gt;org.apache.cassandra.auth.SimpleAuthority、org.apache.cassandra.auth.SimpleAuthenticator、org.apache.cassandra.utils.Hex&lt;/span&gt;，所以先到&lt;a href="https://github.com/apache/cassandra" target="_blank"&gt;github&lt;/a&gt;上，把這些原始檔抓回來進行編譯，打包成 apache-cassandra-auth.jar 並放至 &lt;span style="color: #274e13;"&gt;cassandra_folder/lib&lt;/span&gt; 目錄中&lt;br /&gt;
&lt;br /&gt;
2.修改 &lt;span style="color: #274e13;"&gt;cassandra_folder/conf/cassandra-env.sh&lt;/span&gt;，在最後一行加入下列設定&lt;br /&gt;
&lt;pre class="brush: bash"&gt;JVM_OPTS="$JVM_OPTS -Dpasswd.properties=/cassandra_folder/conf/passwd.properties -Daccess.properties=/cassandra_folder/conf/access.properties"
 
&lt;/pre&gt;
&lt;br /&gt;
3.修改 &lt;span style="color: #274e13;"&gt;cassandra_folder/conf/cassandra.yaml&lt;/span&gt; 設定&lt;br /&gt;
&lt;pre class="brush: text"&gt;# authentication backend, implementing IAuthenticator; used to identify users
authenticator: org.apache.cassandra.auth.SimpleAuthenticator

# authorization backend, implementing IAuthority; used to limit access/provide permissions
#因為1.0版的SimpleAuthority功能異常，目前只能用AllowAllAuthority。所以只要能登入，就擁有所有權限
#authority: org.apache.cassandra.auth.SimpleAuthority
authority: org.apache.cassandra.auth.AllowAllAuthority&lt;/pre&gt;
&lt;br /&gt;
4.自行建立 &lt;span style="color: #274e13;"&gt;cassandra_folder/conf/passwd.properties&lt;/span&gt; 設定檔，加入下列設定&lt;br /&gt;
&lt;pre class="brush: text"&gt; 
# This is a sample password file for SimpleAuthenticator. The format of
# this file is username=password. If -Dpasswd.mode=MD5 then the password
# is represented as an md5 digest, otherwise it is cleartext (keep this
# in mind when setting file mode and ownership).
admin=adminpwd
user1=user1pwd
user2=user2pwd
&lt;/pre&gt;
&lt;br /&gt;
5.自行建立 &lt;span style="color: #274e13;"&gt;cassandra_folder/conf/access.properties&lt;/span&gt; 設定檔，加入下列設定(&lt;span style="color: red;"&gt;註：因為1.0版的SimpleAuthority功能會異常，所以我設定成AllowAllAuthority，而非SimpleAuthority。因此這個設定檔其實是不會生效的&lt;/span&gt;)&lt;br /&gt;
&lt;pre class="brush: text"&gt; 
# The magical '&amp;lt;modify-keyspaces&amp;gt;' property lists users who can modify the
# list of keyspaces: all users will be able to view the list of keyspaces.
&amp;lt;modify-keyspaces&amp;gt;=admin

# Access to Keyspace1 (add/remove column families, etc).
#system、testks是Keyspace的名稱，&amp;lt;rw&amp;gt;指read&amp;amp;write，&amp;lt;ro&amp;gt;指read only
system.&amp;lt;rw&amp;gt;=admin
testks.&amp;lt;rw&amp;gt;=admin
testks.&amp;lt;ro&amp;gt;=user1,user2
&lt;/pre&gt;
&lt;br /&gt;
6.啟動Cassandra，並利用Cassandra-CLI進行連線登入動作，如果出現類似下列的訊息，就代表設定成功了。 &lt;br /&gt;
&lt;pre class="brush: text"&gt;[default@unknown] connect 127.0.0.1/9160 admin 'adminpwd';
Connected to: "Test Cluster" on 127.0.0.1/9160&lt;/pre&gt;
如果登入失敗則會出現類似下列的訊息
&lt;br /&gt;
&lt;pre class="brush: text"&gt;[default@unknown] connect 127.0.0.1/9160 admin 'wrongpwd';
Exception during authentication to the cassandra node, Verify the keyspace exists, and that you are using the correct credentials.&lt;/pre&gt;
&lt;br /&gt;
=================================================================================&lt;br /&gt;
Windows平台的設定方式&lt;br /&gt;
&lt;br /&gt;
懶病發作，等以後有空時再來補...XD&lt;br /&gt;
&lt;br /&gt;
=================================================================================&lt;br /&gt;
如果需要利用Hector API登入需要進行登入認証與授權的Cassandra系統，可參考下列的程式碼範例&lt;br /&gt;
&lt;pre class="brush: java"&gt; CassandraHostConfigurator cassandraHostConfigurator = new CassandraHostConfigurator("127.0.0.1:9160");

 //use authentication and authorization
 Map&amp;lt;String,Stringgt; loginUser = new HashMap&amp;lt;String, Stringgt;();
 loginUser.put("username", "admin");
 loginUser.put("password", "adminpwd");
 Cluster cluster = HFactory.createCluster("TestCluster",cassandraHostConfigurator,loginUser);
 
 //do something else...etc
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9735843-8211639854824700223?l=cloudtu.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/pvDgV/~4/CQtrk-RtqCo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://cloudtu.blogspot.com/feeds/8211639854824700223/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=9735843&amp;postID=8211639854824700223" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/8211639854824700223?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/8211639854824700223?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/pvDgV/~3/CQtrk-RtqCo/cassandra-authentication-and.html" title="Cassandra authentication and authorization configuration" /><author><name>Cloud Tu</name><uri>https://profiles.google.com/103480569436521613170</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-d8rzsEF047s/AAAAAAAAAAI/AAAAAAAAAbA/AXih8jz304M/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://cloudtu.blogspot.com/2011/11/cassandra-authentication-and.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0cMQn4zcCp7ImA9WhRTFE0.&quot;"><id>tag:blogger.com,1999:blog-9735843.post-4363525955101324735</id><published>2011-10-27T00:05:00.004+08:00</published><updated>2011-11-04T20:18:03.088+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-04T20:18:03.088+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="GAE" /><category scheme="http://www.blogger.com/atom/ns#" term="程式語言" /><title>Google App Engine SDK 1.5.5 讓你加量不加價</title><content type="html">Google App Engine SDK 1.5.5版本發佈了。其實在發佈的那一二天我就馬上知道這消息了，但是感覺都沒什麼人在討論這事，因此就把它寫出來讓有用GAE的人參考一下。&lt;br /&gt;
&lt;br /&gt;
發佈新版是真的沒什麼，但是這一個新版的release note(&lt;a href="http://code.google.com/p/googleappengine/wiki/SdkReleaseNotes" target="_blank"&gt;按此&lt;/a&gt;)有儿個很讚的功能呀(節錄如下)，如果有打算跳入GAE這個火坑的人&lt;strike&gt;(不管Google未來收費有多麼坑錢)&lt;/strike&gt;，建議要想辦法升到這個版本。&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;We have increased the number of files you can upload with your application from 3,000 to 10,000.&lt;/li&gt;
&lt;li&gt;We have increased the size limit for a single file uploaded to App Engine from 10MB to 32MB.&lt;/li&gt;
&lt;li&gt;We have increased the Frontend request deadline from 30 seconds to 60 seconds.&lt;/li&gt;
&lt;li&gt;We
 have increased the online URLFetch maximum deadline from 10 seconds to 
60 seconds. The default deadline remains at 10 seconds. The offline 
maximum deadline for URLFetch remains at 10 minutes.&lt;/li&gt;
&lt;li&gt;We have increased the URLFetch Post payload from 1MB to 5MB.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&amp;nbsp;簡單來說，就是這版有些&lt;span style="font-size: large;"&gt;非常重要&lt;/span&gt;的功能讓你加量不加價。像是讓人最不爽的HttpRequest 30秒&lt;strike&gt;軟掉&lt;/strike&gt;Timeout的問題，現在被放大到60秒；這對一般直接porting到GAE上的系統來說，應該算是天大的好消息吧...XD&lt;br /&gt;
&lt;br /&gt;
附註：有時認真看看新版的release note也是能有意外收獲的!!!&lt;br /&gt;
&lt;ul&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9735843-4363525955101324735?l=cloudtu.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/pvDgV/~4/Xcw3oh6TRZs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://cloudtu.blogspot.com/feeds/4363525955101324735/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=9735843&amp;postID=4363525955101324735" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/4363525955101324735?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/4363525955101324735?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/pvDgV/~3/Xcw3oh6TRZs/google-app-engine-sdk-155.html" title="Google App Engine SDK 1.5.5 讓你加量不加價" /><author><name>Cloud Tu</name><uri>https://profiles.google.com/103480569436521613170</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-d8rzsEF047s/AAAAAAAAAAI/AAAAAAAAAbA/AXih8jz304M/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://cloudtu.blogspot.com/2011/10/google-app-engine-sdk-155.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0EHQHszeSp7ImA9WhRQEkk.&quot;"><id>tag:blogger.com,1999:blog-9735843.post-4169048593329507958</id><published>2011-10-03T20:41:00.001+08:00</published><updated>2011-12-07T15:07:11.581+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-07T15:07:11.581+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="程式語言" /><category scheme="http://www.blogger.com/atom/ns#" term="Connection Pool" /><title>DBCP Connection Pool 參數設置筆記</title><content type="html">這陣子因工作需要，必需寫一些對mySQL database頻繁存取的程式。理所當然的就一定會選用Connection Pool來加速DB連線的取得與管理。當時選用了DBCP與BoneCP兩種，下面是針對DBCP設置的SampleCode與心得筆記。&lt;br /&gt;
&lt;pre class="brush: java"&gt; 
public class ConnectionManager {  
 private static final BasicDataSource dataSource; 
 
 static{
     try {
      Class.forName("com.mysql.jdbc.Driver");
   dataSource = new BasicDataSource();
   dataSource.setUrl("dbConnectURL"); 
   dataSource.setUsername("dbUserName");
   dataSource.setPassword("dbPassword");
   dataSource.setMaxActive(dbPoolMaxActive); //connection pool的最大連線數
   dataSource.setMaxIdle(dbPoolMaxIdle); //connection pool的最小連線數
   dataSource.setMaxWait(10000); //單位為millisec。dataSource.getConnection()被呼叫時，超過多久時間未回應就回傳Exception訊息   
   dataSource.setValidationQuery("SELECT 1"); //用來驗証連線是否還活著。MySQL用的語法是用"SELECT 1"，其它DB要設其它對應的語法
   dataSource.setTestOnBorrow(true); //取回連線時是否要驗証連線還活著
   dataSource.setTestWhileIdle(true); //idle的連線是否要驗証還活著
   dataSource.setTimeBetweenEvictionRunsMillis(10000); //You have to set this value, otherwise even though 
                //you've asked connections to be tested while idle,
                //the idle evicter thread will never run
   dataSource.setMinEvictableIdleTimeMillis(60000); //Don't allow connections to hang out idle too long,
                       //never longer than what wait_timeout is set to on the
                   //mysql server.A few minutes or even fraction of a minute
                   //is sometimes okay here, it depends on your application
                   //and how much spikey load it will see
  }
     catch (Exception e) {
            throw new RuntimeException(e);
  }
 }  
  
    public static synchronized Connection getConnection(){
        try {
            return dataSource.getConnection();
        }
        catch (Exception e) {
            throw new RuntimeException(e);
        }       
    }  
}
&lt;/pre&gt;
&lt;br /&gt;
心得筆記&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;在mySQL裡執行"&lt;span style="color: #38761d;"&gt;show variables&lt;/span&gt;"查詢，找出"&lt;span style="color: #38761d;"&gt;wait_timeout參數&lt;/span&gt;"的設置時間(單位為秒)。Connection Pool的參數配置要配合此參數進行合適的調整，否則有時會出現遇想不到的問題。&lt;br /&gt;&lt;br /&gt;之前遇到DB的參數值為"wait_timeout=600"時，Connection Pool常出現&lt;span style="color: red;"&gt;Communications link failure&lt;/span&gt;的問題。這問題的根源其實在於DB，DB端timeout時間很短，所以Connection Pool的參數裡，每個連線的存活時間要跟著調小，以免發生DB端已把連線斷掉，Connection Pool卻不知道，進而導致程式取到已被斷開的連線，然後程式發生連線異常的問題。&amp;nbsp;&lt;/li&gt;
&lt;li&gt;DBCP的JavaDoc API&lt;a href="http://commons.apache.org/dbcp/api-1.4/index.html" target="_blank"&gt;在此&lt;/a&gt;，可查相關的設定明細說明。&lt;/li&gt;
&lt;li&gt;SampleCode裡的&lt;span style="color: #38761d;"&gt;dataSource.setValidationQuery(...)&lt;/span&gt;、&lt;span style="color: #38761d;"&gt;dataSource.setMinEvictableIdleTimeMillis(...)&lt;/span&gt;跟每種不同DB特性的關聯較大，要視使用何種DB做對應調整。&lt;/li&gt;
&lt;li&gt;DataSource本身並不是ThreadSafe，如果程式會開啟多個Thread同時取用連線，要加&lt;span style="color: red;"&gt;synchronized&lt;/span&gt;語法(如SampleCode所示)。&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9735843-4169048593329507958?l=cloudtu.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/pvDgV/~4/NUXYzz7L7go" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://cloudtu.blogspot.com/feeds/4169048593329507958/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=9735843&amp;postID=4169048593329507958" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/4169048593329507958?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/4169048593329507958?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/pvDgV/~3/NUXYzz7L7go/dbcp-connection-pool.html" title="DBCP Connection Pool 參數設置筆記" /><author><name>Cloud Tu</name><uri>https://profiles.google.com/103480569436521613170</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-d8rzsEF047s/AAAAAAAAAAI/AAAAAAAAAbA/AXih8jz304M/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://cloudtu.blogspot.com/2011/10/dbcp-connection-pool.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0EBQH84fSp7ImA9WhRQEkk.&quot;"><id>tag:blogger.com,1999:blog-9735843.post-5302382031583421586</id><published>2011-10-03T17:13:00.000+08:00</published><updated>2011-12-07T15:07:31.135+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-07T15:07:31.135+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="程式語言" /><category scheme="http://www.blogger.com/atom/ns#" term="Connection Pool" /><title>BoneCP Connection Pool 參數設置筆記</title><content type="html">這陣子因工作需要，必需寫一些對mySQL database頻繁存取的程式。理所當然的就一定會選用Connection Pool來加速DB連線的取得與管理。當時選用了DBCP與BoneCP兩種，下面是針對BoneCP設置的SampleCode與心得筆記。&lt;br /&gt;
&lt;pre class="brush: java"&gt;public class ConnectionManager {  
 private static final BoneCPDataSource dataSource; 
 
 static{
  try {
   Class.forName("com.mysql.jdbc.Driver");     
   dataSource = new BoneCPDataSource();
   dataSource.setJdbcUrl("dbConnectURL");
   dataSource.setUsername("dbUserName");
   dataSource.setPassword("dbPassword");
   dataSource.setPartitionCount(dbPoolPartitionCount); //connection pool的partition數量
   dataSource.setMaxConnectionsPerPartition(dbPoolMaxConnectionsPerPartition); //每個partition的最大連線數
   dataSource.setMinConnectionsPerPartition(dbPoolMinConnectionsPerPartition); //每個partition的最小連線數   
   dataSource.setIdleConnectionTestPeriodInMinutes(1); //檢查空閒連線的時間間隔
   dataSource.setConnectionTestStatement("SELECT 1");  //用來驗証連線是否還活著。MySQL用的語法是用"SELECT 1"，其它DB要設其它對應的語法；   
   dataSource.setIdleMaxAgeInMinutes(5); //空閒連線最大存活時間  
   dataSource.setConnectionTimeoutInMs(10000); //dataSource.getConnection()被呼叫時，超過多久時間未回應就回傳Timeout訊息
   //dataSource.setMaxConnectionAge(9, TimeUnit.MINUTES); //Sets the maxConnectionAge. Any connections older than this setting will be closed off whether it is idle or not.
                 //Connections currently in use will not be affected until they are returned to the pool.
                 //加入此項設定用來解決MySQL可能發生連線超時(SQLState = 08S01)的問題
   dataSource.setStatementsCacheSize(10);   
  }
  catch (Exception e) {
   throw new RuntimeException(e);
  }
 }   
  
    public static synchronized Connection getConnection(){
        try {
            return dataSource.getConnection();
        }
        catch (Exception e) {
            throw new RuntimeException(e);
        }       
    }  
}
&lt;/pre&gt;
&lt;br /&gt;
心得筆記&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;在mySQL裡執行"&lt;span style="color: #38761d;"&gt;show variables&lt;/span&gt;"查詢，找出"&lt;span style="color: #38761d;"&gt;wait_timeout參數&lt;/span&gt;"的設置時間(單位為秒)。Connection Pool的參數配置要配合此參數進行合適的調整，否則有時會出現遇想不到的問題。&lt;br /&gt;&lt;br /&gt;之前遇到DB的參數值為"wait_timeout=600"時，Connection Pool常出現&lt;span style="color: red;"&gt;Communications link failure&lt;/span&gt;的問題。這問題的根源其實在於DB，DB端timeout時間很短，所以Connection Pool的參數裡，每個連線的存活時間要跟著調小，以免發生DB端已把連線斷掉，Connection Pool卻不知道，進而導致程式取到已被斷開的連線，然後程式發生連線異常的問題。&amp;nbsp;&lt;/li&gt;
&lt;li&gt;BoneCP的JavaDoc API&lt;a href="http://jolbox.com/bonecp/downloads/site/apidocs/index.html" target="_blank"&gt;在此&lt;/a&gt;，可查相關的設定明細說明。&lt;/li&gt;
&lt;li&gt;SampleCode裡的&lt;span style="color: #38761d;"&gt;dataSource.setConnectionTestStatement(...)&lt;/span&gt;、&lt;span style="color: #38761d;"&gt;dataSource.setIdleMaxAgeInMinutes(...)&lt;/span&gt;、&lt;span style="color: #38761d;"&gt;dataSource.setMaxConnectionAge(...)&lt;/span&gt;跟每種不同DB特性的關聯較大，要視使用何種DB做對應調整。&lt;/li&gt;
&lt;li&gt;DataSource本身並不是ThreadSafe，如果程式會開啟多個Thread同時取用連線，要加&lt;span style="color: red;"&gt;synchronized&lt;/span&gt;語法(如SampleCode所示)。&lt;/li&gt;
&lt;li&gt;&lt;strike&gt;目前如果遇到BoneCP取出的連線在執行資料存取時發生異常，會丟出&lt;span style="color: red;"&gt;Database access problem. Killing off all remaining connections in the connection pool&lt;/span&gt;訊息，然後整個Connection Pool就掛掉了，目前還找不到真正的原因為何...囧rz&lt;br /&gt;&lt;br /&gt;目前為避免此問題，使用&lt;span style="color: #38761d;"&gt;dataSource.setMaxConnectionAge(...)&lt;span style="color: black;"&gt;強制設定&lt;/span&gt;&lt;/span&gt;Connection Pool裡每個Connection(不管是idle還是正被使用中)的生命周期，讓它在短時間內(e.g. 10分鐘)就要消滅，必需再從DB重新取得。&lt;/strike&gt;&lt;/li&gt;
&lt;/ol&gt;
updated 2011/10/31&lt;br /&gt;
這儿天發現&lt;span style="color: red;"&gt;「Database access problem. Killing off all remaining connections in the connection pool」&lt;span style="color: black;"&gt;問題的原因來自於程式本身的邏輯出錯，跟Connection Pool無關。當程式取出Connection後，完全不去用它，等到它超過Timeout的時間間隔後才去使用它，就有可能出現紅字的異常。一般的解決方式就是讓DAO功能的Class去綁定Connection，而不是BusineessObject去綁定Connection，進而達到Connection快速取得與釋放的目的。如果是寫WebApp，可以利用Filter來實作OpenSessionInView的機制，也可以達到同樣的效果，而且還省掉自己必需在程式碼中管理Connection取得與釋放的動作。&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;ol&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9735843-5302382031583421586?l=cloudtu.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/pvDgV/~4/97bMQhkeaOc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://cloudtu.blogspot.com/feeds/5302382031583421586/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=9735843&amp;postID=5302382031583421586" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/5302382031583421586?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/5302382031583421586?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/pvDgV/~3/97bMQhkeaOc/bonecp-connection-pool.html" title="BoneCP Connection Pool 參數設置筆記" /><author><name>Cloud Tu</name><uri>https://profiles.google.com/103480569436521613170</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-d8rzsEF047s/AAAAAAAAAAI/AAAAAAAAAbA/AXih8jz304M/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://cloudtu.blogspot.com/2011/10/bonecp-connection-pool.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0YESXk-eip7ImA9WhRTFE0.&quot;"><id>tag:blogger.com,1999:blog-9735843.post-6900836165587605754</id><published>2011-09-27T16:59:00.000+08:00</published><updated>2011-11-04T20:18:28.752+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-04T20:18:28.752+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="GAE" /><category scheme="http://www.blogger.com/atom/ns#" term="程式語言" /><title>Google App Engine 中文教學投影片</title><content type="html">下面這一整套教學課程投影片是目前我看到最完整的GAE中文教學投影片，有興趣的可以看看。雖然資料有點舊了，但是基本面的東西是不變的，這份內容還是非常受用。&lt;br /&gt;
&lt;br /&gt;
此外...因為這是人家提供的課程投影片，建議已經有基本的GAE實作功力後再來看。它並不是什麼快快樂樂上手指南，內容都非常的精要。完全不懂GAE就來看，應該會看不懂吧...XD &lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.slideboom.com/presentations/130128/Google-App-Engine-%2801%29---%E7%B0%A1%E4%BB%8B" target="_blank"&gt;Google App Engine (01) - 簡介&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://www.slideboom.com/presentations/130429/Google-App-Engine-%2802%29---Hello%2C-Google-App" target="_blank"&gt;Google App Engine (02) - Hello, Google App&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://www.slideboom.com/presentations/130431/Google-App-Engine-%2803%29---%E7%B6%B2%E9%A0%81%E8%AB%8B%E6%B1%82%E8%99%95%E7%90%86%E6%A9%9F%E5%88%B6" target="_blank"&gt;Google App Engine (03) - 網頁請求處理機制&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://www.slideboom.com/presentations/134172/Google-App-Engine-%2804%29---Datastore" target="_blank"&gt;Google App Engine (04) - Datastore&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://www.slideboom.com/presentations/134820/Google-App-Engine-%2805%29---Datastore-%E4%BA%A4%E6%98%93%E8%88%87-JPA" target="_blank"&gt;Google App Engine (05) - Datastore 交易與 JPA&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://www.slideboom.com/presentations/134821/Google-App-Engine-%2806%29---%E5%8F%AF%E6%93%B4%E5%B1%95%E6%9C%8D%E5%8B%99" target="_blank"&gt;Google App Engine (06) - 可擴展服務&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://www.slideboom.com/presentations/134833/Google-App-Engine-%2807%29---%E4%BB%BB%E5%8B%99%E4%BD%87%E5%88%97%E8%88%87%E6%8E%92%E7%A8%8B%E4%BB%BB%E5%8B%99" target="_blank"&gt;Google App Engine (07) - 任務佇列與排程任務&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://www.slideboom.com/presentations/134835/Google-App-Engine-%2808%29---%E7%B6%AD%E8%AD%B7%E4%BD%9C%E6%A5%AD" target="_blank"&gt;Google App Engine (08) - 維護作業&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9735843-6900836165587605754?l=cloudtu.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/pvDgV/~4/-vS4dbl4Vk4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://cloudtu.blogspot.com/feeds/6900836165587605754/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=9735843&amp;postID=6900836165587605754" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/6900836165587605754?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/6900836165587605754?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/pvDgV/~3/-vS4dbl4Vk4/google-app-engine_27.html" title="Google App Engine 中文教學投影片" /><author><name>Cloud Tu</name><uri>https://profiles.google.com/103480569436521613170</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-d8rzsEF047s/AAAAAAAAAAI/AAAAAAAAAbA/AXih8jz304M/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://cloudtu.blogspot.com/2011/09/google-app-engine_27.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0YGRHwzfSp7ImA9WhRTFE0.&quot;"><id>tag:blogger.com,1999:blog-9735843.post-4048608877534722798</id><published>2011-09-14T20:36:00.002+08:00</published><updated>2011-11-04T20:18:45.285+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-04T20:18:45.285+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="程式語言" /><category scheme="http://www.blogger.com/atom/ns#" term="Jetty" /><title>Jetty服務器架構及性能優化</title><content type="html">&lt;div id="__ss_7827140" style="width: 425px;"&gt;
&lt;b style="display: block; margin: 12px 0 4px;"&gt;&lt;a href="http://www.slideshare.net/lovingprince58/jettyv2-20115" target="_blank" title="Jetty服务器架构及调优.v2 2011-5"&gt;Jetty服务器架构及调优.v2 2011-5&lt;/a&gt;&lt;/b&gt; &lt;iframe frameborder="0" height="355" marginheight="0" marginwidth="0" scrolling="no" src="http://www.slideshare.net/slideshow/embed_code/7827140" width="425"&gt;&lt;/iframe&gt; &lt;br /&gt;
&lt;div style="padding: 5px 0 12px;"&gt;
View more &lt;a href="http://www.slideshare.net/" target="_blank"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/lovingprince58" target="_blank"&gt;lovingprince58&lt;/a&gt; &lt;/div&gt;
&lt;/div&gt;
&lt;br /&gt;
難得看到很不錯的Jetty架構介紹中文投影片，把它轉到blog上。對Jetty有興趣的可以看看...:P&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9735843-4048608877534722798?l=cloudtu.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/pvDgV/~4/HEsxMv3tm7M" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://cloudtu.blogspot.com/feeds/4048608877534722798/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=9735843&amp;postID=4048608877534722798" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/4048608877534722798?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/4048608877534722798?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/pvDgV/~3/HEsxMv3tm7M/jetty.html" title="Jetty服務器架構及性能優化" /><author><name>Cloud Tu</name><uri>https://profiles.google.com/103480569436521613170</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-d8rzsEF047s/AAAAAAAAAAI/AAAAAAAAAbA/AXih8jz304M/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://cloudtu.blogspot.com/2011/09/jetty.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0YHSX8zfSp7ImA9WhRTFE0.&quot;"><id>tag:blogger.com,1999:blog-9735843.post-5220527041771858626</id><published>2011-09-06T20:48:00.024+08:00</published><updated>2011-11-04T20:18:58.185+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-04T20:18:58.185+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="GAE" /><category scheme="http://www.blogger.com/atom/ns#" term="程式語言" /><category scheme="http://www.blogger.com/atom/ns#" term="心情記事" /><title>Google App Engine 要大幅漲價了</title><content type="html">這篇是我這陣子在G+上面，針對GoogleAppEngine大幅漲價的碎碎念集結...XD&lt;br /&gt;
&lt;br /&gt;
正文開始~~~&lt;br /&gt;
&lt;br /&gt;
前陣子GAE公佈了未來可能的收費方式，我覺的離實施的日子還好一陣子，就不以為意，暫時先沒去理它。直到...我看到&lt;a href="http://www.readwriteweb.com/hack/2011/09/google-app-engine-pricing-ange.php" target="_blank"&gt;這篇&lt;/a&gt;(&lt;a href="http://www.guao.hk/posts/google-app-engine-pricing-angers-developers-kills-plusfeed.html" target="_blank"&gt;中譯版&lt;/a&gt;)後，才驚覺大事不妙。不管未來收費為何，公司內是打定主意一定要用；但是...如果因為收費太貴導致我的單位被公司大頭狂電，這就不好玩了。所以認真的好好看了一下它未來的收費標準。&lt;br /&gt;
&lt;br /&gt;
Google針對未來收費標準的相關文章有下面儿篇&lt;br /&gt;
&lt;ol&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://www.google.com/enterprise/cloud/appengine/pricing.html" target="_blank"&gt;Google App Engine - Pricing and Features&lt;/a&gt;&lt;/li&gt;
&lt;br /&gt;
&lt;li&gt;&lt;a href="http://code.google.com/intl/zh-TW/appengine/articles/managing-resources.html" target="_blank"&gt;Managing Your App's Resource Usage&lt;/a&gt;&lt;/li&gt;
&lt;br /&gt;
&lt;li&gt;&lt;a href="http://code.google.com/intl/zh-TW/appengine/kb/postpreviewpricing.html" target="_blank"&gt;Google App Engine Post-Preview Pricing FAQ&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
&lt;br /&gt;
目前我的心得則是下面這些&lt;br /&gt;
&lt;ol&gt;&lt;br /&gt;
&lt;li&gt;backend servcie之後一定要用，這樣才可以強制我那些long time service跑在1 instance之上，免的被多收錢&lt;/li&gt;
&lt;br /&gt;
&lt;li&gt;datastore想要躲過爆衝的費用很難。現在我已經是能丟cache的都丟到cache裡了。datastore給的基本quota實在是太少了&lt;/li&gt;
&lt;br /&gt;
&lt;li&gt;官方提供一些省錢方式，有些根本是爛招。Concurrent Requests、Parallelize multiple datastore RPCs via the async datastore API，這些我也知道是改善效能的好方法。問題是...整個team裡有多少人可以寫這種程式而且保証不出包?程式一但因為用了這些方式處理而出包了，省再多的錢也沒屁用&lt;/li&gt;
&lt;br /&gt;
&lt;li&gt;Google....is evil (至少在目前暫定的收費標準下蠻evil的)&lt;/li&gt;
&lt;br /&gt;
&lt;li&gt;有些人開始關注&lt;a href="http://code.google.com/p/appscale/" target="_blank"&gt;AppScale&lt;/a&gt;這個OpenSourceProject。以前常看到有人blog要搬家，現在GAE上也要上演旅鼠大遷移了嗎?...LOL&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
&lt;br /&gt;
最後...語重心長的說句...「免錢的最貴!!!」...(攤手)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9735843-5220527041771858626?l=cloudtu.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/pvDgV/~4/Bo0AcG5QgYs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://cloudtu.blogspot.com/feeds/5220527041771858626/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=9735843&amp;postID=5220527041771858626" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/5220527041771858626?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/5220527041771858626?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/pvDgV/~3/Bo0AcG5QgYs/google-app-engine.html" title="Google App Engine 要大幅漲價了" /><author><name>Cloud Tu</name><uri>https://profiles.google.com/103480569436521613170</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-d8rzsEF047s/AAAAAAAAAAI/AAAAAAAAAbA/AXih8jz304M/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://cloudtu.blogspot.com/2011/09/google-app-engine.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0YASHY7cCp7ImA9WhRTFE0.&quot;"><id>tag:blogger.com,1999:blog-9735843.post-6639832339381083626</id><published>2011-08-31T16:16:00.034+08:00</published><updated>2011-11-04T20:19:09.808+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-04T20:19:09.808+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="GAE" /><category scheme="http://www.blogger.com/atom/ns#" term="程式語言" /><title>GAE Backend Service 簡略心得筆記(2)</title><content type="html">原本以為GAE Backend Service除了要花錢讓人覺的很貴之外，應該沒什麼難的。結果發現我錯了。實做上發現有些很讓人頭大(或怪異)的地方。最糟的是官方都沒講，所以會讓人走很多錯路...Orz
&lt;br /&gt;
&lt;br /&gt;在開始之前，先看一下&lt;a href="http://www.pdjamez.com/2011/05/google-app-engine-backends-part-deux/" target="_blank"&gt;這篇&lt;/a&gt;我個人覺的很重要的文章。
&lt;br /&gt;
&lt;br /&gt;看完後，我實做驗証得到的心得如下
&lt;br /&gt;&lt;ol&gt;
&lt;br /&gt;  &lt;li&gt;backends.xml這個設定檔，如果用最新版的gae eclipse plugin進行deploy至gae server，目前依然無法上傳上去。這明顯是個很有問題的bug。目前還是只能用下指令的方式來上傳這個設定檔。指令檔的操作方式如下所示。
&lt;br /&gt;
&lt;br /&gt;&lt;font color="green"&gt;appcfg backends  &amp;lt;path to the root of your war directory&amp;gt; update&lt;/font&gt;&lt;/li&gt;
&lt;br /&gt;  &lt;li&gt;官方說Backend Service可以在Cronjob中呼叫，但是官方卻沒教你怎麼辦到，一整個就是裝笑偉。前面那份參考文件所提的那種方式算是利用一個很取巧的方式(利用&amp;lt;target&amp;gt; tag的功能)來達到這個功能，雖然不正規，但是個很方便的解法。範例如下，請注意綠色所示部份
&lt;br /&gt;
&lt;br /&gt;&amp;lt;cron&amp;gt;
&lt;br /&gt;    &amp;lt;url&amp;gt;/XXXServlet&amp;lt;/url&amp;gt;
&lt;br /&gt; &lt;font color="green"&gt;&amp;lt;target&amp;gt;BackendServiceName&amp;lt;/target&amp;gt;&lt;/font&gt;
&lt;br /&gt;    &amp;lt;description&amp;gt;Call by backend service sample&amp;lt;/description&amp;gt;
&lt;br /&gt;    &amp;lt;schedule&amp;gt;every 1 minutes&amp;lt;/schedule&amp;gt;
&lt;br /&gt;&amp;lt;/cron&amp;gt;
&lt;br /&gt;&lt;/li&gt;
&lt;br /&gt;  &lt;li&gt;Backend Service的使用狀況可以在gae admin console上查到，但是要切換到下圖紅框所示的選項才可以看的到裡面的細項，這點要注意。
&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-JBeTusgbq78/Tl36EQAeF8I/AAAAAAAAAkc/MJG4_u0wtOA/s1600/backend.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 141px;" src="http://3.bp.blogspot.com/-JBeTusgbq78/Tl36EQAeF8I/AAAAAAAAAkc/MJG4_u0wtOA/s320/backend.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5646944458715830210" /&gt;&lt;/a&gt;
&lt;br /&gt;&lt;/li&gt;
&lt;br /&gt;  &lt;li&gt;官方一直強調Backend Service要付費才能用。事實上沒付費的狀況下，每天有$0.72的quota可用。也就是說如果你只是實驗性的測試一些東西，並且讓它在Backend Service上運行，基本上撐個儿個小時是不成問題的，最差的狀況就是爆quota而已。&lt;/li&gt;
&lt;br /&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9735843-6639832339381083626?l=cloudtu.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/pvDgV/~4/oR4iMhJPjEk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://cloudtu.blogspot.com/feeds/6639832339381083626/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=9735843&amp;postID=6639832339381083626" title="1 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/6639832339381083626?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/6639832339381083626?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/pvDgV/~3/oR4iMhJPjEk/gae-backend-service-2.html" title="GAE Backend Service 簡略心得筆記(2)" /><author><name>Cloud Tu</name><uri>https://profiles.google.com/103480569436521613170</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-d8rzsEF047s/AAAAAAAAAAI/AAAAAAAAAbA/AXih8jz304M/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-JBeTusgbq78/Tl36EQAeF8I/AAAAAAAAAkc/MJG4_u0wtOA/s72-c/backend.jpg" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://cloudtu.blogspot.com/2011/08/gae-backend-service-2.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0YDQ34zfSp7ImA9WhRTFE0.&quot;"><id>tag:blogger.com,1999:blog-9735843.post-3933205000865858068</id><published>2011-08-29T14:32:00.009+08:00</published><updated>2011-11-04T20:19:32.085+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-04T20:19:32.085+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="GAE" /><category scheme="http://www.blogger.com/atom/ns#" term="程式語言" /><title>GAE Backend Service 簡略心得筆記(1)</title><content type="html">&lt;ol&gt;
&lt;br /&gt;&lt;li&gt;費用貴。費用算法by時間，不是by流量。最便宜的組合是1小時要US$0.08&lt;/li&gt;
&lt;br /&gt;&lt;li&gt;最大好處是沒有"30-second deadline for HTTP requests, 10-minute deadline for tasks"這二個限制&lt;/li&gt;
&lt;br /&gt;&lt;li&gt;每個GAE App可以啟動最多5個backend Services&lt;/li&gt;
&lt;br /&gt;&lt;li&gt;要利用Backend Service來處理http request，Client端的URL必需像下面這樣
&lt;br /&gt;
&lt;br /&gt;&lt;font color="green"&gt;http://[instance].[backend].[app].appspot.com/[XXXServlet]&lt;/font&gt;
&lt;br /&gt;
&lt;br /&gt;也就是說只有加了特定的prefix，一般的HttpServlet(or jsp...etc)就會轉由Backend Service代為處理
&lt;br /&gt;&lt;/li&gt;
&lt;br /&gt;&lt;li&gt;Backend Service預設權限是"private"，也就是說沒有admin的權限下，一般user是不能直接經由上述所列的url直接呼叫。當然...這是Backend Service本身設計上的考量，如果要強行打開變成"public"也ok&lt;/li&gt;
&lt;br /&gt;&lt;li&gt;官方文件網址如下
&lt;br /&gt;&lt;a href="http://code.google.com/intl/en/appengine/docs/java/backends/overview.html" target="_blank"&gt;http://code.google.com/intl/en/appengine/docs/java/backends/overview.html&lt;/a&gt;&lt;/li&gt;
&lt;br /&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9735843-3933205000865858068?l=cloudtu.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/pvDgV/~4/W0hIeIvBtmo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://cloudtu.blogspot.com/feeds/3933205000865858068/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=9735843&amp;postID=3933205000865858068" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/3933205000865858068?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9735843/posts/default/3933205000865858068?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/pvDgV/~3/W0hIeIvBtmo/gae-backend-service.html" title="GAE Backend Service 簡略心得筆記(1)" /><author><name>Cloud Tu</name><uri>https://profiles.google.com/103480569436521613170</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-d8rzsEF047s/AAAAAAAAAAI/AAAAAAAAAbA/AXih8jz304M/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://cloudtu.blogspot.com/2011/08/gae-backend-service.html</feedburner:origLink></entry></feed>

