翻译进度
6
分块数量
3
参与人数

连接池

这是一篇协同翻译的文章,你可以点击『我来翻译』按钮来参与翻译。

连接池

连接池是客户端内置的一个对象,主要维持当前的节点列表。从理论上来说,节点只有死节点和活节点。

然而,在现实世界,事情绝不会这么清晰。有时候节点可能处在 「 可能挂了但是没有确定 」, 「 超时但是为知原因 」 或者 「 最近挂了但是现在好了 」的灰色地带。连接池的工作是管理一系列不稳定的连接并尝试给客户端提供最稳定的连接。

如果连接池找不到一个活节点来发送查询,将会返回一个 NoNodesAvailableException 异常。这与最大重试次数有所不同。例如,你的集群有 10 个节点,你发送一个请求,其中 9 个请求因为连接超时而请求失败。而第十个请求发送成功并且成功执行请求。则前九个请求会被标记为死节点(连接池处于使用状态才会被标记),并且这些节点的「 死亡 」定时器将会被触发。

当发送下一个请求给客户端时,这九个节点任然会被认为是 「 死节点 」 ,所以请求会跳过这些节点。请求只会发送到唯一的活节点(#10)中,假如发送到这个节点也失败了,那么就会返回 NoNodesAvailableException 。你会发现这里的发送次数比 retries 的值少,因为 retries 的值只适用于活节点。在这种情况下,只有一个节点是活节点,请求失败后就会返回 NoNodesAvailableException

这有几种连接池的实现可供选择:

benettzhang 翻译于 2天前

staticNoPingConnectionPool (默认)

连接池维持一个静态的 host 列表,这些 host 会在客户端初始化时被假定为活节点。如果一个节点处理请求失败,这个节点会被标记位 dead 节点并维持 60 秒,而请求将会重试下一个节点。60 秒后,这个节点会被重新激活并且会加入请求轮询中。每增加一次请求失败次数都会导致死亡时间以指数级别增长。

一个成功的请求将会重置 failed ping timeout 计数器。

如果你想明确地设置连接池为 StaticNoPingConnectionPool ,你可以调用 ClientBuilder 对象的 setConnectionPool() 方法:

$client = ClientBuilder::create()
            ->setConnectionPool('\Elasticsearch\ConnectionPool\StaticNoPingConnectionPool', [])
            ->build();

注意:要通过命名空间加类名的方法来指定连接池。

benettzhang 翻译于 17小时前

staticConnectionPool

除了要在使用前 ping 节点是否为活节点,其他的特性与 StaticNoPingConnectionPool 相同。这对长时间执行的脚本有用,但是这将会添加额外的开销,因为这对 PHP 不是必须的。

使用 StaticConnectionPool:

$client = ClientBuilder::create()
            ->setConnectionPool('\Elasticsearch\ConnectionPool\StaticConnectionPool', [])
            ->build();

注意:要通过命名空间加载类名的方法来指定连接池。

simpleConnectionPool

SimpleConnectionPool 仅仅会返回选择器指定的下一个节点信息,它不会追踪节点的 「生死状态」。不管节点是活节点还是死节点,这个连接池都将会返回其信息。它仅仅是一个简单的静态 host 连接池。

SimpleConnectionPool 不推荐在常规情况下使用,但是它是个有用的调试工具。

使用 SimpleConnectionPool:

$client = ClientBuilder::create()
            ->setConnectionPool('\Elasticsearch\ConnectionPool\SimpleConnectionPool', [])
            ->build();

注意:要通过命名空间加载类名的方法来指定连接池。

benettzhang 翻译于 17小时前

sniffingConnectionPool

不同于之前的两个静态连接池,sniffingConnectionPool 连接池是动态的。 用户提供主机的种子列表,客户端使用该列表进行「嗅探」并发现群集的其余部分,它通过 Cluster State API 实现了这一点。在集群中添加或删除节点时,客户端将更新期活动连接池。

使用 SniffingConnectionPool

$client = ClientBuilder::create()
            ->setConnectionPool('\Elasticsearch\ConnectionPool\SniffingConnectionPool', [])
            ->build();

请注意,类的实现是通过指定命名空间路径来完成的。

自定义连接池

如果您希望实现自己编写的自定义连接池,类必须实现 ConnectionPoolInterface 接口:

class MyCustomConnectionPool implements ConnectionPoolInterface
{

    /**
     * @param bool $force
     *
     * @return ConnectionInterface
     */
    public function nextConnection($force = false)
    {
        // 此处代码
    }

    /**
     * @return void
     */
    public function scheduleCheck()
    {
        // 此处代码
    }
}
Lewis77 翻译于 14小时前

You can then instantiate an instance of your ConnectionPool and inject it into the ClientBuilder:

$myConnectionPool = new MyCustomConnectionPool();

$client = ClientBuilder::create()
            ->setConnectionPool($myConnectionPool, [])
            ->build();

If your connection pool only makes minor changes, you may consider extending AbstractConnectionPool, which provides some helper concrete methods. If you choose to go down this route, you need to make sure your ConnectionPool's implementation has a compatible constructor (since it is not defined in the interface):

class MyCustomConnectionPool extends AbstractConnectionPool implements ConnectionPoolInterface
{

    public function __construct($connections, SelectorInterface $selector, ConnectionFactory $factory, $connectionPoolParams)
    {
        parent::__construct($connections, $selector, $factory, $connectionPoolParams);
    }

    /**
     * @param bool $force
     *
     * @return ConnectionInterface
     */
    public function nextConnection($force = false)
    {
        // code here
    }

    /**
     * @return void
     */
    public function scheduleCheck()
    {
        // code here
    }
}

If your constructor matches AbstractConnectionPool, you may use either object injection or namespace instantiation:

$myConnectionPool = new MyCustomConnectionPool();

$client = ClientBuilder::create()
            ->setConnectionPool($myConnectionPool, [])                                      // object injection
            ->setConnectionPool('/MyProject/ConnectionPools/MyCustomConnectionPool', [])    // or namespace
            ->build();

Which connection pool to choose? PHP and connection pooling

At first glance, the sniffingConnectionPool implementation seems superior. For many languages, it is. In PHP, the conversation is a bit more nuanced.

Because PHP is a share-nothing architecture, there is no way to maintain a connection pool across script instances. This means that every script is responsible for creating, maintaining, and destroying connections everytime the script is re-run.

Sniffing is a relatively lightweight operation (one API call to /_cluster/state, followed by pings to each node) but it may be a non-negligible overhead for certain PHP applications. The average PHP script will likely load the client, execute a few queries and then close. Imagine this script being called 1000 times per second: the sniffing connection pool will perform the sniffing and pinging process 1000 times per second. The sniffing process will add a large amount of overhead

In reality, if your script only executes a few queries, the sniffing concept is too robust. It tends to be more useful in long-lived processes which potentially "out-live" a static list.

For this reason the default connection pool is currently the staticNoPingConnectionPool. You can, of course, change this default - but we strongly recommend you load test and verify that it does not negatively impact your performance.

本文章首发在 Laravel China 社区
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

参与译者:3
讨论数量: 0
发起讨论


暂无话题~