Full-service Internet Marketing & Web Development
Recent Posts

Recommended Reads
|
Kajabi vs SoftwareProjectsAdrian Singer, September 1, 2010 -- Posted under Conversion |
There's a new kid on the block.
A new system designed to "simplify the deployment of Marketing Campaigns, Sales Funnels, and Product Launches from their current technical complexity down to Drag-and-Drop Ease" (Source: Kajabi.com)
Kajabi was created by Andy Jenkins (VideoBoss, formerly with Stompernet), Kenny Rueter and Travis Rosser. With this roster, you can bet your Inbox is about to be flooded with emails about how Kajabi is the best thing since sliced bread.
With this post, I wanted to address a question by one of our clients - how does Kajabi compare with SoftwareProjects' own Shopping Cart solution.
Disclaimer: Kajabi is still under development. The information I gathered for this post was collected by analyzing two recent product launches powered by Kajabi, along with a series of emails from the Kajabi team.
First things first: Kajabi is NOT a Shopping Cart
Kajabi is not designed to be an end-to-end shopping cart system.
They will integrate with all popular shopping cart systems, but it's just not designed to be a CRM / Affiliate & Lead Manager / Fulfillment / Backoffice, like SoftwareProjects or Infusionsoft.
You can expect limited built-in support for selling your content, but you're not going to get an executive dashboard that lets you manage the full 360 of your Internet Business.

Membership System
Kajabi offers a built-in membership system, where paying members login to access the content (videos / tutorials) they paid for.
You can customize the membership system skin to some degree and manage members from the admin panel. Think aMember plus a CMS (Content Management System).
At this point my understanding is there's going to be a single backoffice (unlike SPI's Customer's Backoffice and Affiliate's Backoffice), which will support a single product per Kajabai deployment.
Content Delivery
This is one area that keeps being emphasized in all communications I hear about Kajabi.
Still not clear how this is different from hosting all videos and MultiMedia on Amazon S3 or EdgeCast, like everyone are doing.
I'm guessing they use the same underlying technology and just make it easier to use.
Autoresponder
Kajabi will not have a built-in Autoresponder.
It is said to integrate with popular Autoresponder services such as AWeber, SoftwareProjects, iContact etc.
Help desk
Kajabi will not have a built-in help desk system.
Hosting
Kajabi is said to offer "Cloud Computing Technology, (so that) you can publish anything you create with Kajabi instantly to the web - with theoretically infinitely scalable virtual hardware resources".
They seem to be using Rackspace Cloud hosting, to create virtual instances of your site as needed, to accommodate traffic demands.
This sounds very similar to SoftwareProjects' Multi-Homed hosting, where we do what no other company has ever done before and guarantee 100% uptime, no matter what.
Battle Tested
Kajabi successfully powered the product launches of Andy Jenkins' Video Boss and Frank Kern's List Control.
While still under development, the technology has proven its ability to handle launch-day traffic without too many glitches.
Here at SoftwareProjects, we have been powering the majority of the big product launches you hear about, including Magnetic Sponsoring WWN, the ShoeMoney System, ListBuilding, PPC Classroom, Affiliate Classroom, OnlineMLMSecrets and others.
Then again... we've been doing this since 1998.
In Summary
We really look forward to working with the Kajabi team on the integration side.
Where Kajabi shines is simplifying the process of getting an info-marketing product up in no time.
I would describe it as an InfoMarketing CMS with a membership backoffice. It may not have all the bells and whistles, but as long as the integration is straightforward, you get the best of both worlds.
-
More on this topic:
* Kajabi's home page
* Kajabi Beta Testing portal
* Follow Kajabi on Twitter
* Andy Jenkins blog
View 1 Comment(s)
A new system designed to "simplify the deployment of Marketing Campaigns, Sales Funnels, and Product Launches from their current technical complexity down to Drag-and-Drop Ease" (Source: Kajabi.com)
Kajabi was created by Andy Jenkins (VideoBoss, formerly with Stompernet), Kenny Rueter and Travis Rosser. With this roster, you can bet your Inbox is about to be flooded with emails about how Kajabi is the best thing since sliced bread.
With this post, I wanted to address a question by one of our clients - how does Kajabi compare with SoftwareProjects' own Shopping Cart solution.
Disclaimer: Kajabi is still under development. The information I gathered for this post was collected by analyzing two recent product launches powered by Kajabi, along with a series of emails from the Kajabi team.
First things first: Kajabi is NOT a Shopping Cart
Kajabi is not designed to be an end-to-end shopping cart system.
They will integrate with all popular shopping cart systems, but it's just not designed to be a CRM / Affiliate & Lead Manager / Fulfillment / Backoffice, like SoftwareProjects or Infusionsoft.
You can expect limited built-in support for selling your content, but you're not going to get an executive dashboard that lets you manage the full 360 of your Internet Business.

