A typical Developer Blog
by Gordon Franke
Icon

Wie kann ich mehrere Instanzen von memcached auf einem Server laufen lassen?

Problem

Ich brauche mehr als einen Memcached Server.

Lösung

Virtuellemaschinen

Ich kann für jeden memcached server eine Virtuellemaschine erstellen.

Probleme

  • mehr speicher (system+memcached)
  • eine ip addresse pro Instanz
  • mehr Aufwand

Multiple Instanzen mithilfe von Ports

Dafür müssen die Skripte init.d und start-memcached gepatched werden um Multiple Instanzen zum laufen zubekommen.

Nach dem patch sucht es nach Konfigurationsdateien die folgendem Muster entsprechen /etc/memcached_*.conf. Wenn es keine Dateien findet benutzt es die /etc/memcached.conf Konfigurationsdatei. Es ist also rückwärtskompatibel.

Wenn du nun 2 memached Instanzen erstellen möchtest kopiere die Konfigurationsdatei und ändere den Port, Speicher …

cp /etc/memcached.conf /etc/memcached_myserver_1.conf
cp /etc/memcached.conf /etc/memcached_myserver_2.conf

Befehle

startet alle Server

/etc/init.d/memcached start

startet nur einen bestimmten Server

/etc/init.d/memcached start myserver_1

stopt alle Server

/etc/init.d/memcached stop

stopt nur einen bestimmten Server

/etc/init.d/memcached stop myserver_1

Die Änderungen

/usr/share/memcached/scripts/start-memcached

26,30d25
> if (scalar(@ARGV) == 2) {
> 	$etcfile = shift(@ARGV);
> 	$pidfile = shift(@ARGV);
> }
>

/etc/init.d/memcached

