Heim  >  Artikel  >  Backend-Entwicklung  >  Rb (Redis Blaster), eine Python-Bibliothek, die nicht repliziertes Sharding für Redis implementiert

Rb (Redis Blaster), eine Python-Bibliothek, die nicht repliziertes Sharding für Redis implementiert

WBOY
WBOYnach vorne
2023-04-11 19:27:271701Durchsuche

Rb, Redis Blaster, ist eine Bibliothek, die nicht repliziertes Sharding für Redis implementiert. Es implementiert ein benutzerdefiniertes Routing-System auf Basis von Python Redis, sodass Sie automatisch verschiedene Server ansprechen können, ohne Anforderungen manuell an einzelne Knoten weiterleiten zu müssen.

Es implementiert nicht alle Funktionen von Redis und versucht dies auch nicht. Sie können einen Client jederzeit mit einem bestimmten Host verbinden, die meisten gehen jedoch davon aus, dass Ihre Vorgänge auf grundlegende Schlüssel-/Wert-Vorgänge beschränkt sind, die automatisch an verschiedene Knoten weitergeleitet werden können.

Was Sie tun können:

  • Einzeltastenoperationen auf dem Host automatisch ausführen.
  • Befehle ausführen auf allen oder einigen Knoten.
  • Führen Sie das alles parallel aus.

Installation

rb ist auf PyPI verfügbar und kann von dort aus installiert werden:

$ pip install rb

Konfiguration

Der Einstieg in rb ist sehr einfach. Wenn Sie py-redis schon einmal verwendet haben, werden Sie sich sofort wie zu Hause fühlen. Der Hauptunterschied besteht darin, dass der Cluster nicht mit einem einzelnen Host verbunden ist, sondern so konfiguriert ist, dass er eine Verbindung mit mehreren herstellt:

rom rb import Cluster

cluster = Cluster(hosts={
0: {'port': 6379},
1: {'port': 6380},
2: {'port': 6381},
3: {'port': 6382},
4: {'port': 6379},
5: {'port': 6380},
6: {'port': 6381},
7: {'port': 6382},
}, host_defaults={
'host': '127.0.0.1',
})

In diesem Fall haben wir 8 Knoten auf vier verschiedenen Serverprozessen auf demselben Host eingerichtet. Der Parameter „hosts“ ist eine Zuordnung der Hosts, zu denen eine Verbindung hergestellt werden soll. Der Schlüssel des Wörterbuchs ist die Host-ID (Ganzzahl) und der Wert ist das Parameterwörterbuch. host_defaults ist ein Wörterbuch optionaler Standardeinstellungen, die für alle Hosts ausgefüllt werden. Dies ist nützlich, wenn Sie einige gemeinsame Standardeinstellungen teilen möchten, die wiederholt werden (in diesem Fall stellen alle Hosts eine Verbindung zu localhost her).

In der Standardkonfiguration wird PartitionRouter für das Routing verwendet.

Routing

Da der Cluster nun erstellt ist, können wir Cluster.get_routing_client() verwenden, um einen Redis-Client zu erhalten, der jeden Befehl automatisch an den richtigen Redis-Knoten weiterleitet:

client = cluster.get_routing_client()
results = {}
for key in keys_to_look_up:
results[key] = client.get(key)

Der Client funktioniert genauso wie der standardmäßige Pyredis StrictClient ist sehr ähnlich, der Hauptunterschied besteht darin, dass es nur Befehle ausführen kann, die nur eine Taste erfordern.

Dieser grundlegende Vorgang wird jedoch seriell ausgeführt. Was rb so nützlich macht, ist, dass es automatisch Redis-Pipelines erstellen und Anfragen parallel an viele Hosts senden kann. Dadurch ändert sich jedoch die Verwendung geringfügig, da der Wert jetzt nicht sofort verfügbar ist:

results = {}
with cluster.map() as client:
for key in keys_to_look_up:
results[key] = client.get(key)

