Search This Blog

Thursday, August 2, 2012

How to use internaly Cloud Files from dedicated servers when using Rackconnect

This is a similar to the previous post: It is possible to use Cloud Files on the private ServiceNet from Cloud Servers .

This issue a example where this questions was asked: Gladinet CloudAFS : RackSpace Servicenet

When the Rackconnect is implementd it changes the default gateway on the cloud servers. It is used as defautl gateway for the dedicated servers when they want to sent traffic to the Rackspace cloud infrastructure. That all togheter means that when the dedicated server wants to sent a Cloud Files API request all what they have to do is to use the privatge network IP address/URL name [1]

$ dig +short A snet-storage101.lon3.clouddrive.com
10.191.209.30

$ curl -X GET -D - -H "X-Auth-Token: mytocken" https://snet-storage101.lon3.clouddrive.com/v1/MossoCloudFS_f3ae48bb-983f-49e1-b656-0c58730fed1b

References
  1. http://www.rackspace.com/blog/networking-and-cloud-servers-more-on-the-interfaces/
  2. http://support.rightscale.com/06-FAQs/What_is_Rackspace_ServiceNet_and_how_can_I_use_it%3F
  3. http://www.rackspace.com/knowledge_center/frequently-asked-question/what-is-servicenet

It is possible to use Cloud Files (CF) on the private ServiceNet from Cloud Servers

In the Rackspace API documentation [1] there is information how to authenticate yourself before you can start sending request to use Cloud files. With the API you can easily for example store a file or get a containers listing.

# to authenticate your self 
$ curl -D - -H "X-Auth-User: myuser" -H "X-Auth-Key: mykey"  https://lon.auth.api.rackspacecloud.com/v1.0
HTTP/1.1 204 No Content
Server: Apache/2.2.3 (Red Hat)
vary: X-Auth-User,X-Auth-Key,X-Storage-User,X-Storage-Pass
X-Storage-Url: https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_f3ae48bb-983f-49e1-b656-0c58730fed1b
Cache-Control: s-maxage=63832
Content-Type: text/xml
Date: Wed, 01 Aug 2012 14:04:51 GMT
X-Auth-Token: 22222222
X-Server-Management-Url: https://lon.servers.api.rackspacecloud.com/v1.0/10020713
X-Storage-Token: 111111111111
Connection: Keep-Alive
X-CDN-Management-Url: https://cdn3.clouddrive.com/v1/MossoCloudFS_f3ae48bb-983f-49e1-b656-0c58730fed1b
Content-Length: 0

# get listing 
$ curl -X GET -D - -H "X-Auth-Token: myusr" https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_f3ae48bb-983f-49e1-b656-0c58730fed1b
HTTP/1.1 200 OK
X-Account-Object-Count: 2
X-Timestamp: 1341923250.51682
X-Account-Bytes-Used: 3210734282
X-Account-Container-Count: 2
Accept-Ranges: bytes
Content-Length: 18
Content-Type: text/plain; charset=utf-8
X-Trans-Id: txa863fe8321ab4b44a31d886d1a9a7fb1
Date: Wed, 01 Aug 2012 14:17:30 GMT

Test1
Test2

The most important thing to note is that the X-Storage-Url points by default to an external IP. It means that every request sent has to go out to get than back to the cloud files. Unnecessary wasting of network bandwidth and additional latency and delay.

$ dig +short A storage101.lon3.clouddrive.com
94.236.56.96

To work this around you can use a little modified X-Storage-Url value and append the snet string at the beginning to the server name.

$ dig +short A storage101.lon3.clouddrive.com
94.236.56.96

$ dig +short A snet-storage101.lon3.clouddrive.com
10.191.209.30

Because the IP 10.191.209.30 belongs to the Rackspace internal service network all the communication will be kept inside. From the cloud server point of view it will believe that it sent traffic to an internal host. No need to use a default gateway and complicated routing of deliver the traffic to the destination host.

A correct Cloud File API request that is utilizing the internal service network within Rackspace cloud infrastructure:

$ curl -X GET -D - -H "X-Auth-Token: mytoken" https://snet-storage101.lon3.clouddrive.com/v1/MossoCloudFS_f3ae48bb-983f-49e1-b656-0c58730fed1b

