Today, I grabbed a router, which took me an hour to get, and I was always in a “crowded” queue before. I couldn’t help but think of the ticketing system I made for Beautiful Encounter last year. Someone asked, why can’t I get a ticket with the script I wrote? The mystery will be revealed in this article.

The conditions that the ticketing system must meet are:

  1. One person, one ticket, a person cannot get two tickets;
  2. The tickets to be issued every day must be issued exactly, neither more nor less (assuming there are enough people to grab tickets);
  3. The probability of successfully grabbing tickets with a program should not be significantly higher than the probability of manually grabbing tickets.

The first two are not difficult to achieve, using database transactions (the number of people grabbing tickets for Beautiful Encounter is not that many, about 100 people come to grab tickets every day, MySQL can fully support it). The third one is not so easy. The easiest solution, and the one previously used by many Internet ticketing activities, is first-come, first-served, but a verification code is required after successfully grabbing a ticket. The machine cannot automatically enter the verification code, so the grabbed ticket is invalidated. This approach has two obvious problems:

  1. The ticketing program can store the verification code image, verification link, cookie, etc. after successfully grabbing the ticket. After the user receives the ticket grabbing success reminder, they manually enter the verification code and complete the follow-up operations, so the program still has the advantage of being the first to start.
  2. At the moment when the ticket grabbing starts, a large number of requests flood into the ticketing system. If a relational database is used, to ensure “one person, one ticket” and the number of tickets issued is neither more nor less, each ticket grabbing operation is a database transaction, and relational databases generally have difficulty supporting a large number of concurrent transactions, causing system overload.

Another solution is to cancel the “ticket grabbing” link and directly draw from all users who participate in the reservation. If the uniqueness of the user can be guaranteed (for example, the campus activity platform that Beautiful Encounter relies on is bound to the USTC mailbox), it is the easiest and there is no possibility of program ticket brushing. Car buying lottery, course selection lottery, etc. are all done this way. However, “lottery” always makes people question fairness. In addition, the drawn users may not pick up the ticket in the end (online shopping is not placing an order), wasting everyone’s feelings. In order to create a fair impression and for “hunger marketing” to make users who grab tickets feel hard to come by, there must be a “ticket grabbing” process at a fixed time.

With the basic idea of “lottery”, it is not difficult to design a ticketing system. It is necessary to ensure that the machine is not significantly higher than humans in the probability of successful ticket grabbing, and to ensure that users who have given up grabbing tickets will not draw tickets (otherwise these people may not pick up the ticket in the end). Therefore, a webpage is needed to let users keep it open, and a ticket grabbing request is sent every few seconds. This interval is agreed upon by the front and back ends, that is, ticket grabbing requests shorter than this interval will be considered invalid by the server. If the user gives up grabbing tickets and closes the ticket grabbing webpage, then the future lottery will have nothing to do with him. This is the same as buying a car lottery. After a few months, you have to “renew” it, otherwise you will be removed from the lottery pool.

Ticket grabbing requests can be sent manually by users, or they can be automatically sent by front-end code at regular intervals. For Beautiful Encounter, because the ticket grabbing time is short (the tickets are issued within 1~2 minutes), in order to create a tense atmosphere, the scheme of manual sending by users is adopted, that is, the user has to manually click the ticket grabbing button after the countdown to 0. If you use the scheme of front-end code to automatically send at regular intervals, please add some random delay, otherwise the 0, 5, 10, 15… seconds will be full of user requests, but it will be very idle in the middle.

Tickets are naturally drawn from these ticket grabbing requests. There are three lottery schemes:

  1. Every time you grab a ticket, you will either draw or not draw with a fixed probability. The advantage is that the implementation is simple, the disadvantage is that the ticket release rate cannot be controlled, and the tickets may not be issued when there are few participants. Beautiful Encounter uses this scheme.
  2. With a certain time interval (such as the same 5 seconds as the countdown) as a cycle, a fixed number of tickets are released each cycle. At the end of the cycle, randomly draw from the requests received in this cycle. If the number of requests in a cycle is less than the number of tickets, the remaining tickets will be put into the next cycle. I think this scheme is the best, but users cannot know the draw result immediately (you can notify the user at the next ticket grabbing request).
  3. With a certain time interval (such as the same 5 seconds as the countdown) as a cycle, a fixed number of tickets are released each cycle, first come first served. Compared with the second scheme, user requests can be returned immediately. There is a risk of being discovered, but the start time of ticket release within the cycle can be randomized to avoid regularity.

In order to punish the ticket brushing script, in the server-side code of Beautiful Encounter, every time a legal ticket grabbing request is received, whether it is within the 5-second silence period (the countdown time agreed by the front and back ends), the last ticket grabbing time is updated, that is, the silence period is extended to (current time + 5 seconds). If a ticket brushing script brushes a ticket every second, it will never get a ticket. Of course, this practice is not friendly to users who open multiple webpages to grab tickets, because there are two independent countdowns. If the user’s mouse is fast enough and clicks every time the countdown reaches 0, they will never be able to grab a ticket.

Therefore, it is best to discard the ticket grabbing requests received during the silence period and not update the last ticket grabbing time. In this way, no matter how many webpages the user opens to grab tickets, they can only send one valid ticket grabbing request every 5 seconds. The current problem with the Beautiful Encounter ticketing system is that the countdown time is returned by the server. If multiple pages are opened, the user will see that the countdown is shorter than 5 seconds each time, which may cause confusion. A simple improvement is to start the countdown from 5 seconds no matter how long it is from the end of the user’s silence period. In this way, although the countdown reaches 0 on some pages, the ticket grabbing request is actually invalid.

Finally, attach a flowchart:

ticket-processticket-process

Comments

2014-02-26