Membership System
Kajabi offers a built-in membership system, where paying members login to access the content (videos / tutorials) they paid for.
You can customize the membership system skin to some degree and manage members from the admin panel. Think aMember plus a CMS (Content Management System).
At this point my understanding is there's going to be a single backoffice (unlike SPI's Customer's Backoffice and Affiliate's Backoffice), which will support a single product per Kajabai deployment.
Content Delivery
This is one area that keeps being emphasized in all communications I hear about Kajabi.
Still not clear how this is different from hosting all videos and MultiMedia on Amazon S3 or EdgeCast, like everyone are doing.
I'm guessing they use the same underlying technology and just make it easier to use.
Autoresponder
Kajabi will not have a built-in Autoresponder.
It is said to integrate with popular Autoresponder services such as AWeber, SoftwareProjects, iContact etc.
Help desk
Kajabi will not have a built-in help desk system.
Hosting
Kajabi is said to offer "Cloud Computing Technology, (so that) you can publish anything you create with Kajabi instantly to the web - with theoretically infinitely scalable virtual hardware resources".
They seem to be using Rackspace Cloud hosting, to create virtual instances of your site as needed, to accommodate traffic demands.
This sounds very similar to SoftwareProjects' Multi-Homed hosting, where we do what no other company has ever done before and guarantee 100% uptime, no matter what.
Battle Tested
Kajabi successfully powered the product launches of Andy Jenkins' Video Boss and Frank Kern's List Control.
While still under development, the technology has proven its ability to handle launch-day traffic without too many glitches.
Here at SoftwareProjects, we have been powering the majority of the big product launches you hear about, including Magnetic Sponsoring WWN, the ShoeMoney System, ListBuilding, PPC Classroom, Affiliate Classroom, OnlineMLMSecrets and others.
Then again... we've been doing this since 1998.
In Summary
We really look forward to working with the Kajabi team on the integration side.
Where Kajabi shines is simplifying the process of getting an info-marketing product up in no time.
I would describe it as an InfoMarketing CMS with a membership backoffice. It may not have all the bells and whistles, but as long as the integration is straightforward, you get the best of both worlds.
-
* Kajabi's home page
* Kajabi Beta Testing portal
* Follow Kajabi on Twitter
* Andy Jenkins blog
View 1 Comment(s)
|
Troubleshooting CassandraMike Peters, August 31, 2010 -- Posted under Programming |
Keynotes from a great presentation titled Cassandra Troubleshooting: out of the shadows, presented by Benjamin Black at the Cassandra Summit in San Francisco two weeks ago.
The slides are here
-
Is your Ring unbalanced?
That's because when you add one node at a time using RandomPartitioner, the new nodes takes over half of the most balanced node:
Note that as long as you're doubling-up the size of your cluster, everything will be balanced. But when you're growing one node at
a time, the cluster will be unbalanced.
To fix: Manually assign tokens.
How do you know which tokens to assign? Use this Python script:
Writes are slow
Make sure your commitlog is on a separate drive.
Writes are fast. Reads keep getting slower
Step 1:
Look at iostat -x to see if you're maxing out utilization
If you are, get more nodes
Step 2:
Look at nodetool tpstats
Focus on the middle column (pending) and specifically:
* Row-Read-STage
* Message-Deserializer-pool
If these two are high (4096 is the max), it means your client is sending too many reads to this node.
Update your client or get more nodes to distribute reads.
Step 3:
Adjust memtable settings
When does a memtable get flushed to disk?
Size: When it gets to a certain size
Time: If it hasn't been flushed in x seconds
Operations: When certain operations occur
If you're flushing memtables too often, you're triggering follow-up effects (compactions, sstable merges) that is consuming a lot of bandwidth.
You want less frequent memtable flush, which leads to less frequent compaction and less disk bandwidth demand.
If memtable is not compatible with your data needs, you begin consuming huge amounts of your bandwidth on compactions.
once a minute = bad
Step 4:
Use SSDs for the disk drives. Makes no difference on the commit log drive.
I inserted a bunch of data, now my nodes are flapping
Flapping = nodes are marked down/up
Step 1:
Monitor swap (vmstat on linux, swapinfo on freebsd)
mmap takes 2gb per segment.
Swapping can delay gossip long enough to cause a node
to be marked down.
Swapping is bad.
To fix: Change DiskAccessMode in the Cassandra config file, to mmap_index_only
We avoid risking driving ourselves into swap by the JVM
allocating large chunks of mmap blocks.
Step 2:
Tell the O/S you want to avoid swapping if possible.
On FreeBSD: add this line to /etc/sysctl.conf
On Linux, echo 0 into /proc/sys/vm/swappiness
View 1 Comment(s)
The slides are here
-
Is your Ring unbalanced?
That's because when you add one node at a time using RandomPartitioner, the new nodes takes over half of the most balanced node:
32
16 16
8 8 16
8 8 8 8
4 4 8 8 8
4 4 4 4 8 8
16 16
8 8 16
8 8 8 8
4 4 8 8 8
4 4 4 4 8 8
Note that as long as you're doubling-up the size of your cluster, everything will be balanced. But when you're growing one node at
a time, the cluster will be unbalanced.
To fix: Manually assign tokens.
How do you know which tokens to assign? Use this Python script:
def tokens(nodes)
0.upto(nodes - 1) do {n}
p (n * (2**127 - 1) / nodes)
end
end
0.upto(nodes - 1) do {n}
p (n * (2**127 - 1) / nodes)
end
end
Writes are slow
Make sure your commitlog is on a separate drive.
Writes are fast. Reads keep getting slower
Step 1:
Look at iostat -x to see if you're maxing out utilization
If you are, get more nodes
Step 2:
Look at nodetool tpstats
Focus on the middle column (pending) and specifically:
* Row-Read-STage
* Message-Deserializer-pool
If these two are high (4096 is the max), it means your client is sending too many reads to this node.
Update your client or get more nodes to distribute reads.
Step 3:
Adjust memtable settings
When does a memtable get flushed to disk?
Size: When it gets to a certain size
Time: If it hasn't been flushed in x seconds
Operations: When certain operations occur
If you're flushing memtables too often, you're triggering follow-up effects (compactions, sstable merges) that is consuming a lot of bandwidth.
You want less frequent memtable flush, which leads to less frequent compaction and less disk bandwidth demand.
If memtable is not compatible with your data needs, you begin consuming huge amounts of your bandwidth on compactions.
once a minute = bad
Step 4:
Use SSDs for the disk drives. Makes no difference on the commit log drive.
I inserted a bunch of data, now my nodes are flapping
Flapping = nodes are marked down/up
Step 1:
Monitor swap (vmstat on linux, swapinfo on freebsd)
mmap takes 2gb per segment.
Swapping can delay gossip long enough to cause a node
to be marked down.
Swapping is bad.
To fix: Change DiskAccessMode in the Cassandra config file, to mmap_index_only
We avoid risking driving ourselves into swap by the JVM
allocating large chunks of mmap blocks.
Step 2:
Tell the O/S you want to avoid swapping if possible.
On FreeBSD: add this line to /etc/sysctl.conf
vm.swap_enabled=0
On Linux, echo 0 into /proc/sys/vm/swappiness
View 1 Comment(s)
|
Scaling in the real worldMike Peters, August 31, 2010 -- Posted under Traffic |
In our ongoing journey to deliver faster, more reliable shopping carts, email marketing and hosting solutions, we're always on the lookout for new technologies and techniques to deal with a lot of data.
I'd like to share a few presentations we recently came across, that talk about scaling in the real world:
* MySpace: Massive scaling a .Net website with the Microsoft Robotic Studio
* Twitter: Big Data in Real-Time at Twitter
* Scale at Facebook
* Yahoo: Selectively Materializing User's Event Feeds
* Four Kitchens: Scalable queuing with flexible service levels
* Cassandra at Mahalo
* Cassandra at CloudKick
I'd like to share a few presentations we recently came across, that talk about scaling in the real world:
* MySpace: Massive scaling a .Net website with the Microsoft Robotic Studio
* Twitter: Big Data in Real-Time at Twitter
* Scale at Facebook
* Yahoo: Selectively Materializing User's Event Feeds
* Four Kitchens: Scalable queuing with flexible service levels
* Cassandra at Mahalo
* Cassandra at CloudKick
|
PHP Thrift library for CassandraMike Peters, August 6, 2010 -- Posted under Programming |
If you're using Cassandra over PHP, you are probably aware of several bugs in the PHP Thrift interface that get in the way.
Courtesy of Jonathan Ellis, here's a list of known patches you need to apply to your PHP Thrift library:
* https://issues.apache.org/jira/browse/THRIFT-347 (TSocket Timeout)
* https://issues.apache.org/jira/browse/THRIFT-638 (Block until recv timeout)
* https://issues.apache.org/jira/browse/THRIFT-780 (Prevent aborts)
* https://issues.apache.org/jira/browse/THRIFT-788 (Multiget more than 17 keys)
To make your life easier, you can download a patched version of Thrift 0.2 for PHP, with all patches applied, here.
-
A great presentation by Cliff Moon: Dealing with the Thrift API
View 2 Comment(s)
Courtesy of Jonathan Ellis, here's a list of known patches you need to apply to your PHP Thrift library:
* https://issues.apache.org/jira/browse/THRIFT-347 (TSocket Timeout)
* https://issues.apache.org/jira/browse/THRIFT-638 (Block until recv timeout)
* https://issues.apache.org/jira/browse/THRIFT-780 (Prevent aborts)
* https://issues.apache.org/jira/browse/THRIFT-788 (Multiget more than 17 keys)
To make your life easier, you can download a patched version of Thrift 0.2 for PHP, with all patches applied, here.
-
A great presentation by Cliff Moon: Dealing with the Thrift API
View 2 Comment(s)
|
Cassandra PHP Wrapper 0.7Mike Peters, July 29, 2010 -- Posted under Programming |
A new version of the SoftwareProjects Cassandra PHP Wrapper (db_cassandra.php) is now available, for Cassandra 0.7.
This version of the PHP Wrapper adds support for:
* Adding Keyspaces and Column families on the fly
* Better error logging
* Disconnect on destructor to prevent java fd leaks
* Reconnect on timeout, up to 10 times
* Deletes
* Updated all API calls to 0.7
You can download the Cassandra 0.7 PHP wrapper, modify and distribute it freely.
Please let us know if you find any issues.
Usage Examples
Adding a new Keyspace with one column family
// Initialize Cassandra
$cassandra = new CassandraDB("mytest_keyspace");
// Debug on
$cassandra->SetDisplayErrors(true);
// Prepare Column Family
// (You can add as many as you need to the cfdef array)
$cfdef = null;
$record = array();
$record['keyspace'] = "mytest_keyspace";
$record['name'] = "mytable";
$record['column_type'] = "Standard";
$record['comparator_type'] = "BytesType";
$record['row_cache_size'] = 0;
$record['key_cache_size'] = 0.01;
$cfdef[] = new cassandra_CfDef($record);
// Add keyspace with one columnfamily
$result = $cassandra->AddKeyspace($cfdef);
Adding records and reading back values
// Initialize Cassandra
$cassandra = new CassandraDB("mytest_keyspace");
// Debug on
$cassandra->SetDisplayErrors(true);
// Set our key
$key = "Mike at softwareprojects.com";
// Insert record ("Columns" in Cassandra)
$record = array();
$record["name"] = "Mike Peters";
$record["email"] = "mike at softwareprojects.com";
if ($cassandra->InsertRecord('mytable', $key, $record))
{
echo "Record (Columns) inserted successfully.\r\n";
}
// Print record
$record = $cassandra->GetRecordByKey('mytable', $key);
print_r($record);
Setup tips
The PHP Wrapper was tested with the 0.7 trunk version, June 30, 2010 build.
Make sure you patch your Thrift TSocket as described here (comments section).
-
Further Reading
If you're just getting started with Cassandra, you'll enjoy the selection of hand picked Cassandra tutorials listed below. These are the best of the best:
= Tutorials
* Start here: WTF is a SuperColumn
* Cassandra Basics - Indexing
* Introduction to Cassandra
* History of Cassandra (Video)
* The shift to NoSQL
= Case Studies
* Scaling Twitter with Cassandra
* Cassandra at Digg
* Cassandra at RackSpace
= Internals
* How Reads work in Cassandra
* How Writes work in Cassandra
* Cassandra Replication and Consistency
* Random Partitioner vs Order Preserving Partitioner (OPP)
* Cassandra 101
* Do you really need SQL to do it all in Cassandra
* Let's play with Cassandra
View 11 Comment(s)
This version of the PHP Wrapper adds support for:
* Adding Keyspaces and Column families on the fly
* Better error logging
* Disconnect on destructor to prevent java fd leaks
* Reconnect on timeout, up to 10 times
* Deletes
* Updated all API calls to 0.7
You can download the Cassandra 0.7 PHP wrapper, modify and distribute it freely.
Please let us know if you find any issues.
Usage Examples
Adding a new Keyspace with one column family
// Initialize Cassandra
$cassandra = new CassandraDB("mytest_keyspace");
// Debug on
$cassandra->SetDisplayErrors(true);
// Prepare Column Family
// (You can add as many as you need to the cfdef array)
$cfdef = null;
$record = array();
$record['keyspace'] = "mytest_keyspace";
$record['name'] = "mytable";
$record['column_type'] = "Standard";
$record['comparator_type'] = "BytesType";
$record['row_cache_size'] = 0;
$record['key_cache_size'] = 0.01;
$cfdef[] = new cassandra_CfDef($record);
// Add keyspace with one columnfamily
$result = $cassandra->AddKeyspace($cfdef);
Adding records and reading back values
// Initialize Cassandra
$cassandra = new CassandraDB("mytest_keyspace");
// Debug on
$cassandra->SetDisplayErrors(true);
// Set our key
$key = "Mike at softwareprojects.com";
// Insert record ("Columns" in Cassandra)
$record = array();
$record["name"] = "Mike Peters";
$record["email"] = "mike at softwareprojects.com";
if ($cassandra->InsertRecord('mytable', $key, $record))
{
echo "Record (Columns) inserted successfully.\r\n";
}
// Print record
$record = $cassandra->GetRecordByKey('mytable', $key);
print_r($record);
Setup tips
The PHP Wrapper was tested with the 0.7 trunk version, June 30, 2010 build.
Make sure you patch your Thrift TSocket as described here (comments section).
-
Further Reading
If you're just getting started with Cassandra, you'll enjoy the selection of hand picked Cassandra tutorials listed below. These are the best of the best:
= Tutorials
* Start here: WTF is a SuperColumn
* Cassandra Basics - Indexing
* Introduction to Cassandra
* History of Cassandra (Video)
* The shift to NoSQL
= Case Studies
* Scaling Twitter with Cassandra
* Cassandra at Digg
* Cassandra at RackSpace
= Internals
* How Reads work in Cassandra
* How Writes work in Cassandra
* Cassandra Replication and Consistency
* Random Partitioner vs Order Preserving Partitioner (OPP)
* Cassandra 101
* Do you really need SQL to do it all in Cassandra
* Let's play with Cassandra
View 11 Comment(s)
|
Mercurial Hook: PHP Syntax CheckMike Peters, June 16, 2010 -- Posted under Programming |
In a previous post, we wrote about PHP real time syntax checking. A method to send email alerts when any critical scripts on your live servers fail to pass PHP syntax validation.
The problem with this approach is that it alerts you of a problem after-the-fact.
Someone uploads a bad PHP script which breaks a critical module, you are alerted, but by that time users are already affected.
Today we'll take it this concept one step further by writing a hook for the Mercurial version control system, preventing developers from checking-in scripts that don't pass syntax-checking.
Installing PHP Syntax Check Mercurial hook
Step 1: The shell script
Save this shell script under your Mercurial folder, calling it: php_syntax.sh
Step 2: Add hook to Mercurial config file
Update your Mercurial hgweb.config, adding the new hook under the 'hooks' section, like this:
[hooks]
pretxnchangegroup.syntax_check = /usr/home/mercurial/php_syntax.sh
--
Replace '/usr/home/mercurial' with the path where you saved php_syntax.sh
Attempting to push changes to the repository that don't pass php-syntax check, are now blocked.
Users will be presented with an error message and the transaction rolled back, until the user fixes the problem and pushes changes again.
View 5 Comment(s)
The problem with this approach is that it alerts you of a problem after-the-fact.
Someone uploads a bad PHP script which breaks a critical module, you are alerted, but by that time users are already affected.
Today we'll take it this concept one step further by writing a hook for the Mercurial version control system, preventing developers from checking-in scripts that don't pass syntax-checking.
Installing PHP Syntax Check Mercurial hook
Step 1: The shell script
Save this shell script under your Mercurial folder, calling it: php_syntax.sh
#!/usr/local/bin/bash
echo "STARTING PHP SYNTAX CHECK..."
# create a random temp file
temp_file=`/usr/bin/mktemp -t php_syntax_files`
# get all modified files and remove duplicate's
#note: use file_mods,file_adds instead
hg log -r $HG_NODE:tip --template "{files}\n" | sort | uniq > $temp_file
# Walk through each line
#for line in "$temp_file"; do
for line in $(< $temp_file); do
# Make sure it is a php file
if [ `echo $line | grep -E "\.(php)|(php4)|(php5)$"` ]
then
# create a random temp file
php_file=`/usr/bin/mktemp -t php_syntax_check`
# save the contents of this file (latest commit) to the temp file
hg cat -r tip $line > $php_file
# check the syntax
php_syntax_output=`/usr/local/bin/php-cgi -l -d display_errors=1 -d error_reporting=4 -d html_errors=0 < $php_file`;
# remove the temp file
rm -f $php_file;
test_syntax=`echo $php_syntax_output | grep "Parse error"`
if [ "$test_syntax" ];then
exit 1;
fi
fi
done
rm -f "$temp_file"
echo "STARTING PHP SYNTAX CHECK..."
# create a random temp file
temp_file=`/usr/bin/mktemp -t php_syntax_files`
# get all modified files and remove duplicate's
#note: use file_mods,file_adds instead
hg log -r $HG_NODE:tip --template "{files}\n" | sort | uniq > $temp_file
# Walk through each line
#for line in "$temp_file"; do
for line in $(< $temp_file); do
# Make sure it is a php file
if [ `echo $line | grep -E "\.(php)|(php4)|(php5)$"` ]
then
# create a random temp file
php_file=`/usr/bin/mktemp -t php_syntax_check`
# save the contents of this file (latest commit) to the temp file
hg cat -r tip $line > $php_file
# check the syntax
php_syntax_output=`/usr/local/bin/php-cgi -l -d display_errors=1 -d error_reporting=4 -d html_errors=0 < $php_file`;
# remove the temp file
rm -f $php_file;
test_syntax=`echo $php_syntax_output | grep "Parse error"`
if [ "$test_syntax" ];then
exit 1;
fi
fi
done
rm -f "$temp_file"
Step 2: Add hook to Mercurial config file
Update your Mercurial hgweb.config, adding the new hook under the 'hooks' section, like this:
[hooks]
pretxnchangegroup.syntax_check = /usr/home/mercurial/php_syntax.sh
--
Replace '/usr/home/mercurial' with the path where you saved php_syntax.sh
Attempting to push changes to the repository that don't pass php-syntax check, are now blocked.
Users will be presented with an error message and the transaction rolled back, until the user fixes the problem and pushes changes again.
View 5 Comment(s)
| « Previous Posts | » Next Posts |