References
  1. http://docs.rackspace.com/files/api/v1/cf-devguide/content/Authentication-d1e639.html
  2. http://www.rackspace.com/cloud/public/files/api/
  3. http://www.rackspace.com/knowledge_center/getting-started/cloud-files
  4. http://blog.chmouel.com/2009/10/20/accessing-to-rackspace-cloud-files-via-servicenet-update/
  5. http://loose-bits.com/2010/10/rackspace-cloud-files-and-servicenet.html
  6. http://docs.rackspace.com/files/api/v1/cf-devguide/content/Service-Access-Endpoints-d1e003.html

Tuesday, July 31, 2012

How does the GIL affect my python program when threads are used

This is in relation to the previous post: "What does the GIL lock means when I use threads in Python" .

I have been reading more about the GIL problem in Python and found out that this limitation only exists for CPython. It is not present in the Java base implementation of the python interpreter [1].

Still not convinced how much it affects the execution time I run couple of tests.

A test program

Cloud server provisioning

I have provisioned a 32GB cloud server for the tests. These are some of the server details.
$ cat /proc/cpuinfo  | egrep 'proc|model name' | sort | uniq 
model name : Quad-Core AMD Opteron(tm) Processor 2374 HE
processor : 0
...
processor : 7

$ free -m
            total       used       free     shared    buffers     cached
Mem:         30041       8364      21676          0         34        580
-/+ buffers/cache:       7749      22291
Swap:        61436          0      61436

$ python -V
Python 2.7.3

$ jython -V
Jython 2.5.1+

$ ls -al /etc/alternatives/java
lrwxrwxrwx 1 root root 46 Jul 31 19:36 /etc/alternatives/java -> /usr/lib/jvm/java-6-openjdk-amd64/jre/bin/java

$ /usr/bin/java -version
java version "1.6.0_24"
OpenJDK Runtime Environment (IcedTea6 1.11.3) (6b24-1.11.3-1ubuntu0.12.04.1)
OpenJDK 64-Bit Server VM (build 20.0-b12, mixed mode)

Test results

I run 4 tests. Two with the python and two with the jython interpreter. To start the tests i used:
$ /usr/bin/time -v jython gil_threads_test.py | tee log 
$ /usr/bin/time -v python gil_threads_test.py | tee log
The results for the python after filtering out the unnecessary lines ( results | grep -v ': 0' )
Test1 
  Command being timed: "python gil_threads_test.py"
  User time (seconds): 759.93
  System time (seconds): 516.46
  Percent of CPU this job got: 170%
  Elapsed (wall clock) time (h:mm:ss or m:ss): 12:27.25
  Maximum resident set size (kbytes): 76240000
  Minor (reclaiming a frame) page faults: 5806046
  Voluntary context switches: 44574718 
  Involuntary context switches: 3311991
 
Test2
  Command being timed: "python gil_threads_test.py"
  User time (seconds): 760.37
  System time (seconds): 515.21
  Percent of CPU this job got: 170%
  Elapsed (wall clock) time (h:mm:ss or m:ss): 12:30.16
  Maximum resident set size (kbytes): 76066992
  Minor (reclaiming a frame) page faults: 5817319
  Voluntary context switches: 44574153
  Involuntary context switches: 3318754
  Page size (bytes): 4096
The results for the jython after filtering out the unnecessary lines ( results | grep -v ': 0' )
Test3
  Command being timed: "jython gil_threads_test.py"
  User time (seconds): 955.74
  System time (seconds): 16.31
  Percent of CPU this job got: 397%
  Elapsed (wall clock) time (h:mm:ss or m:ss): 4:04.75
  Maximum resident set size (kbytes): 30018032
  Minor (reclaiming a frame) page faults: 2034262
  Voluntary context switches: 83887
  Involuntary context switches: 110640
  File system outputs: 328
  Page size (bytes): 4096
  
Test4
  Command being timed: "jython gil_threads_test.py"
  User time (seconds): 984.16
  System time (seconds): 16.22
  Percent of CPU this job got: 385%
  Elapsed (wall clock) time (h:mm:ss or m:ss): 4:19.69
  Maximum resident set size (kbytes): 30718496
  Minor (reclaiming a frame) page faults: 2070011
  Voluntary context switches: 97457
  Involuntary context switches: 109420
  File system outputs: 344
  Page size (bytes): 4096