Während es bisher ähnlich aussieht, wird anstelle des eigentlichen Werts im Ergebniswörterbuch ein Promise-Objekt gespeichert. Wenn der Kartenkontext-Manager endet, werden sie garantiert ausgeführt. Sie können auf die Promise.value-Eigenschaft zugreifen, um den Wert abzurufen:

for key, promise in results.iteritems():
print '%s: %s' % (key, promise.value)

Wenn Sie einen Befehl an alle teilnehmenden Hosts senden möchten (z. B. eine Datenbank löschen), müssen Sie Sie können die Methode Cluster.all() verwenden:

with cluster.all() as client:
client.flushdb()

Wenn Sie dies tun, ist der Versprechenswert ein Wörterbuch mit der Host-ID als Schlüssel und dem Ergebnis als Wert. Zum Beispiel:

with cluster.all() as client:
results = client.info()
for host_id, info in results.iteritems():
print 'host %s is running %s' % (host_id, info['os'])

Um bestimmte Hosts explizit anzusprechen, können Sie Cluster.fanout() verwenden, um eine Liste von Host-IDs zu akzeptieren, an die der Befehl gesendet werden soll.

API

Dies ist eine vollständige Referenz der öffentlichen API. Beachten Sie, dass diese Bibliothek die Python-Redis-Bibliothek erweitert, sodass einige der Klassen über mehr Funktionalität verfügen. Sie müssen sich die py-redis-Bibliothek ansehen.

Cluster

class rb.Cluster(hosts, host_defaults=None, pool_cls=None, pool_options=None, router_cls=None, router_options=None)

cluster ist das Kernobjekt hinter rb. Es wird im Verbindungspool des einzelnen Knotens gespeichert und kann an einem zentralen Ort geteilt werden, während die Anwendung ausgeführt wird.

Grundlegendes Beispiel eines Clusters auf vier Redis-Instanzen mit Standardrouter:

cluster = Cluster(hosts={
0: {'port': 6379},
1: {'port': 6380},
2: {'port': 6381},
3: {'port': 6382},
}, host_defaults={
'host': '127.0.0.1',
})

hosts ist ein Host-Wörterbuch, das Host-ID-Nummern Konfigurationsparametern zuordnet. Die Parameter entsprechen der Signatur der Funktion add_host(). Die Standardwerte für diese Parameter werden von host_defaults übernommen. Um die Poolklasse zu überschreiben, verwenden Sie die Parameter pool_cls und pool_options. Das Gleiche gilt für router_cls und router_options des Routers. Die Pool-Option ist nützlich zum Festlegen von Socket-Timeouts und ähnlichen Parametern.

  • add_host(host_id=None, host='localhost', port=6379, unix_socket_path=None, db=0, password=None, ssl=False, ssl_options=None)

Fügen Sie dem Cluster einen neuen Host hinzu. Dies ist nur für Unit-Tests wirklich nützlich, da Hosts normalerweise über den Konstruktor hinzugefügt werden und es unwahrscheinlich ist, dass Änderungen nach der ersten Verwendung des Clusters sinnvoll sind.

  • all(timeout=None, max_concurrency=64, auto_batch=True)

Fanout an alle Hosts. Ansonsten identisch mit fanout().

Beispiel:

with cluster.all() as client:
client.flushdb()
  • disconnect_pools()

Trennen Sie alle Verbindungen zu internen Pools.

  • execute_commands(mapping, *args, **kwargs)

Führt gleichzeitig eine Reihe von Befehlen aus, die mit dem Routing-Schlüssel im Redis-Cluster verknüpft sind, und gibt eine neue Zuordnung zurück, wobei der Wert eine Liste von Ergebnissen ist, die dem Befehl unter entsprechen der gleiche Standort. Zum Beispiel:

>>> cluster.execute_commands({
... 'foo': [
... ('PING',),
... ('TIME',),
... ],
... 'bar': [
... ('CLIENT', 'GETNAME'),
... ],
... })
{'bar': [<Promise None>],
 'foo': [<Promise True>, <Promise (1454446079, 418404)>]}
  • Befehle, die Instanzen von redis.client.Script sind, prüfen zunächst ihre Existenz auf dem Zielknoten und werden dann vor der Ausführung auf das Ziel geladen und können mit anderen Befehlen verschachtelt werden:
>>> from redis.client import Script
>>> TestScript = Script(None, 'return {KEYS, ARGV}')
>>> cluster.execute_commands({
... 'foo': [
... (TestScript, ('key:1', 'key:2'), range(0, 3)),
... ],
... 'bar': [
... (TestScript, ('key:3', 'key:4'), range(3, 6)),
... ],
... })
{'bar': [<Promise [['key:3', 'key:4'], ['3', '4', '5']]>],
 'foo': [<Promise [['key:1', 'key:2'], ['0', '1', '2']]>]}

Intern , FanoutClient Wird zum Ausgeben von Befehlen verwendet.

  • fanout(hosts=None, timeout=None, max_concurrency=64, auto_batch=True)

用于获取路由客户端、开始扇出操作并 join 结果的快捷上下文管理器。

在上下文管理器中,可用的客户端是 FanoutClient。示例用法:

with cluster.fanout(hosts='all') as client: client.flushdb()
get_local_client(host_id)
  • get_local_client(host_id)

返回特定主机 ID 的本地化 client。这个 client 就像一个普通的 Python redis 客户端一样工作,并立即返回结果。

  • get_local_client_for_key(key)

类似于 get_local_client_for_key() 但根据 router 所说的 key 目的地返回 client。

  • get_pool_for_host(host_id)

返回给定主机的连接池。

redis 客户端使用此连接池来确保它不必不断地重新连接。如果要使用自定义 redis 客户端,可以手动将其作为连接池传入。

  • get_router()

返回 cluster 的 router 。如果 cluster 重新配置,router 将被重新创建。通常,您不需要自己与 router 交互,因为集群的路由客户端会自动执行此操作。

这将返回 BaseRouter 的一个实例。

  • get_routing_client(auto_batch=True)

返回一个路由客户端。该客户端能够自动将请求路由到各个主机。它是线程安全的,可以类似于主机本地客户端使用,但它会拒绝执行无法直接路由到单个节点的命令。

路由客户端的默认行为是尝试将符合条件的命令批处理成批处理版本。例如,路由到同一节点的多个 GET 命令最终可以合并为一个 MGET 命令。可以通过将 auto_batch 设置为 False 来禁用此行为。这对于调试很有用,因为 MONITOR 将更准确地反映代码中发出的命令。

有关详细信息,请参阅 RoutingClient。

  • map(timeout=None, max_concurrency=64, auto_batch=True)

用于获取路由客户端、开始映射操作并 join 结果的快捷上下文管理器。max_concurrency 定义在隐式连接发生之前可以存在多少未完成的并行查询。

在上下文管理器中,可用的客户端是 MappingClient。示例用法:

results = {}
with cluster.map() as client:
for key in keys_to_fetch:
results[key] = client.get(key)
for key, promise in results.iteritems():
print '%s => %s' % (key, promise.value)
  • remove_host(host_id)

从 client 中删除 host。这仅对单元测试真正有用。

Clients

class rb.RoutingClient(cluster, auto_batch=True)

可以路由到单个目标的客户端。

有关参数,请参见 Cluster.get_routing_client()。

  • execute_command(*args, **options)

执行命令并返回解析后的响应

  • fanout(hosts=None, timeout=None, max_concurrency=64, auto_batch=None)

返回映射操作的 context manager,该操作扇出到手动指定的主机,而不是使用路由系统。例如,这可用于清空所有主机上的数据库。context manager 返回一个 FanoutClient。示例用法:

with cluster.fanout(hosts=[0, 1, 2, 3]) as client:
results = client.info()
for host_id, info in results.value.iteritems():
print '%s -> %s' % (host_id, info['is'])

