Ghost’s blog

March 13, 2007

Geolocation on server page

Geolocationing system on the server page would be cool. So let’s do it!

There are several ways to get location information on that page, which way to go?

  1. The easy way: do it by PHP
  2. DB style: fetch info from database
  3. Advanced style: PHP module
  4. Anything, as far as it works

The easy way is to get Maxmind’s GeoIP.dat (used by CountryFilter plugin to block connections from USA, Canada and GB) and use it through “pure” PHP API. On the server page all that is needed is something like $countrycode = geoip_get_country_code($ip) and that’s it. The code must be searched from 700 kB geoip database, which obviously takes some time. Doing the search for nearly 3000 servers on one page slows down generation of the page to about 10 seconds.

DB style thing is to get Maxmind’s IP-to-Country database in CSV format (Comma Separated Value) and load it to database. Then it is possible to query country information while querying all other server information, such as server name and number of players. This should be fast and neat, but it turns out that it’s only neat. Rendering the server page takes over 10 seconds, even though MySQL says it completes the query in 5. Either way, it’s too slow.

Advanced style gets us to real world implementations. Maxmind has C library and PHP module implementation of the IP-to-Country system. Obviously the C implementation of the same system as in “the easy way” is far faster than PHP version. This proves to be true. Compiling C library and managing to install PHP module with PEAR was somewhat tricky to get along, especially the PEAR part, but eventually PHP found GeoIP module and GeoIP module found GeoIP database. For some reason PHP module’s function name was different than on the “pure” PHP API. Luckily I noticed that while messing with the installation. The end result is fast and quite neat, only one line of code to get a country code for certain IP. This method renders the server list page in 2.5 seconds. Well, not something that I’d expect.

Quite poor result with PHP modules was surprise. Searching 3000 servers’ location shouldn’t be taking 2.5 seconds. Well, it wasn’t. Rendering the page without country information takes 1,5-2 seconds, so retrieving the location information takes some 0,5-1 seconds. Moreover for some reason PHP is slowing down MySQL queries. Querying 3000 servers from some 30 000 servers takes only split second for MySQL to complete. It shouldn’t take seconds to render by PHP.

From the very start it’s been clear that ultimately the fastest way would be to retrieve location information only once for every server and store them somewhere, most preferably to the DB with all other server information. This, however, wouldn’t be very neatly integrated to the current server query system. It would take much more effort to change the current server querier - without breaking it - to use Maxmind’s PERL module (they have APIs for every use) than to do things separately.

The conclusion is that the current server list page is already rendering itself very slow. Somekind of caching could be used to speed up things. Then it wouldn’t matter if rendering the page every now and then would take up to 5 seconds.

Update (15 minutes later :P )

Getting pages cached in PHP seems to be very straightforward. The same method is already being used on server stats images, but they are images. Now we have some HTML cached too. Yeah!

March 4, 2007

Migration from ru to pin

Migrating from rusetti to pinsetti has gone extremely well.

It’s unbelieveable that all MySQL databases with all user privileges were perfectly transferred simply by copying the data directory of MySQL to the new server. The database was running in “production use” all the time when backup was being made. It means that the server query thingie, PS3, PS2 and messageboard were possibly writing or reading stuff from the database as it was being copied. That may have caused, and probably did, that the database file wasn’t the same when copying was started and when it was finished. However, MySQL is flexible little pig and it doesn’t seem to have suffered fatal injuries :).

Also the new server query system worked like a charm on a new server, almost. There was one little problem which took about hour to solve. For some reason it was complaining that there is an error in SQL syntax even though the very same SQL queries were being done on rusetti at the same time. The problem was years old Perl MySQL module - SuSE quality (made in Germany). It took minute to update, but an hour to resolve.

Some compromises had to be done. There are no longer “servers on map” or “masterserver rank” graphs. They were based on the old file based server query thing and are no longer supported. For masterserver rank there is already equivalent database solution, but it has jammed the old server once - even though it worked ten times before that. It could be that the new server is juicier and can handle it better, but it remains to be seen.

Currently there are still open issues in the migration. There are lots of Setti Masterserver users who still use the old system. The old system will disappear in less than two weeks leaving thousands of players without server list. Release groups and 3rd party server browser developers should update their clients to use new IP address for the masterserver. It could be that they don’t realize what’s going to happen, even though there is notification in the old masterserver.

March 1, 2007

Setti MasterServer - Better server browser

New MasterServer - better server browser

Setti MasterServer started humbly in March 2006. It steadily gained popularity by delivering the most comprehensive list of public servers and being extremely reliable. The lift-off for Setti MasterServer happened on mid-April when DigitalZone released CS:S patch including Setti MasterServer. User amounts increased immediately 10 times what they had been. The effect cumulated as other releases started to feature Setti MasterServer too.

Currently Setti MasterServer has approximately 5000 users. There are on average 15 requests per minute in a day. At peak times there is one request every two seconds. Since March 2006 there has been nearly 4 million requests from all over the world.

The server itself is relatively simple. There are couple hundred lines of code written in Perl. Basically the server just gets list of servers, transforms it to compatible format and sends the result data back to a client. Server addresses are encoded with 6 bytes. First four digits of an IP address are formatted in one byte each, and a port number is formatted with two bytes in so called “unsigned network ordered short”. Server addressses are packed in 128 groups before sending them to a client.

Setti MasterServer daily requestsSetti MasterServer yearly requestsSetti MasterServer yearly growth