Analisis and results description
  • The execution of the test{1,2} was a lot longer than for test{3,4}. The CPython interpreter needed 12:27.25/12:30.16 versus 4:04.75/4:19.69 for the Jython.
  • The gil_threads_test.py script CPU utilization in user space is about 20% higher for Jython and there is a big difference how much time the interpreters spent in kernel mode.

    Looking at the output from top during the tests we saw that java was able to use 100% all 7 CPUs where python managed only to use have utilization of 13-20%.

    The increaded number of context swithces for python has a direct impact on performance what the execution time results show clearly.
  • One interesting thing. The memory usage is about 100% higher when python is used. Looks like java is able to better manged the memory allocation and memory management. But I'm not sure as well as how much we can trust the output from the utime -v command for this.


References
  1. http://www.jython.org/jythonbook/en/1.0/Concurrency.html

What does the GIL lock means when I use threads in Python

Looking for a way to introduce parallelism to your code you are quickly going to find that there are two different solutions: either you can use threads or processes.

Although python supports both [1] and [2] models the support for threads has a following warning:

[1] CPython implementation detail: Due to the Global Interpreter Lock, in CPython only one thread can execute Python code at once.

It took me a while to understand what this actualy means. This is a serious limitation for a multithreaded programming and it still exists even in the latest python version 3.x [3]. To better understanding what this means this is an example from one of the links below I found:

The GIL enforces Python's requirement that only a single bytecode operation is executed at a time.

References

  1. http://docs.python.org/library/threading.html
  2. http://docs.python.org/library/multiprocessing.html#module-multiprocessing
  3. http://docs.python.org/py3k/library/threading.html

  4. Google search about GIL has many link, I personaly found these very useful
  5. http://www.grouplens.org/node/244
    http://linuxgazette.net/107/pai.html

    The section "Write multithreaded or multiprocess code"
    http://www.scipy.org/ParallelProgramming

    http://stackoverflow.com/questions/10344529/is-the-max-thread-limit-actually-a-non-relevant-issue-for-python-linux
    http://stackoverflow.com/questions/7053284/what-is-more-suitable-in-performance-aspect-multithreading-or-multiprocessing

  6. These below are a little longer to read but they talk about the problem and around it on a very low level
  7. http://www.jeffknupp.com/blog/2012/03/31/pythons-hardest-problem/
    http://jessenoller.com/2009/02/01/python-threads-and-the-global-interpreter-lock/

Sunday, July 29, 2012

How to clean and delete multiple cloud servers after a failed test

The best think about open cloud API is that it is easy accessible and can be easily scripted around. For exmaple during one of my tests I created multiple cloud servers but my job failed and didn't delete them before the exception was thrownd.

Problem

How to extract cloud server names from the log file and how to delted all of them from the accout.