返回的 promise 将所有结果累积到由 host_id 键入的字典中。

hosts 参数是一个 host_id 列表,或者是字符串 'all' ,用于将命令发送到所有主机。

fanout API 需要非常小心地使用,因为当 key 被写入不期望它们的主机时,它可能会造成很多损坏。

  • get_fanout_client(hosts, max_concurrency=64, auto_batch=None)

返回线程不安全的扇出客户端。

返回 FanoutClient 的实例。

  • get_mapping_client(max_concurrency=64, auto_batch=None)

返回一个线程不安全的映射客户端。此客户端的工作方式类似于 redis 管道并返回最终结果对象。它需要 join 才能正常工作。您应该使用自动 join 的 map() 上下文管理器,而不是直接使用它。

返回 MappingClient 的一个实例。

  • map(timeout=None, max_concurrency=64, auto_batch=None)

返回映射操作的 context manager。这会并行运行多个查询,然后最后 join 以收集所有结果。

在上下文管理器中,可用的客户端是 MappingClient。示例用法:

results = {}
with cluster.map() as client:
for key in keys_to_fetch:
results[key] = client.get(key)
for key, promise in results.iteritems():
print '%s => %s' % (key, promise.value)

class rb.MappingClient(connection_pool, max_concurrency=None, auto_batch=True)

路由客户端使用 cluster 的 router 根据执行的 redis 命令的 key 自动定位单个节点。

Parameter finden Sie unter Cluster.map().

  • cancel()

Alle ausstehenden Anfragen stornieren.

  • execute_command(*args, **options)

Führen Sie den Befehl aus und geben Sie die analysierte Antwort zurück

    # 🎜🎜#join(timeout=None)
Warten, bis alle ausstehenden Antworten zurückkommen oder eine Zeitüberschreitung auftritt

    mget(keys, *args)# 🎜🎜#
  • Gibt eine Liste von Werten in derselben Reihenfolge wie der Schlüssel zurück

mset(*args, **kwargs)
  • #🎜 🎜#Schlüssel/Wert entsprechend der Zuordnung festlegen. Eine Karte ist ein Wörterbuch von Schlüssel/Wert-Paaren. Sowohl Schlüssel als auch Wert sollten Zeichenfolgen oder Typen sein, die über str() in Zeichenfolgen konvertiert werden können.
class rb.FanoutClient(hosts, Connection_pool, max_concurrency=None, auto_batch=True)

Dies funktioniert ähnlich wie MappingClient, aber anstatt einen Router zum Auffinden des Hosts zu verwenden, Stattdessen wird der Befehl an alle manuell angegebenen Hosts gesendet.

Die Ergebnisse werden im Wörterbuch mit dem Schlüssel host_id akkumuliert.

Parameter finden Sie unter Cluster.fanout().

execute_command(*args, **options)

  • Führen Sie den Befehl aus und geben Sie die analysierte Antwort zurück
# 🎜🎜#target(hosts)

    Den Client für einen Anruf vorübergehend verlegen. Dies ist nützlich, wenn eine Teilmenge von Hosts für einen einzelnen Aufruf verarbeitet werden muss.
target_key(key)

    Verschieben Sie den Client vorübergehend, um einen Anruf zu tätigen, um ihn gezielt an den Host weiterzuleiten, an den der angegebene Schlüssel weitergeleitet wird . In diesem Fall ist das Ergebnis des Versprechens lediglich ein Hostwert und kein Wörterbuch.
  • Neue Funktionen in Version 1.3.

Promise

class rb.Promise

Ein Promise-Objekt, das versucht, die ES6-API für Promise-Objekte zu spiegeln. Im Gegensatz zum Promise von ES6 bietet dieses Promise auch direkten Zugriff auf den zugrunde liegenden Wert und hat leicht unterschiedliche statische Methodennamen, da dieses Promise extern aufgelöst werden kann.