16a17
> DAEMONNAME=memcached
18d18
< NAME=memcached
20d19
< PIDFILE=/var/run/$NAME.pid
26a26,63
> FILES=(/etc/memcached_*.conf);
> # check for alternative config schema
> if [ -r "${FILES[0]}" ]; then
>   CONFIGS=();
>   for FILE in "${FILES[@]}";
>   do
>     # remove prefix
>     NAME=${FILE#/etc/};
>     # remove suffix
>     NAME=${NAME%.conf};
>
>     # check optional second param
>     if [ $# -ne 2 ];
>     then
>       # add to config array
>       CONFIGS+=($NAME);
>     elif [ "memcached_$2" == "$NAME" ];
>     then
>       # use only one memcached
>       CONFIGS=($NAME);
>       break;
>     fi;
>   done;
>
>   if [ ${#CONFIGS[@]} == 0 ];
>   then
>     echo "Config not exist for: $2" >&2;
>     exit 1;
>   fi;
> else
>   CONFIGS=(memcached);
> fi;
>
> CONFIG_NUM=${#CONFIGS[@]};
> for ((i=0; i < $CONFIG_NUM; i++)); do
>   NAME=${CONFIGS[${i}]};
>   PIDFILE="/var/run/${NAME}.pid";
>
30c67
<       start-stop-daemon --start --quiet --exec $DAEMONBOOTSTRAP
---
>       start-stop-daemon --start --quiet --exec "$DAEMONBOOTSTRAP" -- /etc/${NAME}.conf $PIDFILE
50c87
<       start-stop-daemon --start --quiet --exec $DAEMONBOOTSTRAP
---
>       start-stop-daemon --start --quiet --exec "$DAEMONBOOTSTRAP" -- /etc/${NAME}.conf $PIDFILE
54c91
<       N=/etc/init.d/$NAME
---
>       N=/etc/init.d/$DAEMONNAME
59a97
> done;

Wie kann mir Symfony eine email schicken, wenn ein log Mitteilung erstellt wird?

UPDATE: Ich habe die Klasse aktualisiert und einen neuen Parameter hinzugefügt include_level

Aktiviere das logging für die prod Umgebung in der settings.yml

prod:
  .settings:
    logging_enabled:        on

füge dies zu deiner factories.yml hinzu

prod:
  logger:
    param:
      level: debug
      loggers:
        sf_web_debug:
          class: sfNoLogger
        sf_file_debug:
          param:
            level: warning
        sc_mail:
          class: gfMailLogger
          param:
            level: warning
            include_level: debug
            emails: ["test@test.de"]

erstelle gfMailLogger.class.php in deinem lib Ordner

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
<?php
 
/**
 * gfMailLogger logs messages and send it via email.
 *
 * @package    symfony
 * @subpackage log
 * @author     Gordon Franke <gfranke@nevalon.de>
 * @link       http://www.nevalon.de
 */
class gfMailLogger extends sfLogger
{
  protected
    $emails     = array(),
    $subject,
    $body,
    $include_level,
    $log = false,
    $type       = 'symfony',
    $format     = '%time% %type% [%priority%] %message%%EOL%',
    $timeFormat = '%b %d %H:%M:%S';
 
  /**
   * Initializes this logger.
   *
   * Available options:
   *
   * - emails:        The emails to be send the log messages
   * - subject:       The subject for the email
   * - include_level: Use this to get more detailed information
   * - format:        The log line format (default to %time% %type% [%priority%] %message%%EOL%)
   * - time_format:   The log time strftime format (default to %b %d %H:%M:%S)
   *
   * @param  sfEventDispatcher $dispatcher  A sfEventDispatcher instance
   * @param  array             $options     An array of options.
   *
   * @return Boolean      true, if initialization completes successfully, otherwise false.
   */
  public function initialize(sfEventDispatcher $dispatcher, $options = array())
  {
    if (!isset($options['emails']))
    {
      throw new sfConfigurationException('You must provide a "emails" parameter for this logger.');
    }
    $this->emails = $options['emails'];
 
    if (isset($options['format']))
    {
      $this->format = $options['format'];
    }
 
    if (isset($options['time_format']))
    {
      $this->timeFormat = $options['time_format'];
    }
 
    if (isset($options['type']))
    {
      $this->type = $options['type'];
    }
 
    if (isset($options['subject']))
    {
      $this->subject = $options['subject'];
    }
    else
    {
      $this->subject = sfConfig::get('sf_app') . ':: Log';
    }
 
    parent::initialize($dispatcher, $options);
 
    if (isset($options['include_level']))
    {
      if (!is_int($options['include_level']))
      {
        $options['include_level'] = constant('sfLogger::'.strtoupper($options['include_level']));
      }
 
      $this->include_level = $options['include_level'];
    }
    else
    {
      $this->include_level = $this->getLogLevel();
    }
  }
 
  /**
   * Logs a message.
   *
   * @param string $message   Message
   * @param string $priority  Message priority
   */
  public function log($message, $priority = self::INFO)
  {
    if ($this->include_level < $priority)
    {
      return false;
    }
    if($this->getLogLevel() >= $priority)
    {
      $this->log = true;
    }
 
    return $this->doLog($message, $priority);
  }
 
  /**
   * Logs a message.
   *
   * @param string $message   Message
   * @param string $priority  Message priority
   */
  protected function doLog($message, $priority)
  {
    $this->body .= strtr($this->format, array(
      '%type%'     => $this->type,
      '%message%'  => $message,
      '%time%'     => strftime($this->timeFormat),
      '%priority%' => $this->getPriority($priority),
      '%EOL%'      => PHP_EOL,
    ));
  }
 
  /**
   * Returns the priority string to use in log messages.
   *
   * @param  string $priority The priority constant
   *
   * @return string The priority to use in log messages
   */
  protected function getPriority($priority)
  {
    return sfLogger::getPriorityName($priority);
  }
 
  /**
   * Executes the shutdown method.
   */
  public function shutdown()
  {
    if($this->log)
    {
      foreach($this->emails as $email)
      {
        mail($email, $this->subject, $this->body);
      }
    }
  }
}