$ python performance-single-cs.py-t 1 -s 25 -u user -k key  run | tee log.$(date +%s).txt
$ cat log*.txt
[ 1][  ] starting test nr 1, creating 25 cloud server, please wait ...
[ 1][ 1] created image: {'flavor': 1, 'image': 112, 'name': 'test7945'}
[ 1][ 2] created image: {'flavor': 1, 'image': 112, 'name': 'test7948'}
[ 1][ 3] created image: {'flavor': 1, 'image': 112, 'name': 'test7951'}
[ 1][ 4] created image: {'flavor': 1, 'image': 112, 'name': 'test7954'}
[ 1][ 5] created image: {'flavor': 1, 'image': 112, 'name': 'test7958'}
[ 1][ 6] created image: {'flavor': 1, 'image': 112, 'name': 'test7961'}
[ 1][ 7] created image: {'flavor': 1, 'image': 112, 'name': 'test7965'}
[ 1][ 8] created image: {'flavor': 1, 'image': 112, 'name': 'test7969'}
[ 1][ 9] created image: {'flavor': 1, 'image': 112, 'name': 'test7972'}
[ 1][10] created image: {'flavor': 1, 'image': 112, 'name': 'test7976'}
[ 1][11] created image: {'flavor': 1, 'image': 112, 'name': 'test8050'}
[ 1][12] created image: {'flavor': 1, 'image': 112, 'name': 'test8054'}
[ 1][13] created image: {'flavor': 1, 'image': 112, 'name': 'test8059'}
[ 1][14] created image: {'flavor': 1, 'image': 112, 'name': 'test8063'}
[ 1][15] created image: {'flavor': 1, 'image': 112, 'name': 'test8068'}
[ 1][16] created image: {'flavor': 1, 'image': 112, 'name': 'test8072'}
[ 1][17] created image: {'flavor': 1, 'image': 112, 'name': 'test8077'}
[ 1][18] created image: {'flavor': 1, 'image': 112, 'name': 'test8082'}
[ 1][19] created image: {'flavor': 1, 'image': 112, 'name': 'test8086'}
[ 1][20] created image: {'flavor': 1, 'image': 112, 'name': 'test8091'}
[ 1][21] created image: {'flavor': 1, 'image': 112, 'name': 'test8117'}
[ 1][22] created image: {'flavor': 1, 'image': 112, 'name': 'test8192'}
[ 1][23] created image: {'flavor': 1, 'image': 112, 'name': 'test8197'}
[ 1][24] created image: {'flavor': 1, 'image': 112, 'name': 'test8202'}
[ 1][25] created image: {'flavor': 1, 'image': 112, 'name': 'test8208'}
[ 1][ 1] cloud server build [test7945] created in 298.427304 seconds / 4.9737884 minutes
[ 1][ 2] cloud server build [test7948] created in 298.331735 seconds / 4.97219558333 minutes
[ 1][ 3] cloud server build [test7951] created in 298.268271 seconds / 4.97113785 minutes
[ 1][ 4] cloud server build [test7954] created in 298.469954 seconds / 4.97449923333 minutes
[ 1][ 5] cloud server build [test7958] created in 298.202301 seconds / 4.97003835 minutes
[ 1][ 6] cloud server build [test7961] created in 297.702382 seconds / 4.96170636667 minutes
[ 1][ 7] cloud server build [test7965] created in 298.051012 seconds / 4.96751686667 minutes
[ 1][ 8] cloud server build [test7969] created in 297.3658 seconds / 4.95609666667 minutes
[ 1][ 9] cloud server build [test7972] created in 296.993362 seconds / 4.94988936667 minutes
[ 1][10] cloud server build [test7976] created in 296.810522 seconds / 4.94684203333 minutes
[ 1][11] cloud server build [test8050] created in 226.269396 seconds / 3.7711566 minutes
[ 1][12] cloud server build [test8054] created in 226.051247 seconds / 3.76752078333 minutes
[ 1][14] cloud server build [test8063] created in 225.04139 seconds / 3.75068983333 minutes
[ 1][15] cloud server build [test8068] created in 224.326799 seconds / 3.73877998333 minutes
[ 1][16] cloud server build [test8072] created in 223.051956 seconds / 3.7175326 minutes
[ 1][17] cloud server build [test8077] created in 221.830032 seconds / 3.6971672 minutes
[ 1][18] cloud server build [test8082] created in 219.514883 seconds / 3.65858138333 minutes
[ 1][19] cloud server build [test8086] created in 218.35139 seconds / 3.63918983333 minutes
[ 1][20] cloud server build [test8091] created in 216.172884 seconds / 3.6028814 minutes
[ 1][21] cloud server build [test8117] created in 193.915105 seconds / 3.23191841667 minutes
[ 1][13] cloud server build [test8059] created in 328.421036 seconds / 5.47368393333 minutes
[ 1][22] cloud server build [test8192] created in 197.893329 seconds / 3.29822215 minutes
[ 1][23] cloud server build [test8197] created in 196.71745 seconds / 3.27862416667 minutes
[ 1][24] cloud server build [test8202] created in 263.305984 seconds / 4.38843306667 minutes
[ 1][25] cloud server build [test8208] created in 260.425359 seconds / 4.34042265 minutes

Solution

For a single log file

$ cat log.*.txt | grep "image':" | cut -d':' -f5 | tr '}' ' ' | grep -v created > tmp
echo > 'set -x' >  delete-all-cs.sh
cat tmp | xargs -I cs_name echo 'cloudservers --username user --apikey key delete cs_name' >> delete-all-cs.sh
bash delete-all-cs.sh

