As defined on Redis website, it is an open source, advanced key-value store. It is often referred to as a data structure server since keys can contain strings, hashes, lists among others. It’s similar to say memcached library in the sense that it ia an in memory key/value pair but persistent on disk.. Redis has gained importance as a NoSQL option for web development because of its speed (GET and SET operations in the range of 100,000 per seconds). This post is about including Redis in Tornado for web development.
Let’s start with installing Redis-server
ubuntu@ubuntu:~/tornado-2.2$ sudo apt-get install redis-server Reading package lists... Done Building dependency tree Reading state information... Done The following packages were automatically installed and are no longer required: libtext-glob-perl libcompress-bzip2-perl libparams-util-perl libfile-chmod-perl libdata-compare-perl libfile-pushd-perl libfile-which-perl libcpan-inject-perl libfile-find-rule-perl libcpan-checksums-perl libnumber-compare-perl Use 'apt-get autoremove' to remove them. The following NEW packages will be installed: redis-server 0 upgraded, 1 newly installed, 0 to remove and 171 not upgraded. Need to get 80.8kB of archives. After this operation, 283kB of additional disk space will be used. Get:1 http://us.archive.ubuntu.com/ubuntu/ lucid/universe redis-server 2:1.2.0-1 [80.8kB] Fetched 80.8kB in 2s (27.3kB/s) Selecting previously deselected package redis-server. (Reading database ... 138423 files and directories currently installed.) Unpacking redis-server (from .../redis-server_2%3a1.2.0-1_i386.deb) ... Processing triggers for man-db ... Processing triggers for ureadahead ... Setting up redis-server (2:1.2.0-1) ... Starting redis-server: redis-server.
Confirmation
ubuntu@ubuntu:~/tornado-2.2$ ps aux | grep redis redis 19104 0.0 0.1 2284 716 ? Ss 21:23 0:00 /usr/bin/redis-server /etc/redis/redis.conf
Python client library for redis
ubuntu@ubuntu:~/tornado-2.2$ sudo pip install redis Downloading/unpacking redis Downloading redis-2.6.2.tar.gz Running setup.py egg_info for package redis Installing collected packages: redis Running setup.py install for redis Successfully installed redis
With redis installed, lets go to an example where Redis meets Tornado. In the example below,
- When the web server is started, redis server is initialized with key-value pairs of username and password (password is md5 hash of username in hex format) for users ‘bob’ and ‘clara’.
- On browsing to http://localhost:8888/login and POSTing the username and password details to Tornado web server, authentication of details happen from redis server.
- Relevant message for successful/unsuccessful attempt is render on user’s browser
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<title> | |
Redis Example | |
</title> | |
<body> | |
<form action="/login" method="post"> | |
Username: <input type="text" name="username"> | |
Password: <input type="text" name="password"> | |
<input type="submit" value="Submit"> | |
</form> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import tornado.web | |
import redis | |
from hashlib import md5 | |
class Login(tornado.web.RequestHandler): | |
def initialize(self): | |
## Initialize redis | |
self.r = redis.Redis("localhost") | |
## Add users | |
self.r.sadd("users", 'bob') | |
self.r.set('bob', md5('bob').hexdigest()) | |
self.r.sadd("users", 'bob') | |
self.r.set('clara', md5('clara').hexdigest()) | |
def get(self): | |
self.render('login.html') | |
def post(self): | |
username = self.get_argument("username") | |
password = self.get_argument("password") | |
if self.r.sismember("users", username): | |
if self.r.get(username) == password: | |
self.write("Login successful!") | |
else: | |
self.write("Login Unsuccesful..") | |
application = tornado.web.Application([ | |
(r"/login", Login)], | |
debug=True) | |
if __name__ == '__main__': | |
application.listen(8888) | |
tornado.ioloop.IOLoop.instance().start() |