Articles from June 2014
Increasing Mobile Web Time-to-Glass
Posted on Wednesday, June 25, 2014 at 4:51PM by Jack Servedio
While the conventional thinking on improving the time-to-glass of mobile websites dictates minimizing file sizes, simplifying CSS styling, HTML, and JavaScript, as well as reducing the total amount of content sent to the user - these approaches fail to recognize the fundamental reason why mobile websites take significantly longer to download: network latency, not transfer speed.
On the new, ever expanding, 4G networks transfer speeds are nearly on par with typical residential internet connections, yet websites can take 10 times as long to download, or more, on a mobile device. This all boils down to network latency on mobile networks. On even a modest residential internet connection, latency within the US in most cases will be 30-100ms, however, even on the fastest 4G networks in places like Manhattan or San Francisco, latency will normally be north of 200ms to even geographically close servers. On slower 4G networks or 3G networks, latency continues to climb. At my last company, average latency within the US between customers and our servers in the AWS cloud was right around 500ms, and that's within the US. Worldiwde, it was closer to a full second and a half.
Coupled with these extreme latencies is the limitation on the maximum number of concurrent connections - most mobile browsers allow for a total of 4-6 concurrent connections. On a typical Android Gingerbread device, even a major national mobile website like mobile.nytimes.com will spend just about 5 seconds loading in just latency alone due to it's 38 individual resources (not including all of the additional XHR requests). Even a site like this, which is a relatively large size for mobile, with around 350k worth of resources, transfer time would take less than half of a second on even a sluggish 3G network. Clearly, reducing the actual size of the site woudln't improve things here.
So what to do? The answer is simple: instead of reducing the actual file-size of the website, we need to minimize the number of total requests. While it is best practice for developers to separate out HTML, CSS, and JavaScript into multiple files, it is a terrible practice to serve them up that way to the end-user on a mobile device. We have separate development and minified styles and script files, so why should this be any different? For the New York Times, by serving up all of their HTML, CSS, and JavaScript in the same request, they would eliminate 12 requests - which translates into a full second and a half worth of latency. This is a great first step, and for many sites will represent a very large improvement in time-to-glass.
After doing this, things start to get a little more complicated - but there are plenty of options to chose from. The ultimate goal should be reducing the number of initial resources to 4 (or less) so the initial site can be loaded with the smallest possible latency penalty. Typically, the largest number of requests on a site come from the images - and this is where the bulk of the work lies. For static images such as buttons, backgrounds, logos, etc. the obvious solution is to create a single sprite.
What about dynamic images like product thumbnails? When it comes to these types of images there are three good solutions - all with their own advantages and drawbacks. However, there is no reason you can't use any combination of these as needed.
- The easiest and most obvious of the two solutions is to load them after the site has been displayed using AJAX. This is great since it requires no additional server overhead or bandwidth from the end-user. But, AJAX requests are subject to the same latency issues and maximum concurrent requests limitation and will require time to be displayed. While the site will be loaded and useable, the end-user will still have to wait to see these images and this impacts the user-experience.
- The next, less obvious solution is embedding the image data itself into the site using base 64 encoding. This can allow every single product image to be downloaded with the initial site without adding a single request. There are two main drawbacks to this solution: the first being base 64 encoding an image will increase the image size roughly 1/3 and require more of the end-user's available data. However this is mitigated by the fact that you are eliminating the latency all together. The second, and bigger issue, is that it isn't universally supported - while iOS, Android, Blackberry, and Windows devices do support it, some older Java devices do not. Again, this can be mitigated as well. When an unsupported device processes the image data, it will attempt to download a file that has the name of the image data. With a little creative URL Rewriting, the end user can still be displayed the image - it will just have to be processed like a regular request.
- The last solution is to create on-the-fly image sprites. The obvious drawback to this is the overhead required on the server generating all of these sprites, but this overhead can be eliminated by caching the sprites. The main advantages of this over the other two is that the images will be displayed immediately, there will be no compatibility issues, and no additional user-data is required. However, as the total number of images increases, the total number of possible sprites increases exponentially and this solution can only scale so far.
The last source of requests come from things like tracking pixels, ads, and other external sources. While many sources of tracking scripts and ads understand the importance of latency and make their requests in the background using AJAX, not all of them do. Ensure that every external request on your site is happening in the background long after your own resources are served and available to your customer. Never let a hanging request for an ad prevent an important resource like the sprite containing your logo from loading. Managing the external scripts running on your site properly can be just as important as managing your own resources. Never just copy and paste a script tag from a vendor without thorougly testing it's impact on your site.
Connecting to Vertica with PHP in Linux
Posted on Tuesday, June 24, 2014 at 5:17PM by Jack Servedio
Unlike MySQL, SQL Server, or PostegreSQL, PHP is unable to natively connect to Vertica databases. Luckily, PHP does include ODBC support natively with PDO and Vertica has ODBC drivers. With a little bit of configuration, we can be set up and connecting to a Vertica cluster in just a few minutes.
Before we begin, there are a few dependencies that have to be installed. G++ and OpenSSL are required (and you probably have them already) and we will be using the unixODBC package to implement the ODBC API.
Now that the main dependencies are out of the way, lets go ahead and download the appropriate Vertica Driver. You will have to create a My Vertica account, if you don't already have one, and log into the Vertica Web Site. Once in, navigate to the driver download page and download the appropriate ODBC Linux Driver - there are both 32 and 64 bit versions. You will want to download the driver to /opt/vertica. In my examples, I will be installing Vertica ODBC driver version 6.1.2 for x86 64-bit.
With the drivers downloaded, go ahead and uncompress them. The drivers are going to be gzip compressed tar archives, so a simple tar -zxvf will expand them for you. Before we configure the drivers, we need to make sure that all of the required packages and dependencies are installed with ldd on. If everything is good, it should look like this.
root@server:/opt/vertica# ldd lib64/libverticaodbc.so
linux-vdso.so.1 => (0x00007fff2a3fe000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fc2750f6000)
libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007fc274edc000)
libcrypt.so.1 => /lib/x86_64-linux-gnu/libcrypt.so.1 (0x00007fc274ca2000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fc274a85000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fc274781000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fc27447c000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fc274266000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc273e9e000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc276869000)
If any of the required shared objects (.so files) are shown as "Not Found", you will have to install or update those packages on your machine.
We are now ready to configure ODBC to connect to Vertica using the driver we just downloaded. To do this, we will need to edit two ODBC configuration files, create a new configuration file, and create an environment variable to reference it. To begin editing the ODBC configuration files, you first have to find them - in most cases they are located in /etc/, but if they are not there simply use odbcinst -j to determine the correct location.
The first file we will be updating is the odbc.ini file. In this file, we will be creating a DSN (Database Source Name) for our Vertica Database. This is what the file will look like if you have no other DSNs configured. Be sure to use your Vertica configuration.
[ODBC Data Sources]
VerticaDSNunixodbc = vertica_database_name
[VerticaDSNunixodbc]
Description = Vertica Database using ODBC Driver
Driver = /opt/vertica/lib64/libverticaodbc.so
Servername = vertica.myserver.com
Database = vertica_database_name
UserName = vertica_username
Password = vertica_password
Port = 5433
Next, we will be editing odbcinst.ini, which is located in the same directory has odbc.init, typically /etc/. Here is what it will look like if you have no other DSNs configured.
[VerticaDSNunixodbc]
Description = Vertica Database using ODBC Driver
Driver = /opt/vertica/lib64/libverticaodbc.so
Next, we will need to create the configuration file /etc/vertica.ini. This is the configuration that the Vertica Driver will use to communicate with unixODBC. In this file, we will provide the path to the libodbcinst Shared Object. It should be located in /usr/lib, but may not be there so be sure to verify it's location. Here is what the vertica.ini file should look like.
[Driver]
DriverManagerEncoding = UTF-16
ODBCInstLib = /usr/lib/libodbcinst.so.1.0.0
ErrorMessagesPath = /opt/vertica/lib64
LogLevel = 4
LogPath = /tmp
Now that the Vertica configuration file is created, we will need to create an environment variable called VERTICAINI that points to it. This is how the Vertica Driver will find the configuration file. Here is how to create and verify the environment variable.
root@server:/opt/vertica# export VERTICAINI=/etc/vertica.ini
root@server:/opt/vertica# cat $VERTICAINI
[Driver]
DriverManagerEncoding = UTF-16
ODBCInstLib = /usr/lib/x86_64-linux-gnu/libodbcinst.so
ErrorMessagesPath = /opt/vertica/lib64
LogLevel = 4
LogPath = /tmp
root@server:/opt/vertica#
The Vertica Driver is now configured to work with unixODBC and the DSN for your Vertica Database is all set and ready to go. We will use the isql tool to verify that the connection is working before we attempt to connect using PHP.
root@server:/opt/vertica# isql -v VerticaDSNunixodbc
+---------------------------------------+
| Connected! |
| |
| sql-statement |
| help [tablename] |
| quit |
| |
+---------------------------------------+
SQL> quit
root@server:/opt/vertica#
Great! Everything is working. Lets write some basic PHP Code that uses PHP's PDO module to connect to the Vertica DSN we just created and run a sample query.
<?php
# Vertica DSN Configuration - Edit with your Database Name!
$vadb_dsn = 'odbc:DSN=VerticaDSNunixodbc;Database=vadb';
$vadb_options = array(PDO::ATTR_AUTOCOMMIT=>FALSE, PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION);
$vadb_user = 'username';
$vadb_pass = 'password';
# Connect to Vertica Database
try {
$vadb = new PDO( $vadb_dsn, $vadb_user, $vadb_pass, $vadb_options );
}
catch ( PDOException $e ) {
die( "Couldn't connect to Vertica" );
}
# Query to Select Timestamp of Vertica Database
$vsql = "SELECT CURRENT_TIMESTAMP as 'ts';";
# Prepare Statement and Execute
$stmt = $vadb->prepare( $vsql );
$stmt->execute();
# Fetch Results
while( $row = $stmt->fetch(PDO::FETCH_ASSOC) ) {
$vertica_timestamp = $row['ts'];
}
# Close Connection
$vadb = null;
# Output the Timestamp
echo "Vertica Current Timestamp: " . $vertica_timestamp;
?>
When this script is run, it will connect to the configured Vertica Database and execute a query to get the current timestamp. You have successfully configured PHP and your server to connect with Vertica.
- Page 1 of 1
- << First
- 1
- Last >>