When we have multiple log files

$ cat << END > aux_script.sh
cat $1 | grep "image':" | cut -d':' -f5 | tr '}' ' ' | grep -v created > tmp
cat tmp | xargs -I cs_name echo 'cloudservers --username user --apikey key delete cs_name' >> delete-all-cs.sh
END

$ for i in log.*.txt ; do echo $i; ./aux_script.sh $i;  done
$ bash -x delete-all-cs.sh

Summary and results discussion

The solution with 'xargs' works pretty well for relatively small number of servers to delete. As each cloud server is deleted in a single cloudserver run there is no parallelism involved.

An interesting solution could be built with a help of a parallel tool [3]. It could allow us to execute multiple commands in parallel and achieve a much better timing results. Of course to make it work we would have to take into consideration the API limitations and design some workarounds it.

References
  1. https://github.com/rtomaszewski/cloud-performance
  2. http://www.cyberciti.biz/faq/linux-unix-bsd-xargs-construct- argument-lists-utility/
  3. https://savannah.gnu.org/projects/parallel/

How to avoid Rackspace cloud API limits when creating cloud servers (cloudservers.exceptions.OverLimit)

The Rackspace Cloud API has number of limitations. One of them is how many cloud server you can create in 1 minute. The current limitations [1] looks like:

VerbURIRegExDefault
POST*.*10/min
POST*/servers^/servers50/
When your program [2] tries to create more than 10 cloud servers a minute you are going to run into error and start seeing this cloudservers.exceptions.OverLimit exception.

$ python performance-single-cs.py -v -t 1 -s 13 -u user -k key  run | tee log.$(date +%s).txt

Traceback (most recent call last):
  File "performance-single-cs.py", line 349, in module
    Main().run()
  File "performance-single-cs.py", line 346, in run
    self.test_performance(user,key, sample, cs_count, timeout)
  File "performance-single-cs.py", line 298, in test_performance
    t.test_multi_cs_perf(sample, cs_count, timeout)
  File "performance-single-cs.py", line 250, in test_multi_cs_perf
    cs_records=self.cs_create_all(cs_count, i+1)
  File "performance-single-cs.py", line 225, in cs_create_all
    server=self.cs_create(k, sample_nr)
  File "performance-single-cs.py", line 178, in cs_create
    server=sm.create(name, image, flavor)
  File "/usr/lib/pymodules/python2.7/cloudservers/servers.py", line 172, in create
    return self._create("/servers", body, "server")
  File "/usr/lib/pymodules/python2.7/cloudservers/base.py", line 26, in _create
    resp, body = self.api.client.post(url, body=body)
  File "/usr/lib/pymodules/python2.7/cloudservers/client.py", line 69, in post
    return self._cs_request(url, 'POST', **kwargs)
  File "/usr/lib/pymodules/python2.7/cloudservers/client.py", line 50, in _cs_request
    resp, body = self.request(self.management_url + url, method, **kwargs)
  File "/usr/lib/pymodules/python2.7/cloudservers/client.py", line 37, in request
    raise exceptions.from_response(resp, body)
cloudservers.exceptions.OverLimit: Too many requests... (HTTP 413)

A naive code that was used in the first version of my program was simply trying to sent as many create requests as possible. This of course is not going to work if we increase servers above the allowed limit.


Code demonstration

An exaple of the naive code.

A code that is more inteligent looks like this.



References
  1. http://docs.rackspace.com/servers/api/v1.0/cs-devguide/content/Rate_Limits-d1e1017.html
  2. https://github.com/rtomaszewski/cloud-performance

Saturday, July 28, 2012

My python script buffers the output and it causes delays before the text appiers on the console

Linux bash is exelent tool for every day use. It allows you to combine tools and chain them toggethr to achieve remarkable results. As one of my favorite I use this one when testing:
$ python some_script.py | tee log.$(date +%s).txt 

Problem

The problem is that althoug I get all the output on the console it appers to be bufffered and I can't monitor the logs in live when my script runs. An example code can be seen below.
 
Solution

You have to tell python to stop buffering the data sent the the stream you are using (stdin, stdout, stderr). On on the way I found convenient is by using the command line '-u' options.

References