static all(iterable_or_dict)

    Ein Versprechen ist gelöst, wenn alle bestandenen Versprechen gelöst wurden. Sie können eine Liste mit Versprechen oder ein Wörterbuch mit Versprechen übergeben.
done(on_success=None, on_failure=None)

    Fügen Sie einige Rückrufe an das Versprechen an und geben Sie das Versprechen zurück.
is_pending

    True, wenn das Versprechen noch aussteht, andernfalls False.
is_rejected

    True, wenn das Versprechen abgelehnt wurde, andernfalls False.
is_resolved

    True, wenn das Versprechen gelöst wurde, andernfalls False.
Grund

    Der Grund für dieses Versprechen, wenn es abgelehnt wird.
ablehnen (Grund)

    Ein Versprechen mit dem angegebenen Grund ablehnen.
statisch abgelehnt (Grund)

    Erstellen Sie ein Versprechenobjekt, das mit einem bestimmten Wert abgelehnt wird.
resolve(value)

    Lösen Sie das Versprechen mit dem angegebenen Wert auf.
statisch aufgelöst(Wert)

    Erstellt ein Versprechensobjekt, das mit einem bestimmten Wert aufgelöst wird.
then(success=None, failed=None)

    Eine praktische Methode zum Hinzufügen von Erfolgs- und/oder Misserfolgsrückrufen zu einem Versprechen, das Außerdem wird während dieses Vorgangs ein weiteres Versprechen zurückgegeben.
value

    Der Wert, den dieses Versprechen hat, wenn es eingelöst wird.
  • Routers

class rb.BaseRouter(cluster)

Die Basisklasse für alle Routen. Wenn Sie eine benutzerdefinierte Route implementieren möchten, ist dies Ihre Unterklasse.

cluster

    verweist zurück auf den Cluster, zu dem dieser Router gehört.
get_host_for_command(command, args)

    Gibt den Host zurück, auf dem dieser Befehl ausgeführt werden soll.
get_host_for_key(key)

    Routing ausführen und die host_id des Ziels zurückgeben.
  • Unterklassen müssen dies implementieren.

get_key(command, args)

    Gibt den Schlüssel der Befehlsoperation zurück.
  • class rb.ConsistentHashingRouter(cluster)

Gibt den Router von host_id basierend auf dem konsistenten Hashing-Algorithmus zurück. Konsistente Hashing-Algorithmen funktionieren nur, wenn der Schlüsselparameter angegeben wird.

Der Router erfordert, dass die Hosts lückenlos sind, was bedeutet, dass die IDs von N Hosts von 0 bis N-1 reichen.

get_host_for_key(key)

    Routing ausführen und die host_id des Ziels zurückgeben.
  • Unterklassen müssen dies implementieren.

class rb.PartitionRouter(cluster)

Ein einfacher Router, der Befehle individuell an einen einzelnen Knoten weiterleitet, basierend nur auf einer einfachen crc32 % node_count-Einstellung.

Der Router erfordert, dass die Hosts lückenlos sind, was bedeutet, dass die IDs von N Hosts von 0 bis N-1 reichen.

  • get_host_for_key(key)

执行路由并返回目标的 host_id。

子类需要实现这一点。

exception rb.UnroutableCommand

如果发出的命令无法通过 router 路由到单个主机,则引发。

Testing

class rb.testing.TestSetup(servers=4, databases_each=8, server_executable='redis-server')

测试设置是生成多个 redis 服务器进行测试并自动关闭它们的便捷方式。这可以用作 context manager 来自动终止客户端。

  • rb.testing.make_test_cluster(*args, **kwargs)

用于创建测试设置然后从中创建 cluster 的便捷快捷方式。这必须用作 context manager:

from rb.testing import make_test_cluster
with make_test_cluster() as cluster:
...

Das obige ist der detaillierte Inhalt vonRb (Redis Blaster), eine Python-Bibliothek, die nicht repliziertes Sharding für Redis implementiert. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:51cto.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen