Система голосования PHP + MySQL с ограничением по IP

Мне нужно внедрить систему анонимного голосования (регистрация пользователя - это непросто). Я решил, что лучший вариант - ограничить количество голосов по одному элементу до 10 на каждый IP-адрес (с учетом школ и т. Д.).

Как лучше всего обойти это? Я использую PHP + MySQL. В часы пик может быть до 20 голосов в секунду. Я использую внешние интерфейсы с балансировкой нагрузки с выделенным сервером MySQL.

Меня беспокоит вставка строки в базу данных для каждого голосования, а затем запрос этих данных, чтобы увидеть, достигли ли они своего предела, может быть слишком много для обработки сервером?

Может мне лучше взглянуть на MongoDB или что-то в этом роде?

Есть другие идеи?


person bradley    schedule 16.07.2011    source источник


Ответы (6)


Я бы посоветовал сохранить статус "проголосовало" в куки. Это позволит голосовать целым школам и офисам. Выполнение 10 на IP-адрес позволит одному пользователю на адресе голосовать 10 раз.

Очевидно, есть способы обойти это, например, очистить файлы cookie и т. Д., Но я думаю, что это хороший вариант.

person adlawson    schedule 16.07.2011
comment
Извините, забудьте упомянуть, что я уже этим занимаюсь. Мне просто нужно запретить людям, которые хотят пойти немного дальше, очистив свои файлы cookie, от голосования более 10 раз. Я знаю, что нет надежного способа, но ограничение по IP кажется хорошим компромиссом. - person bradley; 16.07.2011
comment
В этом случае вы можете добавить верхний предел для IP, но я полагаю, это зависит от вашего рынка. Если вы ожидаете, что проголосует много школьных / офисных пользователей, это может быть не самой хорошей идеей. Кроме того, даже с ограничением IP-адресов пользователи могли так же легко голосовать через прокси. Если действительно так важно сохранить по одному голосу на человека, я бы посоветовал зарегистрироваться. - person adlawson; 16.07.2011

Я думаю, что базы данных ключ / значение здесь будут лучше.
Кроме того, вам не нужно строить строки для каждого голоса, вам нужна только одна строка на IP и используйте запросы LIKE

INSERT INTO .. ON DUPLICATE KEY UPDATE
person RiaD    schedule 16.07.2011

Мне нужно внедрить систему анонимного голосования (регистрация пользователя невозможна)

IP-адреса - не способ решить эту проблему, потому что во многих компаниях / школах тысячи людей привязаны всего к паре IP-адресов. Если вы не хотите, чтобы пользователи входили в систему из-за анонимного голосования, я бы посоветовал вам использовать CAPTCHA (recaptcha) для защиты массового голосования, потому что все другие методы могут быть обойдены опытным программистом. Возможно даже подделать IP-адрес. Я считаю, что во многих дистрибутивах Linux вы можете легко подделать IP-адреса.

alfred@alfred-laptop:~/bash$ apt-cache search ^fake$
fake - IP address takeover tool

http://en.wikipedia.org/wiki/IP_address_spoofing#Defense_against_spoofing:

Также рекомендуется разрабатывать сетевые протоколы и службы так, чтобы они не полагались на IP-адрес источника для аутентификации.

Но опытный программист не может обойти хорошо протестированные CAPTCHA, такие как recaptcha. Голосовать немного сложнее, но, на мой взгляд, это единственный способ противодействовать фальшивым результатам голосования. Также капча не может сделать систему голосования неуязвимой для ошибочных голосов. Единственный способ создать такую ​​систему - использовать аутентификацию. Ведите список пользователей (личностей), которым разрешено голосовать.

Как лучше всего обойти это? Я использую PHP + MySQL. В часы пик может быть до 20 голосов в секунду.

Это даже не вызовет проблем с Redis, потому что он безумно быстр.

Redis - это расширенное хранилище ключей и значений с открытым исходным кодом. Его часто называют сервером структуры данных, поскольку ключи могут содержать строки, хэши, списки, наборы и отсортированные наборы.

Сначала моя системная информация. Мне он нравится, но он уже довольно старый.

-Computer-
Processor       : 2x Intel(R) Core(TM)2 Duo CPU     T7100  @ 1.80GHz
Memory      : 2051MB (1403MB used)
Operating System        : Ubuntu 10.10
User Name       : alfred (alfred)
Date/Time       : Sat 16 Jul 2011 07:53:20 PM CEST
-Display-
Resolution      : 1280x800 pixels
OpenGL Renderer     : Unknown
X11 Vendor      : The X.Org Foundation
-Multimedia-
Audio Adapter       : HDA-Intel - HDA Intel
-Input Devices-
 Power Button
 Lid Switch
 Sleep Button
 Power Button
 AT Translated Set 2 keyboard
 Dell Dell USB Keyboard
 Logitech Trackball
 PS/2 Logitech Wheel Mouse
 Video Bus
-Printers (CUPS)-
Canon-MP150     : <i>Default</i>
HP-Photosmart-b110
-SCSI Disks-
HL-DT-ST DVDRAM GSA-T20N
ATA WDC WD1600BEVS-2

Далее я собираюсь протестировать свой redis-сервер:

alfred@alfred-laptop:~/database/redis-2.2.0-rc4/src$ ./redis-server --version
Redis server version 2.1.12 (00000000:0)

alfred@alfred-laptop:~/database/redis-2.2.0-rc4/src$ ./redis-benchmark 
====== PING (inline) ======
  10000 requests completed in 0.23 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

94.11% <= 1 milliseconds
97.77% <= 2 milliseconds
98.97% <= 3 milliseconds
99.02% <= 4 milliseconds
99.51% <= 6 milliseconds
99.88% <= 7 milliseconds
100.00% <= 7 milliseconds
44052.86 requests per second

====== PING ======
  10000 requests completed in 0.23 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

87.97% <= 1 milliseconds
97.44% <= 2 milliseconds
98.83% <= 3 milliseconds
99.41% <= 4 milliseconds
99.51% <= 5 milliseconds
99.70% <= 6 milliseconds
100.00% <= 6 milliseconds
43478.26 requests per second

====== MSET (10 keys) ======
  10000 requests completed in 0.37 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

11.02% <= 1 milliseconds
82.00% <= 2 milliseconds
93.94% <= 3 milliseconds
97.18% <= 4 milliseconds
98.17% <= 5 milliseconds
98.89% <= 6 milliseconds
99.44% <= 7 milliseconds
99.51% <= 9 milliseconds
99.52% <= 10 milliseconds
100.00% <= 10 milliseconds
26881.72 requests per second

====== SET ======
  10000 requests completed in 0.24 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

86.50% <= 1 milliseconds
96.08% <= 2 milliseconds
97.45% <= 3 milliseconds
97.87% <= 4 milliseconds
99.02% <= 5 milliseconds
99.51% <= 6 milliseconds
99.52% <= 7 milliseconds
100.00% <= 7 milliseconds
40983.61 requests per second

====== GET ======
  10000 requests completed in 0.23 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

86.06% <= 1 milliseconds
97.51% <= 2 milliseconds
98.89% <= 3 milliseconds
99.65% <= 4 milliseconds
100.00% <= 4 milliseconds
42553.19 requests per second

====== INCR ======
  10000 requests completed in 0.23 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

90.72% <= 1 milliseconds
96.92% <= 2 milliseconds
98.12% <= 3 milliseconds
98.33% <= 4 milliseconds
99.27% <= 5 milliseconds
99.51% <= 7 milliseconds
100.00% <= 7 milliseconds
43103.45 requests per second

====== LPUSH ======
  10000 requests completed in 0.23 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

87.92% <= 1 milliseconds
96.35% <= 2 milliseconds
98.26% <= 3 milliseconds
99.51% <= 7 milliseconds
100.00% <= 7 milliseconds
42735.04 requests per second

====== LPOP ======
  10000 requests completed in 0.24 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

87.75% <= 1 milliseconds
96.67% <= 2 milliseconds
97.77% <= 3 milliseconds
98.64% <= 4 milliseconds
98.65% <= 5 milliseconds
99.80% <= 6 milliseconds
100.00% <= 6 milliseconds
41841.00 requests per second

====== SADD ======
  10000 requests completed in 0.23 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

89.55% <= 1 milliseconds
96.56% <= 2 milliseconds
97.80% <= 3 milliseconds
98.76% <= 4 milliseconds
99.50% <= 5 milliseconds
99.63% <= 6 milliseconds
100.00% <= 6 milliseconds
42553.19 requests per second

====== SPOP ======
  10000 requests completed in 0.25 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

88.12% <= 1 milliseconds
96.21% <= 2 milliseconds
97.45% <= 3 milliseconds
97.99% <= 4 milliseconds
98.53% <= 5 milliseconds
99.51% <= 6 milliseconds
100.00% <= 6 milliseconds
40322.58 requests per second

====== LPUSH (again, in order to bench LRANGE) ======
  10000 requests completed in 0.24 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

89.41% <= 1 milliseconds
96.05% <= 2 milliseconds
97.76% <= 3 milliseconds
98.76% <= 4 milliseconds
99.01% <= 5 milliseconds
99.51% <= 7 milliseconds
99.96% <= 8 milliseconds
100.00% <= 8 milliseconds
42016.81 requests per second

====== LRANGE (first 100 elements) ======
  10000 requests completed in 0.40 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

11.56% <= 1 milliseconds
76.23% <= 2 milliseconds
91.93% <= 3 milliseconds
94.47% <= 4 milliseconds
97.80% <= 5 milliseconds
99.23% <= 6 milliseconds
99.87% <= 9 milliseconds
100.00% <= 9 milliseconds
24937.66 requests per second

====== LRANGE (first 300 elements) ======
  10000 requests completed in 0.86 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

2.28% <= 1 milliseconds
10.90% <= 2 milliseconds
35.68% <= 3 milliseconds
63.74% <= 4 milliseconds
86.00% <= 5 milliseconds
92.65% <= 6 milliseconds
94.96% <= 7 milliseconds
97.50% <= 8 milliseconds
98.04% <= 9 milliseconds
98.75% <= 10 milliseconds
99.56% <= 11 milliseconds
99.96% <= 12 milliseconds
100.00% <= 12 milliseconds
11682.24 requests per second

====== LRANGE (first 450 elements) ======
  10000 requests completed in 1.15 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

1.13% <= 1 milliseconds
6.20% <= 2 milliseconds
10.38% <= 3 milliseconds
27.37% <= 4 milliseconds
53.45% <= 5 milliseconds
74.60% <= 6 milliseconds
89.41% <= 7 milliseconds
95.40% <= 8 milliseconds
98.04% <= 9 milliseconds
98.98% <= 10 milliseconds
99.46% <= 11 milliseconds
99.58% <= 12 milliseconds
99.73% <= 13 milliseconds
99.87% <= 14 milliseconds
100.00% <= 14 milliseconds
8695.65 requests per second

====== LRANGE (first 600 elements) ======
  10000 requests completed in 1.45 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

0.52% <= 1 milliseconds
6.23% <= 2 milliseconds
10.67% <= 3 milliseconds
16.37% <= 4 milliseconds
27.51% <= 5 milliseconds
46.06% <= 6 milliseconds
60.82% <= 7 milliseconds
79.70% <= 8 milliseconds
90.96% <= 9 milliseconds
96.01% <= 10 milliseconds
97.99% <= 11 milliseconds
99.43% <= 12 milliseconds
99.90% <= 13 milliseconds
100.00% <= 13 milliseconds
6896.55 requests per second

Операция incr - это то, что вам нужно, и вы можете видеть, что моя система может справиться с 43103.45 requests per second.

Может мне лучше взглянуть на MongoDB или что-то в этом роде?

Я бы порекомендовал redis, как показано выше.

person Alfred    schedule 16.07.2011

Балансировка нагрузки, как вы описали, должна подойти. У выделенного сервера MySQL не должно возникнуть проблем с такой скоростью запросов. Я не думаю, что MongoDB поможет в подобной проблеме. Что-то вроде memcached намного эффективнее, но в какой-то момент вам все равно придется отправлять данные в более устойчивую базу данных MySQL.

Я согласен с adlawston на использование файлов cookie. Вы по-прежнему можете иметь верхний предел голосов, которые можно подавать с одного IP-адреса.

person Sid    schedule 16.07.2011

10 - это совершенно произвольное значение, и оно не будет учитывать офисы, в которых за одним общедоступным IPv4-адресом могут находиться сотни или даже тысячи человек. Не говоря уже о том, что вы потенциально позволяете людям голосовать десять раз.

Ясно, что это не надежное и не подходящее для определенной цели решение.

Найдите другой способ однозначно идентифицировать людей.

person Lightness Races in Orbit    schedule 16.07.2011

Просто убедитесь, что вы индексируете поле IP, и рассмотрите возможность представления его как чего-то другого, кроме строки (например, целого числа). Подробнее см. Здесь: http://daipratt.co.uk/mysql-store-ip-address/

Кроме того, идея cookie от Adlawson хороша. Вы можете использовать и то, и другое, и, возможно, сделать так, чтобы IP-адрес просто запускал для вас предупреждение, где вы могли бы перейти на какой-то экран администратора и решить, похожи ли эти IP-адреса на кого-то, кто пытается обмануть систему, а не на то, чтобы быть школой.

Обновление, касающееся ipv6: я не очень хорошо разбираюсь в ipv6 с точки зрения текущего веб-хостинга, поэтому не уверен, есть ли пользователи исключительно на ipv6. Если это так, вы можете рассмотреть некоторые идеи, представленные в этих сообщениях, о том, как их хранить:

person Dolan Antenucci    schedule 16.07.2011
comment
Звучит хорошо. Стоит ли беспокоиться об IPv6? Я не могу сохранить их в виде целого числа, или это вряд ли произойдет до того, как интернет-провайдер начнет их раздавать? Простите мое незнание. - person bradley; 16.07.2011
comment
Я обновил сообщение выше с некоторой информацией о ipv6 (хотя мой опыт в этом вопросе довольно ограничен) - person Dolan Antenucci; 17.07.2011