如何在Pylons应用中连接Cassandra?

10 投票
2 回答
899 浏览
提问于 2025-04-16 03:52

我创建了一个新的Pylons项目,想用Cassandra作为我的数据库服务器。我打算使用Pycassa来支持cassandra 0.7beta。可惜的是,我不知道在哪里建立连接,以便在我的应用程序中使用。

我的目标是:

  • 在应用程序启动时创建一个连接池
  • 每次请求时从连接池中获取一个连接,并让它在我的控制器和库中可用(在请求的上下文中)。最好是“懒惰地”获取连接,也就是说,只有在需要的时候才获取
  • 如果一个连接被使用过,在请求处理完后释放它

另外,有什么重要的事情我需要知道吗?当我看到一些评论说“使用QueuePool时要小心,特别是当use_threadlocal=True并且启用了重试时。可能需要同步,以防止在另一个线程使用时连接发生变化。”这到底是什么意思呢?

谢谢。

--

皮埃尔

2 个回答

1

好的。

我工作了一点,学到了很多,也找到了一个可能的解决办法。

创建连接池

创建连接池的最佳位置似乎是在 app_globals.py 文件中,这个文件基本上是一个容器,可以在“应用程序的整个生命周期”中访问的对象。实际上,这正是我想要的连接池。

我在文件末尾添加了我的初始化代码,这段代码从 pylons 配置文件中获取设置:

"""Creating an instance of the Pycassa Pool"""
kwargs = {}

# Parsing servers
if 'cassandra.servers' in config['app_conf']:
    servers = config['app_conf']['cassandra.servers'].split(',')
    if len(servers):
        kwargs['server_list'] = servers

# Parsing timeout
if 'cassandra.timeout' in config['app_conf']:
    try:
        kwargs['timeout'] = float(config['app_conf']['cassandra.timeout'])
    except:
        pass

# Finally creating the pool
self.cass_pool = pycassa.QueuePool(keyspace='Keyspace1', **kwargs)

我本可以做得更好,比如把它放到一个函数里,或者支持更多参数(比如连接池大小等等)。我会这么做的。

在每次请求时获取连接

好吧。似乎有一个简单的方法:在 base.py 文件中,添加类似 c.conn = g.cass_pool.get() 的代码,在调用 WSGIController 之前,之后再加上 c.conn.return_to_pool()。这个方法简单且有效。但这样即使控制器不需要,也会从连接池中获取连接。我需要深入研究一下。

创建连接管理器

我有个简单的想法,就是创建一个类,在每次请求时在 base.py 文件中实例化,这个类会在需要时自动从连接池中获取连接(并在之后释放它)。这是一个非常简单的类:

class LocalManager:
    '''Requests a connection from a Pycassa Pool when needed, and releases it at the end of the object's life'''

    def __init__(self, pool):
        '''Class constructor'''
        assert isinstance(pool, Pool)
        self._pool = pool
        self._conn = None

    def get(self):
        '''Grabs a connection from the pool if not already done, and returns it'''
        if self._conn is None:
            self._conn = self._pool.get()
        return self._conn

    def __getattr__(self, key):
        '''It's cooler to write "c.conn" than "c.get()" in the code, isn't it?'''
        if key == 'conn':
            return self.get()
        else:
            return self.__dict__[key]

    def __del__(self):
        '''Releases the connection, if needed'''
        if not self._conn is None:
            self._conn.return_to_pool()

我只需在 base.py 中调用 WSGIController 之前添加 c.cass = CassandraLocalManager(g.cass_pool),之后再加上 del(c.cass),就完成了。

而且它有效:

conn = c.cass.conn
cf = pycassa.ColumnFamily(conn, 'TestCF')
print cf.get('foo')

\o/

我不知道这是否是最好的方法。如果不是,请告诉我 =)

另外,我仍然不太明白 Pycassa 源代码中的“同步”部分。如果在我的情况下需要这个,我该怎么做才能避免问题。

谢谢。

2

好吧,我又多做了一些工作。其实,使用连接管理器可能不是个好主意,因为这应该是模板的上下文。此外,为每个线程打开一个连接其实没什么大不了的。每个请求打开一个连接才会有问题。

最后,我在应用的全局变量里用了pycassa.connect_thread_local(),就这样搞定了。

撰写回答