laravel memcached 具体连接的哪个服务器

配置多个服务器,在 Illuminate\Cache\MemcachedConnector 使用addServer 添加进 memcached 具体见文档

cat config/cache.php

'memcached' => [
            'driver' => 'memcached',
            'servers' =>
           [
                [
                    'host' => '127.0.0.1', 'port' => 11211, 'weight' => 80
                ],
                 [
                    'host' => '127.0.0.1', 'port' => 11212, 'weight' => 20
                ],
            ],

https://laravel-china.org/top...

public function connect(array $servers)
{
    $memcached = $this->getMemcached();
    // For each server in the array, we'll just extract the configuration and add
    // the server to the Memcached connection. Once we have added all of these
    // servers we'll verify the connection is successful and return it back.
    foreach ($servers as $server) {
        $memcached->addServer(
            $server['host'], $server['port'], $server['weight']
        );
    }
    $memcachedStatus = $memcached->getVersion();
    //Where a connection has failed to a server the version is returned as '255.255.255'.
    array:2 [▼
  "xxx:11211" => "1.5.5"
  "xxx:11222" => "1.5.5"
]
    if (! is_array($memcachedStatus)) {
        throw new RuntimeException('No Memcached servers added.');
    }
    if (in_array('255.255.255', $memcachedStatus) && count(array_unique($memcachedStatus)) === 1) {
        throw new RuntimeException('Could not establish Memcached connection.');
    }
    return $memcached;
}

cat Illuminate\Cache\Repository.php

public function get($key, $default = null)
    {
    //$this->store 来自Illuminate\Cache\MemcachedStore 
  dump($this->store->getmemcached()->getstats());//返回config/cache.php memcached servers数组服务器信息  
        $value = $this->store->get($key);

        if (is_null($value))
        {
            $this->fireCacheEvent('missed', [$key]);

            $value = value($default);
        }
        else
        {
            $this->fireCacheEvent('hit', [$key, $value]);
        }

        return $value;
    }

cat bootstarp/app.php
$app['events']->listen('cache.write',function($key, $value, $time) use ($app){
    dump(app('cache')->store(),app('cache.store')->getStore()->getMemcached()->getstats());
});

测试

echo \Cache::get('test');// 调用函数里 $this->store->getmemcached()->getstats() 输出的还是2个服务器信息 ["127.0.0.1:11221" => [],"127.0.0.1:11222" => [],],怎么知道获取 test 缓存的时候具体连接的哪个服务器呢?

阅读 3.2k
2 个回答

laravel使用的memcached客户端是 php-memcached 该客户端是C实现,底层封装了 libmemcached

我们可以直接看下 C 源码是怎么获取一个服务器上的值的,经查找,在文件libmemcached/get.c中get源码实现如下:

    //声明一个服务器实例的变量
    memcached_server_write_instance_st instance;
    uint32_t server_key;
    //如果指定了服务器,则直接使用指定的服务器,memcached的客户端是可以直接指定从哪台服务器上读值的。
    if (is_master_key_set)
    {
      server_key= master_server_key;
    }
    else
    {
      //如果没有指定,则通过key计算hash值,并使用该hash值获取指定的服务器实例
      server_key= memcached_generate_hash_with_redistribution(ptr, keys[x], key_length[x]);
    }
    //得到一个服务器的实例,下面会使用这个实例来读取服务器上的数据
    instance= memcached_server_instance_fetch(ptr, server_key);

如果你调用的方法没有指定服务器,会通过 memcached_generate_hash_with_redistribution 方法计算key的hash值,然后调用 memcached_server_instance_fetch 方法获取memcached实例,并执行命令。

而如果使用的是set方法,源文件libmemcached/storage.c中实现如下:

  //这里直接计算key的hash值
  server_key= memcached_generate_hash_with_redistribution(ptr, master_key, master_key_length);
  instance= memcached_server_instance_fetch(ptr, server_key);

  WATCHPOINT_SET(instance->io_wait_count.read= 0);
  WATCHPOINT_SET(instance->io_wait_count.write= 0);

  if (ptr->flags.binary_protocol)
  {
    rc= memcached_send_binary(ptr, instance, server_key,
                              key, key_length,
                              value, value_length, expiration,
                              flags, cas, verb);
    WATCHPOINT_IF_LABELED_NUMBER(instance->io_wait_count.read > 2, "read IO_WAIT", instance->io_wait_count.read);
    WATCHPOINT_IF_LABELED_NUMBER(instance->io_wait_count.write > 2, "write_IO_WAIT", instance->io_wait_count.write);
  }
  else
  {
...

通过以上的源码发现,参数 weight 方法貌似没用。源码中该方法也仅仅是赋值给了 memcached 的实例,源文件 libmemcached/server.c中的实现:

static inline void _server_init(memcached_server_st *self, const memcached_st *root,
                                const char *hostname, in_port_t port,
                                uint32_t weight, memcached_connection_t type)
{
  self->options.sockaddr_inited= false;
  self->options.is_shutting_down= false;
  self->number_of_hosts= 0;
  self->cursor_active= 0;
  self->port= port;
  self->cached_errno= 0;
  self->fd= -1;
  self->io_bytes_sent= 0;
  self->server_failure_counter= 0;
//这里赋值给了weight属性
  self->weight= weight;
  self->state.is_corked= false;
  self->state.is_dead= false;
  WATCHPOINT_SET(self->io_wait_count.read= 0);
  WATCHPOINT_SET(self->io_wait_count.write= 0);
  self->major_version= UINT8_MAX;
  self->micro_version= UINT8_MAX;
  self->minor_version= UINT8_MAX;
  self->type= type;
  self->read_ptr= self->read_buffer;
  self->cached_server_error= NULL;
  self->read_buffer_length= 0;
  self->read_data_length= 0;
  self->write_buffer_offset= 0;
  self->address_info= NULL;

并没有找到具体在哪使用的,计算hash的方法注释掉的有一段如下:

  if (hashkit->active_fn != NULL || hashkit->weight_fn != NULL)
  {
    live_servers= 0;

    for (count= 0, context= hashkit->list; count < hashkit->list_size;
         count++, context+= hashkit->context_size)
    {
      if (hashkit->active_fn != NULL)
      {
        if (hashkit->active_fn(context))
          live_servers++;
        else
          continue;
      }

      if (hashkit->weight_fn != NULL)
        total_weight+= hashkit->weight_fn(context);
    }
  }

貌似有用到 weight 的值,但是但是源码确实加了#if 0的判断。

如果客户端不提供,那么没办法知道。memcached把key经过hash以后,结合weight等参数来选择实例,而且不同的客户端的hash函数还可能不一样。不知道你为什么需要知道具体来自哪个实例

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题