At this time there are about 2600 servers in Setti server list. That means there will be about 20 packets to be sent to a client. Every packet is 768 bytes in size, so the total cost for sending all servers to one client is 15 kb. Every day there are in total about 20000 requests, so the bandwidth consumption for the service is 320 MB per day. Surprisingly much.

February 28, 2007

History of Setti server querier

Dawn of the list

Setti server querier was born sometime in 2005. The first version listed handful of servers and allowed server admins to submit their own servers on the list. The main cause for the service was to help people keep track on servers allowing all players, ie. public, listed on different web sites.

Obviously, after a while, some servers went down and the list contained dead servers. The solution in all its simplicity was to add “Report broken” link next to the server address. The link made it possible for users to say the server is down. This system was active for few weeks. Not surprisingly the server list was very static and not very useful - still slightly more useful than lists on dozen of forums. After some time, quite expectedly, web crawlers started to terrorize report links and all servers gained “broken” points.

Enter QStat

QStat is program which is able to query many kinds of server types. It is possible to give list of servers as parameter and QStat will query all of them. It’s even possible to output the result as customized web page. This is how things were in the early days of Setti server list. The main page of Setti CSS server was generated every 10 minutes by QStat. All changes on the main page had to be done in the QStat template. Server querying was automatic, so from this point on Setti server list has been somewhat unique in its kind.

Old Setti CSS server main page. Generated by QStat.

Around that time the system started to store historical data too. It was started partly due to difficulties recognizing servers being down for only hour or two from servers being down for two weeks. The historical data allowed generation of very accurate server statistics.

At this point the server query system was functioning quite effortlessly. It was easy to submit servers ( “in the form at the bottom of the page” ) and dead servers were removed automatically. The system scanned hundreds of servers all over the world in minutes. The speed was sufficient for the time being. However, there were still problems keeping the list valid. Not all submitted servers were public. They had to be removed from the list by adding them manually in excluded servers list. At the time it wasn’t known how to automatically verify whether a server is accepting all players or not.

Enter client emulation

The biggest revolution in server querying happened on October 2005. Then bug.meh.not revealed the secrets of client-server-client communication when the client joins the server. The procedure allowed anyone to check whether a server will accept all players or not. Not long after his release the client emulation was reproduced for much greater use: verifying servers in Setti servers list. The effect of being able to tell a server from a public server is the most significant thing for server lists.

UPDATED RELEASE: Source/HL Cracked Server Query Tool

[ Posted: Monday 29th August 2005 11:06 pm ]

Cracked server tester

[ Posted: Sunday 23rd October 2005 01:09 pm ]

[DEV]Cracked Server Finder:SourceCode

[ Posted: Sunday 30th October 2005 01:55 pm ]

Historical data

By this time the QStat based Setti server querier was to be decommissioned. New Perl based system featuring server status checking was to replace the old, somewhat messy system. The speed of server querying was slightly disappointing, due to lack of threads, but as there weren’t too many servers there wasn’t need for better system. Just as before.

Historical data for all servers had grown much, but all statistics based on the thousand log files were working good. There were slight problems because of changed syntax along the way. The very first historical data entry looked like this.

1128021324,fal.setti.info:27015,24/24,de_dust2,42,cstrike fal.setti.info CSS server

The line contains unixtime, server address, players, map name, ping, server name with server type. When the query system changed to Perl program, it was good time to add some more information which could be requested from the server.

1146333203,ru.setti.info:27015,26/25,de_dust2, 0/d/0/l/1.0.0.28,Setti CSS server

The line is almost the same, but ping has been replaced with “0/d/0/l/1.0.0.28″. Cleverly enough the delimiter is “/” and not “,”, so all statistics scripts still worked without changes. The first entry is ping, fixed to 0 for being no use, ‘d’ for dedicated, 0 for no VAC, ‘l’ for linux and 1.0.0.28 as game version. After months and several small improvements the syntax for historical server data reached its final form.

1153264488,ru.setti.info:27015,25/24,de_dust2,0/d/0/l/1.0.0.28/cstrikes/240/1,Setti CSS server

There is additional “/cstrikes/240/1″, which means ‘cstrike’ for game directory with appended ’s’ to indicate HL2/Source, 240 as AppID and 1 for number of bots.

The statistics files take whopping 2.7 GB disk space in 10000 files, ie. that many servers. Still, all stats for great number of servers were rendered in split second. Global server statistics and such were generated from the overwhelming number of log files by nifty handcrafted Perl programs. Sweet.

New, improved & database

The new database system is much faster than the old file based system. It’s because of threads. The latest file based system had threads, but they weren’t used as efficiently. The current database based server querier scans 3000 servers in 120 seconds, which is 25 servers per second. It’s good enough. Just as before, no need for better.

Some compromises had to be done with the database. There are three historical database tables: daily, weekly and monthly. Daily table contains data in ten minute intervals for one week, week table contains data in one hour intervals for month and monthly table contains data in four hour intervals infinitely - don’t mind the names. The file based queries stores all historical data in ten minute intervals. All! It means that in file based system it’s possible to see back in time in great accuracy. For example it’s possible to look at New Year on 2006 and see all aforementioned server statistics in ten minute intervals for all servers. The new system does only 4 hour accuracy. Good enough.

Additionally the new server query system scans a lot wider span of servers than all the other server query systems combined. The old system started to cough around 700 servers. The new could do 10000, but it seems that 3000 is all there is.

For the first time in the history of Setti server queriers the system in use is on solid ground. Confidence in the system is higher than ever. The system is easy to maintain and the database makes it easy to query different kind of results.

It’s fast. It’s reliable. It’s the product of necessity.