3

我有 2 台运行 PHP 和 Nginx 的 Web 服务器……而且我有 1 台 Redis 服务器。我希望 Web 服务器将 Redis 数据库用于用户登录数据。这将允许我扩展 Web 服务器,而无需强制登录用户在他们访问新服务器时重新进行身份验证。

两台 PHP/Nginx 服务器都使用 Redis 进行会话处理,并且它们都指向同一个 Redis 数据库。当我在浏览器中访问任一站点时,它会生成一个会话令牌并将其存储在 Redis 中(总共创建两个 Redis 密钥)......但是我想要的是在访问站点 #1 时创建一个新会话,将会话存储在Redis,并在我访问时让站点 #2 认出我,因为它查询 Redis(因此总共只有一个 Redis 密钥)。

我的所有 3 台服务器都在 AWS 中,在同一个 VPC 中。我使用内部 IP 地址与 Web 服务器和 Redis 进行通信(因此对机器有一定程度的信任)。

我显然在这里遗漏了一些东西,它可能是负载均衡器(我将实现)。但我试图用最少的组件开发一个 Redis 共享设计。此外,我不完全确定负载平衡器有助于解决这个问题。

以下是代码的相关部分:

PHP/Nginx 服务器:(x2)

(1) /etc/php/7.2/fpm/php.ini

session.save_handler = redis
session.save_path = "tcp://10.xxx.xx.xxx:6379" // both web servers point to the same Redis IP address

(2) /var/www/html/test.php

<?php 

ini_set('session.save_handler', 'redis'); // redundant; including for completeness
ini_set('session.save_path', 'tcp://10.xxx.xx.xxx:6379'); // redundant; including for completeness

session_name('FOOBAR');
session_start();
echo nl2br(
    '<pre>' . session_save_path() . '</pre>' . PHP_EOL
);

echo nl2br(
    'Running PHP version: ' . phpversion() . PHP_EOL
);

if (!array_key_exists('visit', $_SESSION)) {
    $_SESSION['visit'] = 0;
}
$_SESSION['visit']++;

echo nl2br(
    'You have been here ' . $_SESSION['visit'] . ' times.'
);

Redis 服务器:(x1)

(3) /etc/redis/redis.conf

bind 0.0.0.0

当我点击这两个站点的test.php页面时,它们成功地生成了自己的会话并将其存储在 Redis 数据库中。而且他们正确地增加了他们各自的会话令牌......但我希望这些网络服务器与他们共享 Redis 会话数据,所以他们“记住”所有登录的用户(即使这是用户第一次访问给定的网络服务器)。

谢谢!


编辑:我还尝试手动查询 Redis 以获取登录用户数据。这产生了与上面的test.php相似的结果。每个网站最终都创建和管理了自己的会话令牌。

PHP/Nginx 服务器:(x2)

(4) /var/www/html/redis-check.php

<?php

   $cookie = "PHPREDIS_SESSION:" . $_COOKIE['FOOBAR'];

   // Connecting to Redis server on localhost 
   $redis = new Redis(); 
   $redis->connect('10.xxx.xx.xxx', 6379); 
   echo "Connection to server sucessfully";
   echo '<br />';

   // Check if cookie value exists in Redis 
   $seenuser = $redis->get($cookie);

   if( !empty($seenuser) )
   {
      echo 'Hello, old friend!<br />';
      echo '<br />';
      echo 'Cookie Value: ' . $cookie;
      echo '<br />';
      echo 'Session Value: ' . $seenuser;
   }
   else
   {
      // This is a new user, so create a new session
      ini_set('session.save_handler', 'redis'); // redundant; including for completeness
      ini_set('session.save_path', 'tcp://10.xxx.xx.xxx:6379'); // redundant; including for completeness
      session_name('FOOBAR');
      session_start();

      if (!array_key_exists('visit', $_SESSION))
      {
          $_SESSION['visit'] = 0;
      }
      $_SESSION['visit']++;

      $cookie = "PHPREDIS_SESSION:" . $_COOKIE['FOOBAR'];
      $seenuser = $redis->get($cookie);

      echo 'New Login<br />';
      echo '<br />';
      echo 'Cookie Value: ' . $cookie;
      echo '<br />';
      echo 'Session Value: ' . $seenuser;
   }
4

1 回答 1

1

看起来我的问题是由于缺少负载平衡器。我将 HAProxy 放在我的两台 Web 服务器前面,在浏览器中指向 HAProxy 的地址,Web 服务器立即开始共享存储在 Redis 中的会话数据。我猜他们都在使用 HAProxy 地址。而我的浏览器(Chrome)只显示 HAProxy 地址的一个 cookie(这是我想要的)......当我绕过 HAProxy 并直接在浏览器中指向 Web 服务器时,它们会生成自己的会话令牌(这对这种情况)。

所以这里是相关的代码部分 (你可以忽略我的 OP 中的内容):

PHP/Nginx 服务器:(x2)

(1) /etc/php/7.2/fpm/php.ini

session.save_handler = redis
session.save_path = "tcp://10.xxx.xx.xxx:6379" // both web servers point to the same Redis IP address

(2) /var/www/html/test.php

<?php

session_name('FOOBAR');
session_start();

echo 'IP Address: ' . getHostByName(getHostName());
echo '<br />';
echo '*******************************************************************************';
echo '<br />';

if (!array_key_exists('visit', $_SESSION))
{

    $_SESSION['visit'] = 0;

    echo 'Hello, new friend!';
    echo '<br />';
}
else
{

    echo 'Glad you are still with us!!';
    echo '<br />';
}

$_SESSION['visit']++;

echo 'You have been here ' . $_SESSION['visit'] . ' times.';

Redis 服务器:(x1)

(3) /etc/redis/redis.conf

bind 0.0.0.0

高可用性服务器:(x1)

(4) /etc/haproxy/haproxy.cfg

frontend proxy_in
    bind *:80
    default_backend web_farm

backend web_farm
    balance roundrobin
    mode http
    server web1 10.xxx.xx.111:80 check  # web server 1
    server web2 10.xxx.xx.222:80 check  # web server 2

PHP/Nginx 服务器:(x2)

/var/www/html/redis-check.php

Ignore this file. The revised test.php file is all that is needed.

奈杰尔和萨德,谢谢你的链接!在问题上获得不同的观点总是好的。

于 2019-03-30T06:24:57.623 回答