{"componentChunkName":"component---src-templates-blog-list-jsx","path":"/blog/23/","result":{"data":{"prismic":{"allFeaturedblogs":{"edges":[{"node":{"featured_blogs_enabled":true,"heading":[{"type":"paragraph","text":"Featured posts","spans":[]}],"featured_blog_1":{"__typename":"PRISMIC_Blog","_linkType":"Link.document","blog_header_image":{"dimensions":{"width":790,"height":395},"alt":null,"copyright":null,"url":"https://images.prismic.io/www-static/6d8d81b1-971a-4313-b033-b4e125cb14a0_MondoDB-blog-header-790x395.PNG?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"Introducing DigitalOcean Managed MongoDB – a fully managed, database as a service for modern apps","spans":[]}],"blog_post_date":"2021-06-29","blog_post_content":[{"type":"paragraph","text":"MongoDB is one of the most popular databases, and it’s ideal for apps that evolve rapidly and need to handle huge volumes of data and traffic. It offers advantages like flexible document schemas, code-native data access, change-friendly design, and easy horizontal scale-out.","spans":[{"start":22,"end":44,"type":"hyperlink","data":{"link_type":"Web","url":"https://db-engines.com/en/ranking","target":"_blank"}}]},{"type":"paragraph","text":"However, building and maintaining MongoDB clusters from the ground up can be a huge undertaking. Developers often complain that they have to spend their valuable time and resources on database management. Well, we’ve been listening and have some great news: accessing and managing MongoDB on DigitalOcean just got a lot simpler!","spans":[]},{"type":"paragraph","text":"We are excited to announce that DigitalOcean Managed MongoDB is now in General Availability. Managed MongoDB is a fully managed, database as a service (DBaaS) offering from DigitalOcean, built in partnership with and certified by MongoDB Inc. It provides you all the technical capabilities that make MongoDB so beloved in the developer community. Together we have ensured that you will get access to all the latest releases of the MongoDB document database as they become available.","spans":[{"start":32,"end":91,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/products/managed-databases-mongodb/"}},{"start":230,"end":241,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.mongodb.com/","target":"_blank"}}]},{"type":"paragraph","text":"Managed MongoDB simplifies the MongoDB administration. Developers of all skill levels, even those who do not have prior experience in databases, can spin up MongoDB clusters in just a few minutes. We handle the provisioning, managing, scaling, updates, backups, and security of your MongoDB clusters, allowing you to offload the complex, time consuming –yet critical – database administration tasks to us. This empowers you to focus on what really matters: building awesome apps.","spans":[]},{"type":"embed","oembed":{"height":113,"width":200,"embed_url":"https://www.youtube.com/watch?v=NvHQSV7jnKA","type":"video","version":"1.0","title":"Create a MongoDB Database on DigitalOcean","author_name":"DigitalOcean","author_url":"https://www.youtube.com/c/Digitalocean","provider_name":"YouTube","provider_url":"https://www.youtube.com/","cache_age":null,"thumbnail_url":"https://i.ytimg.com/vi/NvHQSV7jnKA/hqdefault.jpg","thumbnail_width":480,"thumbnail_height":360,"html":"<iframe width=\"200\" height=\"113\" src=\"https://www.youtube.com/embed/NvHQSV7jnKA?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe>"}},{"type":"heading2","text":"Benefits of Managed MongoDB","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"list-item","text":"Easy set up and maintenance: We create the database clusters for you. Simply choose the cluster configuration (e.g., memory, disk size, number of nodes, etc.), and the data center in which you want to host the database. Follow a few simple steps and your database cluster will be up and running in a matter of minutes. You can spin up clusters using the cloud control panel, CLI, or API.\n\n","spans":[{"start":0,"end":28,"type":"strong"}]},{"type":"list-item","text":"Automatic daily backups with point in time recovery: Data is one of the most important assets of an app, so it’s critical to backup your database. We take backups of your entire clusters automatically on a daily basis, for free. We also provide a point in time recovery for 7 days, that way if things go wrong due to human error, machine error, or some combination of both, you can easily restore the database as it was at any point in the previous 7 days. \n\n","spans":[{"start":0,"end":52,"type":"strong"}]},{"type":"list-item","text":"Automatic updates and access to latest MongoDB releases: You get access to MongoDB 4.4. This is the latest release of MongoDB and comes packed with numerous enhancements like hedged reads, rust, and swift drivers. Since we have developed Managed MongoDB in partnership with MongoDB Inc, you will always get access to new releases as they become available. With Managed MongoDB, the updates happen automatically. Just select a date and time for the updates and we take care of the rest. This makes it easy to stay up to date with MongoDB releases without disrupting your business.\n\n","spans":[{"start":0,"end":56,"type":"strong"},{"start":148,"end":169,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.mongodb.com/new","target":"_blank"}}]},{"type":"list-item","text":"High availability with automated failover: If your database goes down, it can take down the entire app, leading to bad customer experiences. With Managed MongoDB, you can easily minimize the downtime for your database and make it highly available with standby nodes. Standby nodes add redundancy, so if for example the primary node fails, the standby node is immediately promoted to primary and begins serving requests while we provision a replacement standby node in the background.\n\n","spans":[{"start":0,"end":42,"type":"strong"}]},{"type":"list-item","text":"Scale up easily to handle traffic spikes: As your app gains traction and the usage grows, it’s important to have a database that can keep up with the increased demand. With Managed MongoDB, you can easily scale up the size of database nodes when needed.\n\n","spans":[{"start":0,"end":41,"type":"strong"}]},{"type":"list-item","text":"Secure by default: Since data is critical, it also needs to be secure. We encrypt data at rest with LUKS and in transit with SSL. When you create a new cluster, it’s placed in a VPC network by default that provides a more secure connection between resources. You can also restrict access to your nodes to prevent brute-force password and denial-of-service attacks.","spans":[{"start":0,"end":18,"type":"strong"},{"start":178,"end":189,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/docs/networking/vpc/"}}]},{"type":"heading2","text":"The need for Managed Databases","spans":[]},{"type":"paragraph","text":"DigitalOcean’s mission is to simplify cloud computing so developers, startups, and SMBs can spend more time building software that changes the world. While databases are a critical component to any application, building, maintaining, and scaling them can be complex and time consuming. For developers that are building apps for their business, database administration is often not a core focus area. But it’s quite common to find developers that write the code and then also roll up their sleeves to maintain databases. Such users would rather offload the tedious database administration and focus their limited time and energy on building and enhancing their apps. ","spans":[]},{"type":"paragraph","text":"With this in mind, we introduced Managed Databases a couple of years ago and are excited to add Managed MongoDB to our portfolio. With this release, DigitalOcean Managed Databases now supports the following engines:","spans":[{"start":33,"end":50,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/products/managed-databases/"}}]},{"type":"image","url":"https://images.prismic.io/www-static/87745cc1-1c5f-4463-b104-104b7fc30dc7_managed-databases-logos.png?auto=compress,format","alt":null,"copyright":null,"dimensions":{"width":849,"height":104}},{"type":"paragraph","text":"Managed MongoDB launch comes on the heels of DigitalOcean App Platform, a modern, reimagined PaaS (Platform as a Service) that we released a few months ago. App Platform makes it very easy to build, deploy, and scale apps and static sites. You can deploy code by simply pointing to your GitHub and GitLab repos, and App Platform will do all the heavy lifting of managing infrastructure, app runtimes, and dependencies. App Platform, along with Managed Databases, helps fulfill DigitalOcean’s mission by empowering developers, startups, and SMBs to focus more on their apps, and less on the underlying infrastructure and databases.","spans":[{"start":45,"end":70,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/products/app-platform/"}}]},{"type":"heading2","text":"How Managed MongoDB works","spans":[]},{"type":"paragraph","text":"DigitalOcean provides you with various compute options to build your apps like:","spans":[]},{"type":"list-item","text":"Droplets: On-demand, Linux virtual machines suitable for production business applications and personal passion projects.","spans":[{"start":0,"end":8,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/products/droplets/"}}]},{"type":"list-item","text":"DigitalOcean Kubernetes: Managed Kubernetes with automatic scaling, upgrades, and a free control plane.","spans":[{"start":0,"end":23,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/products/kubernetes/"}}]},{"type":"list-item","text":"DigitalOcean App Platform: A fully managed Platform as a Service.","spans":[{"start":0,"end":25,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/products/app-platform/"}}]},{"type":"paragraph","text":"No matter which compute option you choose to build your apps, you can easily add Managed MongoDB to it. In addition to this, Managed MongoDB also integrates with the Node.js 1-Click App from DigitalOcean Marketplace making it a lot easier to build Node.js apps.","spans":[{"start":166,"end":215,"type":"hyperlink","data":{"link_type":"Web","url":"https://marketplace.digitalocean.com/apps/nodejs"}}]},{"type":"heading2","text":"Simple, predictable pricing","spans":[]},{"type":"paragraph","text":"Just like all DigitalOcean products, Managed MongoDB provides simple, predictable pricing that allows you to control costs and prevent any surprise bills. You can spin up a database cluster for just $15/month, or a highly available three-node replica set for $45/month. Click here for more information.","spans":[{"start":270,"end":301,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/pricing/#managed-databases"}}]},{"type":"heading2","text":"Regional availability","spans":[]},{"type":"paragraph","text":"Managed MongoDB is currently available in the following regions:","spans":[]},{"type":"list-item","text":"NYC3 (New York, USA)","spans":[]},{"type":"list-item","text":"FRA1 (Frankfurt, Germany)","spans":[]},{"type":"list-item","text":"AMS3 (Amsterdam, Netherlands)","spans":[]},{"type":"paragraph","text":"We will be making Managed Mongo available in other regions soon. Please check out the release notes for most up to date information on regional availability.","spans":[{"start":86,"end":99,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/docs/release-notes/"}}]},{"type":"heading2","text":"Join us at deploy, DigitalOcean’s virtual user conference","spans":[]},{"type":"paragraph","text":"Today we have deploy, DigitalOcean’s signature user conference, which focuses on celebrating, educating, and connecting awesome builders from all over the world.","spans":[{"start":14,"end":20,"type":"hyperlink","data":{"link_type":"Web","url":"https://deploy.digitalocean.com/home"}}]},{"type":"paragraph","text":"Check out the keynote session from DigitalOcean's CEO, Yancey Spruill, in which he talks about where we're headed as a company and shares some exciting product updates. His keynote will be followed by sessions from community members, engineers, customers, and other experts that are building technologies and businesses powered by the cloud. With live Q&A and an active Discord server, there’s ample opportunity to engage and learn something new. Click here to attend the deploy conference.","spans":[{"start":14,"end":69,"type":"hyperlink","data":{"link_type":"Web","url":"https://deploy.digitalocean.com/agenda/session/552806"}},{"start":347,"end":384,"type":"hyperlink","data":{"link_type":"Web","url":"http://do.co/deploy-discord"}},{"start":461,"end":489,"type":"hyperlink","data":{"link_type":"Web","url":"http://do.co/deploy"}}]},{"type":"paragraph","text":"We are also launching a hackathon for DigitalOcean Managed MongoDB. Learn how you can participate, submit an app and get a t-shirt.","spans":[{"start":24,"end":66,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/mongodb-hackathon"}}]},{"type":"paragraph","text":"We hope you will give Managed MongoDB a try. Here are some sample datasets and sample apps that you can use to kick the tires. Check out the docs and let us know what you think!","spans":[{"start":22,"end":43,"type":"hyperlink","data":{"link_type":"Web","url":"https://cloud.digitalocean.com/databases/new?engine=mongodb"}},{"start":59,"end":90,"type":"hyperlink","data":{"link_type":"Web","url":"https://github.com/do-community/mongodb-resources","target":"_blank"}},{"start":141,"end":145,"type":"hyperlink","data":{"link_type":"Web","url":"https://docs.digitalocean.com/products/databases/mongodb/"}}]},{"type":"paragraph","text":"If you’d like to have a conversation about using DigitalOcean and Managed MongoDB in your business, please feel free to contact our sales team.","spans":[{"start":120,"end":142,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/company/contact/sales/"}}]},{"type":"paragraph","text":"Happy coding!","spans":[]},{"type":"paragraph","text":"André Bearfield","spans":[]},{"type":"paragraph","text":"Director of Product Management","spans":[]}],"tags":[{"tag1":{"__typename":"PRISMIC_Tag","tag":"Product Updates","_linkType":"Link.document","_meta":{"uid":"product-updates"}}}],"author":{"__typename":"PRISMIC_Author","author_name":"André Bearfield","author_image":{"dimensions":{"width":553,"height":547},"alt":"André Bearfield","copyright":null,"url":"https://images.prismic.io/www-static/fdc7c85186f0a850b04083e1d4306bd1c19772e8_andre-bearfield.png?auto=compress,format"},"_meta":{"uid":"andre-bearfield"}},"_meta":{"uid":"introducing-digitalocean-managed-mongodb"}},"featured_blog_2":{"__typename":"PRISMIC_Blog","_linkType":"Link.document","blog_header_image":{"dimensions":{"width":790,"height":400},"alt":"Droplet Console","copyright":null,"url":"https://images.prismic.io/www-static/710499ae-78cc-4179-afc1-15793637b200_DODX3727-790x400-logo-2.jpg?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"Securely connect to Droplets with SSH key pairs using a new Droplet Console","spans":[]}],"blog_post_date":"2021-08-10","blog_post_content":[{"type":"paragraph","text":"The famous author Ken Blanchard once said, “Feedback is the breakfast of champions.\" This is something we truly believe at DigitalOcean, and we always strive to enhance our products based on customer feedback.","spans":[]},{"type":"paragraph","text":"With this goal in mind, we are excited to introduce a new Droplet Console that will make it much easier to connect to your Droplets securely. The new Droplet Console provides one-click SSH access to your Droplets through a native-like SSH/Terminal experience. It also eliminates the need for a password or manual configuration of SSH keys. Starting today, we’re pleased to announce that the new Droplet Console is now available to all Droplet users.","spans":[]},{"type":"heading2","text":"Why you should be using Secure Shell (SSH) ","spans":[]},{"type":"paragraph","text":"Password-based security is notoriously insecure due to password fatigue and the overuse of passwords such as ‘123456’. Secure Shell or SSH is a network communication protocol that solves this by using passwordless solutions for encryption, enabling two computers to communicate and securely share data. At a high level, SSH works by creating cryptographic key pairs consisting of a public and private key, which are computer generated and stored separately to ensure their security. ","spans":[{"start":80,"end":117,"type":"hyperlink","data":{"link_type":"Web","url":"https://cybernews.com/best-password-managers/most-common-passwords/"}}]},{"type":"paragraph","text":"SSH has become the default encryption protocol for many industries, but it was difficult to use SSH keys with DigitalOcean’s current Recovery (VNC) console, which is why we developed our new Droplet Console. The new Droplet Console is backed by an agent that security supervises the key pair, while also providing one-click SSH access to our users. You can see the full list of features below.","spans":[]},{"type":"heading2","text":"The new Droplet Console: More time saving, less time wasting ","spans":[]},{"type":"paragraph","text":"The new Droplet Console is for everyone who is looking to build fast, secure apps and avoid hassles with SSH access & usability issues.","spans":[]},{"type":"paragraph","text":"In addition to easier SSH access, the new Droplet Console comes with:","spans":[]},{"type":"list-item","text":"Copy/paste text: Instead of typing lengthy key pairs and text manually, you can use copy/paste to save time. ","spans":[{"start":0,"end":17,"type":"strong"}]},{"type":"list-item","text":"Multi-color support: Multi-color support makes the console more useful and intuitive, and breaks the conventional standard appearance which is black text on a white background. ","spans":[{"start":0,"end":41,"type":"strong"}]},{"type":"list-item","text":"Multi-language support: DigitalOcean’s new Droplet Console supports multiple languages, meaning you can now type and view any content in any language that is supported by UTF-8","spans":[{"start":0,"end":24,"type":"strong"}]},{"type":"list-item","text":"OS/images supported: Linux distributions (Ubuntu(16.04 - 20.04), Fedora (32 & 33), Debian (9), CentOS (7.6 & 8.3), CentOS 8 Stream, Rocky Linux and Marketplace images.","spans":[{"start":0,"end":20,"type":"strong"},{"start":148,"end":159,"type":"hyperlink","data":{"link_type":"Web","url":"https://marketplace.digitalocean.com/"}}]},{"type":"paragraph","text":"The new Droplet Console is available by default on any new Droplets you spin up. You can also enable it manually on older Droplets. Click here to learn more!","spans":[{"start":132,"end":157,"type":"hyperlink","data":{"link_type":"Web","url":"https://docs.digitalocean.com/products/droplets/how-to/connect-with-console/"}}]},{"type":"paragraph","text":"Check out this short walkthrough video that shows the new Droplet Console in action: ","spans":[]},{"type":"embed","oembed":{"type":"video","embed_url":"https://www.youtube.com/watch?v=Qt7QihVuxiE","title":"Access Your Droplet Terminal Through the Web Console","provider_name":"YouTube","thumbnail_url":"https://i.ytimg.com/vi/Qt7QihVuxiE/hqdefault.jpg","provider_url":"https://www.youtube.com/","author_name":"DigitalOcean","author_url":"https://www.youtube.com/c/Digitalocean","height":113,"width":200,"version":"1.0","thumbnail_height":360,"thumbnail_width":480,"html":"<iframe width=\"200\" height=\"113\" src=\"https://www.youtube.com/embed/Qt7QihVuxiE?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe>"}},{"type":"paragraph","text":"We hope you’re excited about the new Droplet Console. You’re welcome to spin some Droplets up right now, and try out the new Droplet Console – why wait?","spans":[{"start":72,"end":103,"type":"hyperlink","data":{"link_type":"Web","url":"https://cloud.digitalocean.com/droplets/new"}}]},{"type":"paragraph","text":"Happy coding!","spans":[]},{"type":"paragraph","text":"Harsh Banwait, Senior Product Manager","spans":[]}],"tags":[{"tag1":{"__typename":"PRISMIC_Tag","tag":"Product Updates","_linkType":"Link.document","_meta":{"uid":"product-updates"}}}],"author":{"__typename":"PRISMIC_Author","author_name":"Harsh Banwait","author_image":{"dimensions":{"width":600,"height":399},"alt":null,"copyright":null,"url":"https://images.prismic.io/www-static/e83ff690-b20c-4d88-a2b6-57e562558cd6_download.png?auto=compress,format"},"_meta":{"uid":"harsh-banwait"}},"_meta":{"uid":"new-droplet-console-ssh-support"}},"featured_blog_3":{"__typename":"PRISMIC_Blog","_linkType":"Link.document","blog_header_image":{"dimensions":{"width":790,"height":400},"alt":null,"copyright":null,"url":"https://images.prismic.io/www-static/588e28d3-d41e-480b-937b-8c3b19201f6e_DODX3568-790x400-Blog.jpg?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"How to scale your SaaS product without breaking the bank","spans":[]}],"blog_post_date":"2021-06-22","blog_post_content":[{"type":"paragraph","text":"These days, if you are in the business of software, chances are you are delivering or plan to deliver your services using a Software-as-a-Service (SaaS) model. A combination of internet-based delivery, subscription-based pricing, and low-friction product experiences have made SaaS solutions valuable tools for their users, and an excellent vehicle for software builders looking to distribute their products.","spans":[]},{"type":"paragraph","text":"These factors have made SaaS solutions ubiquitous; SaaS is the largest segment in the public cloud market, and is used to provide functionality ranging from personal finance apps for consumers, to productivity software for businesses, and even tools and services for software developers themselves to compose their applications and simplify their workflows. It is also not uncommon to find micro-SaaS applications being built for specific industries such as retail, job functions such as accounting or marketing, or tasks such as event management. ","spans":[]},{"type":"paragraph","text":"The best thing about this SaaS wave has been that it has allowed a new generation of software builders to build and monetize applications and participate in the digital economy. Previously, you had to be a big company with lots of resources, name recognition and distribution networks to successfully sell software products. Now, irrespective of whether you are a single person working on a passion project, a small team of developers in a startup, or a small and medium-sized business (SMB), the SaaS model enables you to express your ideas in the form of software and deliver them to customers anywhere in the world.","spans":[]},{"type":"heading2","text":"The unique challenges of building SaaS solutions","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"Despite the opportunities that come with the widespread adoption of SaaS products, software builders still have to answer key questions in their journey to building successful SaaS products. Understanding what customers to target, features to prioritize, how to price your product, and how to acquire customers are all critical questions to figure out while you are also doing the important job of actually building and operating the product. ","spans":[]},{"type":"paragraph","text":"Writing the code, testing, deployment, monitoring the usage in production, and ensuring that your apps are able to handle the additional demand when customer base and usage grows are all essential and time-consuming tasks.","spans":[]},{"type":"paragraph","text":"Additionally, being able to test multiple ideas, pivot, and double down on the ideas that actually work is critical in early stages of SaaS development. Once growth comes, it is equally important to scale up without compromising on performance or reliability. Needless to say, all of this needs to be economically viable as well, since not everyone has the resources of large SaaS providers like Salesforce or Adobe.","spans":[]},{"type":"heading2","text":"Cloud Computing enables builders but also poses challenges","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"Fortunately, for the act of building and operating your apps, cloud computing can help take some load off your shoulders. Unless you have the scale and resources of Facebook, chances are you are not going to set up your own data centers to host the computing infrastructure that powers your SaaS company. Public cloud infrastructure providers can bring great value to SaaS builders by providing on-demand computing services with usage-based pricing. However, just like how the legacy software companies weren't built for the SaaS model, the early (and big) cloud computing services were not optimized for the unique needs of small SaaS building teams. ","spans":[]},{"type":"paragraph","text":"Smaller SaaS teams face challenges with large cloud computing providers, including:","spans":[]},{"type":"heading4","text":"Too many technology options","spans":[]},{"type":"paragraph","text":"There are just too many options for tech stacks on which to build your SaaS - programming languages, application development frameworks, libraries, runtime environments, architectural patterns, and deployment models - and the list is growing by the day.","spans":[]},{"type":"heading4","text":"Complexity of cloud computing services","spans":[]},{"type":"paragraph","text":"Even when you have decided on a technology stack, there is a lot of cloud vendor-specific terminology you need to learn and heavy lifting you need to do to build on the cloud, not all of which contributes to making your SaaS applications successful.","spans":[]},{"type":"heading4","text":"Unpredictable costs","spans":[]},{"type":"paragraph","text":"The experimentation necessary in early stages of SaaS development, as well as the scaling of applications required during the growth phase, call for affordable and predictable pricing from your cloud provider. The last thing SaaS teams want is surprising and indecipherable bills from your cloud provider. Unfortunately, smaller businesses often experience unpredictable costs with cloud providers who are busy serving only the large enterprises.","spans":[]},{"type":"heading2","text":"DigitalOcean provides a simple, cost effective solution for SaaS builders","spans":[]},{"type":"paragraph","text":"Fortunately, at DigitalOcean we have a laser focus on small software development teams, who are trying to build the next generation of applications. Today, DigitalOcean customers are already building SaaS applications which serve all kinds of customers.","spans":[{"start":191,"end":217,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/solutions/saas/"}}]},{"type":"paragraph","text":"We believe SaaS builders should focus on building apps that power their business, and not spend their valuable time on managing infrastructure. That is exactly what we have been able to enable through our intuitive products that are built for scale and reliability.","spans":[{"start":205,"end":223,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/products/"}}]},{"type":"list-item","text":"Vidazoo is an advertising technology company specializing in video streaming and serving. It serves video ads to thousands of websites and handles close to 10 billion requests per day. \n\n“We are as much a data company as an adtech company. Our business relies on speedy and accurate data processing at massive scale. DigitalOcean provides us the perfect set of tools to operate our SaaS business profitably, while not making us feel the need to become full time system administrators. We plan to move a lot of our apps to DigitalOcean App Platform and other fully managed products.” - Roman Svichar, CTO of Vidazoo","spans":[{"start":0,"end":7,"type":"hyperlink","data":{"link_type":"Web","url":"https://vidazoo.com/"}},{"start":187,"end":583,"type":"em"}]},{"type":"paragraph","text":"We believe in meeting customers where they are. If they already have an understanding of cloud infrastructure technologies, they should be able to leverage that knowledge and get started with our products without any further ramp up.","spans":[]},{"type":"list-item","text":"Whatfix is an enterprise SaaS provider that offers a digital adoption platform to businesses. The company helps enterprises gain the full value of their investments in enterprise applications by providing real-time, interactive, and contextual guidance to users of those applications. \n\n“What we really love about the DigitalOcean platform is the ease of use. We feel like we know infrastructure and can handle most of the configuration and management. What we needed from a cloud was not bells and whistles but efficiency and reliability. DigitalOcean provides us a platform to build our apps and then gets out of the way. Just how we like it.” - Achyuth Krishna, Director of Engineering of Whatfix","spans":[{"start":0,"end":7,"type":"hyperlink","data":{"link_type":"Web","url":"https://whatfix.com/blog/driving-the-future-now-were-excited-to-announce-our-90-million-series-d-funding/"}},{"start":287,"end":648,"type":"em"}]},{"type":"paragraph","text":"We understand that scaling while maintaining reliability of applications and profitability of business is important, so we provide robust solutions which minimize downtime.","spans":[]},{"type":"list-item","text":"Centra is a SaaS-based e-commerce platform for global direct-to-consumer and wholesale e-commerce brands. Centra provides a powerful e-commerce backend that lets brands build pixel-perfect, custom designed, online flagship stores. \n\n“How do we enable our customers to create differentiated online experiences? How do we ensure their e-commerce apps stay up and running at all times? How do we scale on-demand when traffic grows or new customers come in? These are the questions that we ask ourselves every day. Thankfully, we have a partner in DigitalOcean that provides just the platform to answer those questions enabling us to guarantee 99.9% uptime for our clients.” - Martin Jensen, CEO of Centra","spans":[{"start":0,"end":6,"type":"hyperlink","data":{"link_type":"Web","url":"https://centra.com/"}},{"start":233,"end":673,"type":"em"}]},{"type":"paragraph","text":"These are just a few examples of SaaS businesses finding success on DigitalOcean. We are constantly amazed by the creativity and innovation that software builders are utilizing our platform for. If you are interested in learning more about product updates, technical deep-dives and best practices for building SaaS products and businesses, please contact us to learn how we can help you get started. ","spans":[{"start":340,"end":357,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/migrate/?utmmedium=blog","target":"_blank"}}]},{"type":"paragraph","text":"Come build with DigitalOcean!","spans":[]},{"type":"paragraph","text":"Looking to migrate your SaaS to DigitalOcean? Leverage free infrastructure credits, robust training, and technical support to ensure a worry-free migration.","spans":[{"start":0,"end":156,"type":"strong"},{"start":0,"end":156,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/migrate/?utmmedium=blog","target":"_blank"}}]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"Raman Sharma","spans":[]},{"type":"paragraph","text":"Vice President, Product & Programs Marketing","spans":[]}],"tags":[{"tag1":{"__typename":"PRISMIC_Tag","tag":"Developer Relations","_linkType":"Link.document","_meta":{"uid":"developer-relations"}}}],"author":{"__typename":"PRISMIC_Author","author_name":"Raman Sharma","author_image":{"dimensions":{"width":512,"height":512},"alt":null,"copyright":null,"url":"https://images.prismic.io/www-static/497b4b14-d192-493a-8b66-7ae176ba99f3_raman.png?auto=compress,format"},"_meta":{"uid":"raman-sharma"}},"_meta":{"uid":"how-to-scale-your-saas-product-without-breaking-the-bank"}}}}]}}},"pageContext":{"limit":12,"skip":264,"numPages":33,"currentPage":23,"data":[{"node":{"author":{"_linkType":"Link.document","author_name":"Luca Salvatore","author_image":{"dimensions":{"width":250,"height":250},"alt":"Luca Salvatore","copyright":null,"url":"https://images.prismic.io/www-static/fd8fb2a54e8e54d882c33bccac82b22a684d920e_9bb2be860884302b74920173da25866a.jpg?auto=compress,format"},"_meta":{"uid":"luca_salvatore"}},"blog_header_image":{"dimensions":{"width":784,"height":418},"alt":"next generation of digital networking","copyright":null,"url":"https://images.prismic.io/www-static/76d24fe4-9a7c-4cfc-aed1-57e3956539a1_hero.png?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"Building the Next Generation of DigitalOcean Networking","spans":[]}],"blog_post_content":[{"type":"paragraph","text":"On April 15th, we opened our newest datacenter in Frankfurt. The blog post announcing FRA1 mentioned that the new datacenter was built using 40G networking and faster SSDs. What that blog didn't mention was that the entire network was actually redesigned from the ground up to allow us to grow and scale to some pretty impressive numbers. On top of that, we have also started retrofitting some of our older locations with this new design, which includes 40G networking and newer, faster hypervisors.","spans":[{"start":61,"end":90,"type":"hyperlink","data":{"link_type":"Web","url":"https://assets.digitalocean.com/blog/static/introducing-our-new-european-region-frankfurt/"}}]},{"type":"paragraph","text":"In this blog, we'll go into more detail about how we've been upgrading live DCs to the new architecture, and also take a look into how we are building out future datacenters.","spans":[]},{"type":"heading2","text":"Frankfurt's Design","spans":[]},{"type":"paragraph","text":"First, let's look at the at the new design that we used in Frankfurt. It is based on the widely used Clos topology which utilizes spine and leaf switches to build a highly scalable and redundant network. In this case, leaf switches are top of rack (TOR) switches, and spine switches act as an aggregation layer before heading into the core of the network.","spans":[]},{"type":"paragraph","text":"Here's how it all looks:","spans":[]},{"type":"image","url":"https://images.prismic.io/www-static/2661f8383196470a0ea2537161de1ba5256b1d84_fig1.png?auto=compress,format","alt":null,"copyright":null,"dimensions":{"width":1058,"height":290}},{"type":"paragraph","text":"The leaf switches in this diagram represent TOR switches. Each hypervisor in the rack has a 40G connection to both leaf switches. From there, every leaf switch connects to every spine (again, with 40G connections). This allows for huge amounts of bandwidth and provides a high level of redundancy.","spans":[]},{"type":"heading2","text":"Scaling the Network","spans":[]},{"type":"paragraph","text":"The diagram above only shows 4 pairs of leaf switches, which means 4 racks in this case. In reality, the number of racks each pod supports is limited to the number of ports in the spine. Each spine switch can have a maximum of 32 40G ports. We reserve some uplinks for the connections to the cores, so the number we work with is 12 racks per pod, i.e., 24 ports per spine. Once the spine is full, we scale out horizontally.","spans":[]},{"type":"paragraph","text":"This diagram shows another pod added, along with the connections up to the core:","spans":[]},{"type":"image","url":"https://images.prismic.io/www-static/41d67a2c6d708745b0e8db6f5e82a4217582bac0_fig2.jpg?auto=compress,format","alt":null,"copyright":null,"dimensions":{"width":1178,"height":505}},{"type":"paragraph","text":"Scaling the network out in this manner presents an interesting problem. All switches have limits on the amount of information they can hold. These are things like MAC addresses, ARPs entries, and routing information. In the core of our network, we are mainly concerned with the number of ARP entries that the core switches can store. The maximum number on the ARPs we support in the core is 256,000. While this may seem like a big number (and it is), only the biggest switches can support ARP tables that size.","spans":[]},{"type":"heading2","text":"Using Zones","spans":[]},{"type":"paragraph","text":"The solution to this problem is to split the network into zones. Where each pod has its own set of spine switches, each zone has its own set of core switches. Expanding on the diagram above, we can now have a network which looks like the diagram below, which also includes edge routers to show how two (or more) zones would connect to each other.","spans":[]},{"type":"image","url":"https://images.prismic.io/www-static/93d21a5e1b9f22378788e3e4065eb13a0ed14684_fig3.jpg?auto=compress,format","alt":null,"copyright":null,"dimensions":{"width":1182,"height":1102}},{"type":"paragraph","text":"With this design, we are now able to scale out the network horizontally. The limiting factor becomes the availability of ports on the edge routers. Because that count is quite large, this design will last us for some time to come. Each different level of the network is connected using 40G interfaces, including the hypervisors. In most cases, these are configured using aggregation (802.3ad), so the bandwidth could be 80G or even 160G at some points.","spans":[]},{"type":"heading2","text":"Current and Future DCs","spans":[]},{"type":"paragraph","text":"Using this design, it's very easy to retrofit our existing locations. We simply build out the network in new racks, and when it's all working, we connect the new cores to the edge routers, make some changes in our backend code, and the new zone is live!","spans":[]},{"type":"paragraph","text":"This new 40G design is what we will be using in all future DCs, and has already been deployed in FRA1, NYC1, and NYC3. We will also be adding this design into two more locations in the next few months. With this type of architecture, the DigitalOcean network will be able to continue to scale and serve our customers for many years to come.","spans":[]},{"type":"paragraph","text":"by Luca Salvatore","spans":[{"start":3,"end":17,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/_LucaNet"}}]}],"blog_post_date":"2015-08-25","tags":[{"tag1":{"tag":"Engineering","_linkType":"Link.document","_meta":{"uid":"engineering"}}}],"_meta":{"uid":"building-the-next-generation-of-digitalocean-networking"}}},{"node":{"author":{"_linkType":"Link.document","author_name":"Erika Heidi","author_image":null,"_meta":{"uid":"erika_heidi"}},"blog_header_image":{"dimensions":{"width":784,"height":418},"alt":"elephant super heros in masks flying with the words 'Get ready for PHP 7'","copyright":null,"url":"https://images.prismic.io/www-static/eda8fb19-1f01-4d9e-b729-59107e7fecf0_get_ready.jpg?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"Getting Ready for PHP 7","spans":[]}],"blog_post_content":[{"type":"paragraph","text":"2015 has been an important year for PHP. Eleven years after its 5.0 release, a new major version is finally coming our way! PHP 7 is scheduled for release before the end of the year, bringing many new language features and an impressive performance boost.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"But how will this impact your current PHP codebase? What really changed? How safe is it to update? This post will answer these questions and give you a taste of what's to come with PHP 7.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"heading2","text":"Performance Improvements","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"Performance is undoubtedly the biggest reason why you should upgrade your servers as soon as a stable version is released. The core refactoring introduced by the [phpng RFC](https://wiki.php.net/rfc/phpng) makes PHP 7 as fast as (or faster than) HHVM. The official benchmarks are impressive: most real world applications running on PHP 5.6 will run at least twice as fast on PHP 7. ","spans":[{"start":358,"end":371,"type":"strong"}]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"For detailed performance benchmarks, have a look at Rasmus Lerdorf's presentation at PHP Australia. (You can use the arrow keys to navigate through the slides.) Here are some WordPress benchmarks from that presentation:","spans":[{"start":52,"end":98,"type":"hyperlink","data":{"link_type":"Web","url":"http://talks.php.net/oz15#/wpbench"}}]},{"type":"paragraph","text":"","spans":[]},{"type":"image","url":"https://images.prismic.io/www-static/fa4737dd-0d2a-4389-8809-fccf2128af79_php7_graph.jpg?auto=compress,format","alt":null,"copyright":null,"dimensions":{"width":784,"height":490}},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"PHP 7 handles more than twice as many requests per second, which in practical terms will represent a 100% improvement on performance for Wordpress websites.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"heading2","text":"Backwards Compatibility Pitfalls","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"Let's talk about the few things that could potentially break a legacy application running on older versions of PHP.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"heading3","text":" Deprecated Items Removed","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"A number of deprecated items have been removed. Because they've been deprecated for some time now, hopefully you aren't using them! This might, however, have an impact on legacy applications.","spans":[{"start":12,"end":46,"type":"hyperlink","data":{"link_type":"Web","url":"https://wiki.php.net/rfc/remove_deprecated_functionality_in_php7"}}]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"In particular, ASP-style tags ( `<%`, `<%=` and `%>` ), were removed along with script tags ( `<script language=\"php\">` ). Make sure you are using the recommended `<?php` tag instead. Other functions that were previously deprecated, like [split](http://php.net/manual/en/function.split.php), have also been removed in PHP 7.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"The ereg extension (and all `ereg_*` functions) have been deprecated since PHP 5.3. It should be replaced with the PCRE extension (`preg_*` functions), which offers many more features. The mysql extension (and the `mysql_*` functions) have been deprecated since PHP 5.5.  For a direct migration, you can use the mysqli extension and the `mysqli_*` functions instead.","spans":[{"start":4,"end":8,"type":"strong"},{"start":115,"end":119,"type":"strong"},{"start":189,"end":194,"type":"strong"},{"start":245,"end":269,"type":"hyperlink","data":{"link_type":"Web","url":"https://wiki.php.net/rfc/mysql_deprecation"}},{"start":312,"end":318,"type":"strong"}]},{"type":"paragraph","text":"","spans":[]},{"type":"heading3","text":" Uniform Variable Syntax","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"The [uniform variable syntax](https://wiki.php.net/rfc/uniform_variable_syntax) is meant to solve a series of inconsistencies when evaluating variable-variable expressions. Consider the following code:","spans":[]},{"type":"paragraph","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    <?php  ","spans":[]},{"type":"paragraph","text":"    class Person  ","spans":[]},{"type":"paragraph","text":"    {","spans":[]},{"type":"paragraph","text":"       public $name = 'Erika';","spans":[]},{"type":"paragraph","text":"       public $job = 'Developer Advocate';","spans":[]},{"type":"paragraph","text":"    }","spans":[]},{"type":"paragraph","text":"    ","spans":[]},{"type":"paragraph","text":"    $person = new Person();","spans":[]},{"type":"paragraph","text":"    $property = [ 'first' => 'name', 'second' => 'info' ];","spans":[]},{"type":"paragraph","text":"    echo \"\\nMy name is \" . $person->$property['first'] . \"\\n\\n\";  ","spans":[]},{"type":"paragraph","text":"`}```    ","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"In PHP 5, the expression `$person->$property['first']` is evaluated as `$person->{$property['first']}`. In practical terms, this will be interpreted as `$person->name`, giving you the result \"My name is Erika\". Even though this is an edge case, it shows clear inconsistencies with the normal expression evaluation order, which is left to right.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"In PHP 7, the expression `$person->$property['first']` is evaluated as `{$person->$property}['first']`. The interpreter will evaluate `$person->$property` first; consequently, the previous code example won't work in PHP 7 because `$property` is an array and cannot be converted to a string.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"A quick and easy way to fix this problem is by explicitly defining the evaluation order with the help of curly braces (e.g. `$person->{$property['first']}`), which will guarantee the same behavior on both PHP 5 and PHP 7.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"Thanks to the new uniform left-to-right variable syntax, many expressions previously treated as invalid will now become valid. To illustrate this new behavior, consider the following class:","spans":[]},{"type":"paragraph","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    <?php  ","spans":[]},{"type":"paragraph","text":"    class Person  ","spans":[]},{"type":"paragraph","text":"    {","spans":[]},{"type":"paragraph","text":"       public static $company = 'DigitalOcean';","spans":[]},{"type":"paragraph","text":"       public function getFriends()","spans":[]},{"type":"paragraph","text":"       {","spans":[]},{"type":"paragraph","text":"           return [","spans":[]},{"type":"paragraph","text":"               'erika' => function () {","spans":[]},{"type":"paragraph","text":"                   return 'Elephpants and Cats';","spans":[]},{"type":"paragraph","text":"               },","spans":[]},{"type":"paragraph","text":"               'sammy' => function () {","spans":[]},{"type":"paragraph","text":"                   return 'Sharks and Penguins';","spans":[]},{"type":"paragraph","text":"               }","spans":[]},{"type":"paragraph","text":"           ];","spans":[]},{"type":"paragraph","text":"       }","spans":[]},{"type":"paragraph","text":"    ","spans":[]},{"type":"paragraph","text":"       public function getFriendsOf($someone)","spans":[]},{"type":"paragraph","text":"       {","spans":[]},{"type":"paragraph","text":"           return $this->getFriends()[$someone];","spans":[]},{"type":"paragraph","text":"       }","spans":[]},{"type":"paragraph","text":"    ","spans":[]},{"type":"paragraph","text":"       public static function getNewPerson()","spans":[]},{"type":"paragraph","text":"       {","spans":[]},{"type":"paragraph","text":"           return new Person();","spans":[]},{"type":"paragraph","text":"       }","spans":[]},{"type":"paragraph","text":"    }","spans":[]},{"type":"paragraph","text":"`}```    ","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"With PHP 7, we can create nested associations and different combinations between operators:","spans":[]},{"type":"paragraph","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    $person = new Person();","spans":[]},{"type":"paragraph","text":"    echo \"\\n\" . $person->getFriends()['erika']() . \"\\n\\n\";  ","spans":[]},{"type":"paragraph","text":"    echo \"\\n\" . $person->getFriendsOf('sammy')() . \"\\n\\n\";  ","spans":[]},{"type":"paragraph","text":"`}```    ","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"This snippet would give us a parse error on PHP 5, but works as expected on PHP 7.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"Similarly, nested static access is also possible:","spans":[]},{"type":"paragraph","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    echo \"\\n\" . $person::getNewPerson()::$company . \"\\n\\n\";  ","spans":[]},{"type":"paragraph","text":"    `}```","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"In PHP 5, this would give us the classic `T_PAAMAYIM_NEKUDOTAYIM` syntax error.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"heading3","text":"Fatal Error with multiple \"default\" clauses","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"This is, again, an edge case and it's more related to logic errors in your code. There's no use for multiple default clauses in a switch, but because it never caused any trouble (e.g. no warnings), it can be difficult to detect the mistake. In PHP 5, the last *default* would be used, but in PHP 7 you will now get a *Fatal Error: Switch statements may only contain one default clause*.","spans":[{"start":100,"end":136,"type":"hyperlink","data":{"link_type":"Web","url":"https://wiki.php.net/rfc/switch.default.multiple"}},{"start":261,"end":268,"type":"em"},{"start":318,"end":384,"type":"em"}]},{"type":"paragraph","text":"","spans":[]},{"type":"heading3","text":"Engine Exceptions","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"Engine exceptions are meant to facilitate handling errors in your application. Existing fatal and recoverable fatal errors were replaced by exceptions, making it possible for us to catch said errors and take action — like displaying them in a nicer way, logging them, or performing recovery procedures.","spans":[{"start":0,"end":17,"type":"hyperlink","data":{"link_type":"Web","url":"https://wiki.php.net/rfc/engine_exceptions_for_php7"}}]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"The implementation of engine exceptions was done in such a way to keep backwards compatibility, but there is an edge case that could impact legacy applications when they have a custom error handling function in place. Consider the following code:","spans":[]},{"type":"paragraph","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    <?php  ","spans":[]},{"type":"paragraph","text":"    set_error_handler(function ($code, $message) {  ","spans":[]},{"type":"paragraph","text":"       echo \"ERROR $code: \" . $message . \"\\n\\n\";","spans":[]},{"type":"paragraph","text":"    });","spans":[]},{"type":"paragraph","text":"    ","spans":[]},{"type":"paragraph","text":"    function a(ArrayObject $b){  ","spans":[]},{"type":"paragraph","text":"       return $b;","spans":[]},{"type":"paragraph","text":"    }","spans":[]},{"type":"paragraph","text":"    ","spans":[]},{"type":"paragraph","text":"    a(\"test\");","spans":[]},{"type":"paragraph","text":"    ","spans":[]},{"type":"paragraph","text":"    echo \"Hello World\";  ","spans":[]},{"type":"paragraph","text":"    `}```","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"This code generates a recoverable error caused by the type mismatch when calling the function `a()` using a string as parameter. In PHP 5, it generates an `E_RECOVERABLE` that is caught by the custom error handler, so this is the output you get:","spans":[]},{"type":"paragraph","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    ERROR 4096: Argument 1 passed to a() must be an instance of ArrayObject, string given, called in /data/Projects/php7dev/tests/test04.php on line 12 and defined(...)","spans":[]},{"type":"paragraph","text":"    ","spans":[]},{"type":"paragraph","text":"    Hello World  ","spans":[]},{"type":"paragraph","text":"    `}```","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"Notice that the execution continues because the error was handled. In PHP 7, this code generates a `TypeError` exception (not an error!) so the custom error handler won't be called. This is the output you get:","spans":[]},{"type":"paragraph","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    Fatal error: Uncaught TypeError: Argument 1 passed to a() must be an instance of ArrayObject, string given, called in /vagrant/tests/test04.php on line 12 and defined in /vagrant/tests/test04.php:7  ","spans":[]},{"type":"paragraph","text":"    Stack trace:  ","spans":[]},{"type":"paragraph","text":"    #0 /vagrant/tests/test04.php(12): a('test')","spans":[]},{"type":"paragraph","text":"    #1 {main}","spans":[]},{"type":"paragraph","text":"      thrown in /vagrant/tests/test04.php on line 7","spans":[]},{"type":"paragraph","text":"    `}```","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"The execution is stopped because the exception was not caught. To solve this problem, you should catch the exceptions using try/catch blocks. It's important to notice that the [Exception hierarchy](https://wiki.php.net/rfc/throwable-interface) had to change to accommodate the new engine exceptions with minimal impact on legacy code:","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"list-item","text":"Throwable interface","spans":[]},{"type":"list-item","text":"Exception implements Throwable","spans":[]},{"type":"list-item","text":"ErrorException extends Exception","spans":[]},{"type":"list-item","text":"RuntimeException extends Exception","spans":[]},{"type":"list-item","text":"Error implements Throwable","spans":[]},{"type":"list-item","text":"TypeError extends Error","spans":[]},{"type":"list-item","text":"ParseError extends Error","spans":[]},{"type":"list-item","text":"AssertionError extends Error","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"This basically means that the new catch-all Exception is now `Throwable` instead of `Exception`. This should not impact any legacy code, but keep it in mind when handling the new engine exceptions in PHP 7.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"heading2","text":"New Language Features","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"Now the fun part — let's talk about the most exciting new features that will be available when you upgrade to PHP 7.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"heading3","text":"New Operators","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"PHP 7 comes with two shiny new operators: the spaceship (or combined comparison operator) and the null coalesce operator.","spans":[{"start":46,"end":55,"type":"strong"},{"start":98,"end":120,"type":"strong"}]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"The spaceship operator ( `<=>` ), also known as combined comparison operator, can be used to make your chained comparison more concise. Consider the following expression:","spans":[{"start":4,"end":22,"type":"hyperlink","data":{"link_type":"Web","url":"https://wiki.php.net/rfc/combined-comparison-operator"}}]},{"type":"paragraph","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    $a <=> $b","spans":[]},{"type":"paragraph","text":"`}```    ","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"This expression will evaluate to **-1** if `$a` is smaller than `$b`, **0** if `$a` equals `$b`, and **1** if `$a` is greater than `$b`. It's basically a shortcut for the following expression:","spans":[{"start":35,"end":37,"type":"strong"},{"start":72,"end":73,"type":"strong"},{"start":103,"end":104,"type":"strong"}]},{"type":"paragraph","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    ($a < $b) ? -1 : (($a > $b) ? 1 : 0)","spans":[]},{"type":"paragraph","text":"    `}```   ","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"The null coalesce operator ( `??` ) also works as a shortcut for a common use case: a conditional attribution that checks if a value is set before using it. In PHP 5, you would usually do something like this:","spans":[{"start":4,"end":26,"type":"hyperlink","data":{"link_type":"Web","url":"https://wiki.php.net/rfc/isset_ternary"}}]},{"type":"paragraph","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    $a = isset($b) ? $b : \"default\";","spans":[]},{"type":"paragraph","text":"`}```       ","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"With the null coalesce operator in PHP 7, we can simply use:","spans":[]},{"type":"paragraph","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    $a = $b ?? \"default\";","spans":[]},{"type":"paragraph","text":"    `}```   ","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"heading3","text":"Scalar Type Hints","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"One of the most debated new features coming with PHP 7, scalar type hints, will finally make it possible to use integers, floats, strings, and booleans as type hints for functions and methods. By default, scalar type hints are non-restrictive, which means that if you pass a float value to an integer parameter, it will just coerce it to int without generating any errors or warnings.","spans":[{"start":56,"end":73,"type":"hyperlink","data":{"link_type":"Web","url":"https://wiki.php.net/rfc/scalar_type_hints_v5","target":"_blank"}}]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"It is possible, however, to enable a strict mode that will throw errors when the wrong type is passed as an argument. Consider the following code:","spans":[]},{"type":"paragraph","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    <?php  ","spans":[]},{"type":"paragraph","text":"    function double(int $value)  ","spans":[]},{"type":"paragraph","text":"    {","spans":[]},{"type":"paragraph","text":"       return 2 * $value;","spans":[]},{"type":"paragraph","text":"    }","spans":[]},{"type":"paragraph","text":"    $a = double(\"5\");","spans":[]},{"type":"paragraph","text":"    var_dump($a);  ","spans":[]},{"type":"paragraph","text":"   `}```    ","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"This code won't generate any errors because we are not using strict mode. The only thing that will happen is a type conversion, so the string \"5\" passed as an argument will be coerced into integer inside the double function.","spans":[{"start":208,"end":214,"type":"em"}]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"If we want to make sure only integers are allowed to be passed to the double function, we can enable strict mode by including the directive `declare(strict_types = 1)` as the very first line in our script:","spans":[{"start":70,"end":76,"type":"em"}]},{"type":"paragraph","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    <?php  ","spans":[]},{"type":"paragraph","text":"    declare(strict_types = 1);  ","spans":[]},{"type":"paragraph","text":"    function double(int $value)  ","spans":[]},{"type":"paragraph","text":"    {","spans":[]},{"type":"paragraph","text":"       return 2 * $value;","spans":[]},{"type":"paragraph","text":"    }","spans":[]},{"type":"paragraph","text":"    $a = double(\"5\");","spans":[]},{"type":"paragraph","text":"    var_dump($a);  ","spans":[]},{"type":"paragraph","text":"   `}```    ","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"This code will generate a Fatal error: Uncaught TypeError: Argument 1 passed to double() must be of the type integer, string given.","spans":[{"start":26,"end":130,"type":"em"}]},{"type":"paragraph","text":"","spans":[]},{"type":"heading3","text":" Return Type Hints","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"Another important new feature coming with PHP 7 is the ability to define the return type of methods and functions, and it behaves in the same fashion as scalar type hints in regards of coercion and strict mode:","spans":[{"start":77,"end":88,"type":"hyperlink","data":{"link_type":"Web","url":"https://wiki.php.net/rfc/return_types"}}]},{"type":"paragraph","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    <?php  ","spans":[]},{"type":"paragraph","text":"    function a() : bool  ","spans":[]},{"type":"paragraph","text":"    {","spans":[]},{"type":"paragraph","text":"       return 1;","spans":[]},{"type":"paragraph","text":"    }","spans":[]},{"type":"paragraph","text":"    var_dump(a());  ","spans":[]},{"type":"paragraph","text":"`}```    ","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"This snippet will run without warnings and the returned value will be converted to bool automatically. If you enable strict mode (just the same as with scalar type hints), you will get a fatal error instead:","spans":[]},{"type":"paragraph","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"`Fatal error: Uncaught TypeError: Return value of a() must be of the type boolean, integer returned`","spans":[]},{"type":"paragraph","text":"`}```","spans":[]},{"type":"paragraph","text":"Once again, notice that these errors are actually Exceptions that can be caught and handled using try/catch blocks. It's also important to highlight that you can use any valid type hint, not only scalar types.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"heading2","text":"What's Next","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"The PHP 7 timeline indicates a stable release in mid-October, subject to quality. We are currently on release candidate cycles, and a beta version is already available for tests. Check out the RFC with all changes coming with PHP 7 for more information.","spans":[{"start":3,"end":18,"type":"hyperlink","data":{"link_type":"Web","url":"https://wiki.php.net/rfc/php7timeline"}},{"start":134,"end":146,"type":"hyperlink","data":{"link_type":"Web","url":"http://php.net"}},{"start":193,"end":231,"type":"hyperlink","data":{"link_type":"Web","url":"https://wiki.php.net/rfc#php_70"}}]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"Note that even though no new features will be included, some changes might still happen before the final release, so please don't use PHP 7 in production just yet! There's a Vagrant VM created and shared by Rasmus Lerdorf that you can use to test your current code on PHP 7. You are strongly encouraged to test your applications and report any problems you might find.","spans":[{"start":174,"end":184,"type":"hyperlink","data":{"link_type":"Web","url":"https://github.com/rlerdorf/php7dev"}}]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"Happy coding!","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"by Erika Heidi","spans":[{"start":3,"end":14,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/erikaheidi"}}]}],"blog_post_date":"2015-07-15","tags":[{"tag1":{"tag":"Engineering","_linkType":"Link.document","_meta":{"uid":"engineering"}}}],"_meta":{"uid":"getting-ready-for-php-7"}}},{"node":{"author":{"_linkType":"Link.document","author_name":"DigitalOcean","author_image":{"dimensions":{"width":600,"height":600},"alt":"Sammy avatar","copyright":null,"url":"https://images.prismic.io/www-static/a10e3c2eb15b74ee43f872be3044313423b1c9a9_sammy_avatar.png?auto=compress,format"},"_meta":{"uid":"digitalocean"}},"blog_header_image":{"dimensions":{"width":784,"height":418},"alt":"Sunset over ocean with fish jumping over the text 'Thank you!' illustration","copyright":null,"url":"https://images.prismic.io/www-static/ead0daf7acfebeee9c21c3c8759797106654db2a_thank_you.jpg?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"Series B Funding: Writing a New Chapter in the DigitalOcean Story","spans":[]}],"blog_post_content":[{"type":"paragraph","text":"For over three years, we've been driven by the desire to empower developers and make cloud infrastructure simple. To date, over 500,000 developers have deployed more than 6 million Droplets on DigitalOcean and as the infrastructure needs of our developer community have continued to evolve, we have aspired to as well.","spans":[]},{"type":"paragraph","text":"Today, we're excited to announce that we've closed a Series B funding round worth $83 million, led by Access Industries with participation from Andreessen Horowitz. This funding represents our continued commitment to helping developers thrive and to help scaling startups grow on our infrastructure.","spans":[]},{"type":"heading3","text":"Scaling","spans":[]},{"type":"paragraph","text":"We've experienced many of the growing pains that come with turning into a scalable business. In 2011, our five founders wanted to create a simple infrastructure experience that developers would love to use. In 2012, TechStars accepted us into their Boulder class; we set up shop in Colorado that summer and graduated the program with our first 400 customers.","spans":[]},{"type":"image","url":"https://images.prismic.io/www-static/8285e1a0c09ab58da49745359130542415501aac_the_beginning.jpg?auto=compress,format","alt":"TechStars","copyright":null,"dimensions":{"width":564,"height":396}},{"type":"paragraph","text":"TechStars 2012","spans":[{"start":0,"end":14,"type":"em"}]},{"type":"paragraph","text":"The early DigitalOcean adopters had only two choices of datacenter regions (New York and Amsterdam) on a cloud that was maintained and operated on just a few servers.","spans":[]},{"type":"paragraph","text":"Since then, a lot has changed. We've raised a seed round and Series A which we used to build out servers in six locations (New York, London, Singapore, Frankfurt, Amsterdam, and San Francisco), added features like user data, IPv6, private networking, team account management, and updated our Community platform. Our hardware footprint expanded, the complexity of our system deepened, and the technological challenges we faced grew. A cloud that once ran on six servers now is powered by over ten thousand.","spans":[{"start":292,"end":301,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community"}}]},{"type":"heading3","text":"Growing Together","spans":[]},{"type":"paragraph","text":"Since our outset, we have loved to see the variety of amazing work hosted on DigitalOcean, from single-server hacks created overnight at hackathons to innovative applications which serve millions of happy users.","spans":[]},{"type":"paragraph","text":"As developers and entrepreneurs ourselves, we've seen how quickly a company can grow. That same single-server app, gone viral on Hacker News, can transition from a personal project to a full-fledged business. We want to make that transition effortless and raised this Series B to continue supporting individual developers further on in their journey.","spans":[]},{"type":"paragraph","text":"How? The $83 million is going directly into growing our team and expanding our product offerings with networking and storage features. When we started, we felt the pain points of developers who had to contend with questions on how to spin up a single server rather than being able to focus on their applications. We solved this by providing developers with a simple and intuitive control panel. Now, by learning from our own company's growth, we're focused on addressing developers' challenges as they grow; spinning up a server should be simple, but so should creating a production environment to handle load at any scale.","spans":[{"start":44,"end":60,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/company/careers/"}}]},{"type":"heading3","text":"Thank You!","spans":[]},{"type":"paragraph","text":"We are extraordinarily indebted to the amazing people who have personally made all of this possible.","spans":[]},{"type":"paragraph","text":"Thank you to the DigitalOcean family for building and supporting this cloud with your signature love, creativity, passion, and hard work!","spans":[{"start":17,"end":36,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/company/about/"}}]},{"type":"paragraph","text":"Thank you to our investors, IA Ventures, Andreessen Horowitz, and Access Industries for believing in our vision.","spans":[]},{"type":"paragraph","text":"Last but certainly not least, we would like to thank you, our community! Thank you for growing with us and for challenging us to be better every day. We wouldn't be here without you.","spans":[]},{"type":"paragraph","text":"Here's to writing this new chapter together!","spans":[]},{"type":"paragraph","text":"DigitalOcean HQ 2015","spans":[{"start":0,"end":20,"type":"em"}]},{"type":"image","url":"https://images.prismic.io/www-static/0470fe0347edc7a6a3342eb5940af5300b213e5b_the_team.jpg?auto=compress,format","alt":"DigitalOcean HQ","copyright":null,"dimensions":{"width":2000,"height":1333}}],"blog_post_date":"2015-07-07","tags":[{"tag1":{"tag":"News","_linkType":"Link.document","_meta":{"uid":"news"}}}],"_meta":{"uid":"series-b-funding-writing-a-new-chapter-in-the-digitalocean-story"}}},{"node":{"author":{"_linkType":"Link.document","author_name":"Brian Knox","author_image":null,"_meta":{"uid":"brian_knox"}},"blog_header_image":{"dimensions":{"width":784,"height":418},"alt":"open source doors","copyright":null,"url":"https://images.prismic.io/www-static/34c2992c-c506-4f5c-976a-714b8b9907b0_open_source.jpg?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"Community, Collaboration, and Problem Solving: The Value of Open Source","spans":[]}],"blog_post_content":[{"type":"heading2","text":"Open Source is a Tool","spans":[]},{"type":"paragraph","text":"When managing a large computing infrastructure, it's paramount to understand what's happening within it; as your infrastructure scales, this becomes increasingly challenging. Fortunately, while this can be a difficult problem, there is a powerful tool available to help solve it: open source software.","spans":[]},{"type":"paragraph","text":"When describing open source software as a tool, I'm referring to the process of open source itself, not a specific piece of open source software. Any open source tool with a history in a particular problem space can be thought of, at a higher level, as a collection of solved problems within that space. This is a perspective on open source software I gained from Pieter Hintjens while working on various ZeroMQ projects, and I find it a highly valuable framing of what open source provides.","spans":[]},{"type":"paragraph","text":"The community that forms around a particular successful piece of software over time evolves into a community of experts about the problems that software solves. Being a contributing member of such communities yields great benefits — not only better tools, but strong and lasting relationships with other people working on the same issues.","spans":[]},{"type":"heading2","text":"A Real World Example","spans":[]},{"type":"paragraph","text":"As a specific example, the metrics team at DO was recently trying to figure out how to safely and securely tail logs in real-time from remote servers as conveniently as if they were local.  To solve this, we first looked at Rsyslog, which is a logging daemon common on many Linux distributions.","spans":[{"start":224,"end":231,"type":"hyperlink","data":{"link_type":"Web","url":"http://www.rsyslog.com/"}}]},{"type":"paragraph","text":"At its heart, Rsyslog provides the ability to receive, parse, filter, and forward log messages. Over the eleven years of its life, it has become a collection of solutions to a wide range of problems, like how to handle logs as efficiently as possible, how to deal with devices logging messages that aren't standards-compliant, how to insert logs into databases for indexing and storage, how to transform logs into a common structured format, and many more.","spans":[]},{"type":"paragraph","text":"Our problem fell into an appropriate scope for Rsyslog, but we couldn't quite solve it with that alone. Our solution was to integrate Rsyslog with CZMQ, a high level C binding for ZeroMQ. CZMQ provides certificate-based authentication, libsodium-based encryption, and support for publisher filtered publish-subscribe buses, among other things. This makes it a natural fit for our particular problem when combined with Rsyslog's parser and message templates.","spans":[{"start":147,"end":151,"type":"hyperlink","data":{"link_type":"Web","url":"http://czmq.zeromq.org/"}},{"start":180,"end":186,"type":"hyperlink","data":{"link_type":"Web","url":"http://zeromq.org/"}}]},{"type":"paragraph","text":"With this combination, we can create dynamic topic streams for log messages and provide them over secure, encrypted streams without additional infrastructure. We've contributed the input and output plugins back to Rsyslog, and they'll soon be part of the official packages, so anyone else with a similar problem can use them. That said, we've tried only one possible approach of many to solving this problem, and we're looking forward to iterating on it, making improvements, and releasing more software around this idea.","spans":[{"start":181,"end":186,"type":"hyperlink","data":{"link_type":"Web","url":"https://github.com/rsyslog/rsyslog/tree/master/contrib/imczmq"}},{"start":191,"end":197,"type":"hyperlink","data":{"link_type":"Web","url":"https://github.com/rsyslog/rsyslog/tree/master/contrib/omczmq"}}]},{"type":"paragraph","text":"For example, by using these plugins with LogTalez, a minimal API and command line client built on top of the GoCZMQ Go bindings for CZMQ, logs from any Rsyslog aggregator can be requested by host and program name combinations, piped to standard command line tools, and / or used with useful Go libraries. We're currently working on the ability to extract metrics from log streams using these plugins with Prometheus, a monitoring system and time series database released by SoundCloud.","spans":[{"start":41,"end":49,"type":"hyperlink","data":{"link_type":"Web","url":"https://github.com/digitalocean/logtalez"}},{"start":109,"end":115,"type":"hyperlink","data":{"link_type":"Web","url":"https://github.com/zeromq/goczmq"}},{"start":405,"end":415,"type":"hyperlink","data":{"link_type":"Web","url":"https://github.com/prometheus/prometheus"}}]},{"type":"heading2","text":"DO + OSS","spans":[]},{"type":"paragraph","text":"Actively taking part in open source development allows us to learn from each other's perspectives and have a conversation about different approaches to the same problems. The tools built through these conversations become shared repositories of knowledge gained through direct experience, freeing all of us to work on the core problems our individual organizations are addressing.","spans":[]},{"type":"paragraph","text":"I'm overjoyed to work at an organization that believes in this approach and puts resources behind it. Our Community team has created a site to highlight some of the open source projects that DO folks release and contribute to. Keep an eye on it for more to come!","spans":[{"start":125,"end":139,"type":"hyperlink","data":{"link_type":"Web","url":"https://developers.digitalocean.com/opensource/"}}]},{"type":"paragraph","text":"by Brian Knox","spans":[{"start":3,"end":13,"type":"hyperlink","data":{"link_type":"Web","url":"https://github.com/taotetek"}}]}],"blog_post_date":"2015-06-29","tags":[{"tag1":{"tag":"Engineering","_linkType":"Link.document","_meta":{"uid":"engineering"}}},{"tag1":{"tag":"Community","_linkType":"Link.document","_meta":{"uid":"community"}}}],"_meta":{"uid":"community-collaboration-and-problem-solving"}}},{"node":{"author":{"_linkType":"Link.document","author_name":"DigitalOcean","author_image":{"dimensions":{"width":600,"height":600},"alt":"Sammy avatar","copyright":null,"url":"https://images.prismic.io/www-static/a10e3c2eb15b74ee43f872be3044313423b1c9a9_sammy_avatar.png?auto=compress,format"},"_meta":{"uid":"digitalocean"}},"blog_header_image":{"dimensions":{"width":784,"height":418},"alt":"stack javascript.com","copyright":null,"url":"https://images.prismic.io/www-static/3cdeeb9a-1675-4b14-bd12-1c3cfd01c8b1_guest-post-javascript-com.jpg?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"Guest Post: Behind the Stack of JavaScript.com","spans":[]}],"blog_post_content":[{"type":"paragraph","text":"This morning at Code School we released JavaScript.com, a free community resource that serves two purposes: to provide a starting point to learn JavaScript, and to keep JavaScript developers up to date with the latest news, frameworks, and libraries.","spans":[{"start":16,"end":27,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.codeschool.com/"}},{"start":40,"end":54,"type":"hyperlink","data":{"link_type":"Web","url":"http://javascript.com"}}]},{"type":"paragraph","text":"Since the purpose of JavaScript.com is to teach everyone about web development, I couldn't resist this opportunity to spread a little knowledge about the site's deployment process. In this article, I thought I'd give a peek behind the curtain to show you the stack we're using and why we're hosting with DigitalOcean.","spans":[]},{"type":"heading2","text":"How Does JavaScript.com Work?","spans":[]},{"type":"paragraph","text":"JavaScript.com is developed in JavaScript, of course. We chose Node.js for its speed, ease of use, and community support. But that's not telling the whole story.","spans":[]},{"type":"paragraph","text":"We don't want every web request to make it all the way to our application servers, since that would strain them unnecessarily. So, before any web request makes it to the application, it passes through several layers that help offload and balance the traffic between multiple servers.","spans":[]},{"type":"heading2","text":"Content Delivery & Caching","spans":[]},{"type":"paragraph","text":"The first destination on your request's journey is CloudFlare. We've been experimenting with CloudFlare for some time at Code School, as both a security and extra caching layer. If CloudFlare sees a request for a static page that's been generated recently, it will return that page from one of its data centers rather than asking our application servers to regenerate the page. The sort of page and asset caching CloudFlare provides works extremely well with a read-heavy site like JavaScript.com. After all, the best kind of cached request never even hits your server.","spans":[]},{"type":"heading2","text":"Load Balancing","spans":[]},{"type":"paragraph","text":"After CloudFlare, any uncached request will go through one of two load balancers running HAProxy. These load balancers allow us to quickly add new application servers to the mix as the load increases. A lone HAProxy process can service many millions of requests per day, so we run only two of them: one to serve requests from the Internet, and one on standby, ready to take over if the hot server fails. This is called a \"hot standby\" configuration.","spans":[]},{"type":"heading2","text":"Application Servers","spans":[]},{"type":"paragraph","text":"Finally, HAProxy routes the request down to our NGINX and Phusion Passenger stack. NGINX is a web server that handles static requests (like images), while Phusion Passenger manages our Node processes and dynamic requests (like the comments page) from within NGINX. We really enjoy Passenger on the DevOps side of things since it makes Node process management dead simple.","spans":[]},{"type":"paragraph","text":"All of these application servers are designed to run independently from one another. So, we can fire up as many as we need of each type to handle whatever traffic we see on JavaScript.com.","spans":[]},{"type":"heading2","text":"Database Servers","spans":[]},{"type":"paragraph","text":"In order to save all those stories and comments, JavaScript.com uses the PostgreSQL database. It is an extremely quick and reliable piece of software that we use across Code School for a variety of applications.","spans":[]},{"type":"paragraph","text":"The database always gets its own server, along with a spare, should the main server ever go down. As a bonus, a PostgreSQL hot spare can be used by the JavaScript.com application as a read-only database should the main server fall under too much load.","spans":[]},{"type":"heading2","text":"One Command to Deploy Them All","spans":[]},{"type":"paragraph","text":"JavaScript.com is made up of a minimum of six servers: two load balancers, two application servers, and two database servers. Since we want to be able to scale out at a moment's notice, we need a way to spin up new servers quickly and automatically. Enter SaltStack and DigitalOcean.","spans":[]},{"type":"image","url":"https://images.prismic.io/www-static/4413289e7896aff6e20f3f97813062020413c3cf_stack-of-javascript-com.png?auto=compress,format","alt":"Javascript.com","copyright":null,"dimensions":{"width":745,"height":460}},{"type":"paragraph","text":"SaltStack is a configuration management system for servers that lets us configure the following:","spans":[]},{"type":"list-item","text":"Deploy a new DigitalOcean server","spans":[]},{"type":"list-item","text":"Configure the server to run JavaScript.com","spans":[]},{"type":"list-item","text":"Grant access to the database servers","spans":[]},{"type":"list-item","text":"Add the new server to the load balancer so it can start handling requests","spans":[]},{"type":"paragraph","text":"It finishes this provisioning process for a new server in just a few minutes. Our process for code deployments is exactly the same, since SaltStack knows how to ship new code to existing servers as well.","spans":[]},{"type":"paragraph","text":"In order to scale out horizontally, we needed a provider that not only spins up servers very quickly, but can also do so programmatically. DigitalOcean works very well on both fronts, and in multiple locations around the world. If we end up with more traffic than expected, more capacity is just a salt-cloud command away.","spans":[]},{"type":"heading2","text":"Conclusion","spans":[]},{"type":"paragraph","text":"To create a website that's ready to handle a great deal of traffic, you need a detailed plan. Not only do you need a caching layer, but you must also be able to spin up new servers quickly as more uncacheable requests flow in. The first step in this process is separating your stack into layers so that each can scale independently. The second is making use of tools like HAProxy, SaltStack, and DigitalOcean to bring it all together.","spans":[]},{"type":"paragraph","text":"Now that you've read about JavaScript.com's stack, go try it — and feel free to promote your own stack, framework, or library on our community news page.","spans":[{"start":27,"end":41,"type":"hyperlink","data":{"link_type":"Web","url":"http://javascript.com"}}]},{"type":"paragraph","text":"by Thomas Meeks","spans":[{"start":3,"end":15,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/codeschool"}}]}],"blog_post_date":"2015-06-15","tags":[{"tag1":{"tag":"Community","_linkType":"Link.document","_meta":{"uid":"community"}}}],"_meta":{"uid":"guest-post-behind-the-stack-of-javascript-com"}}},{"node":{"author":{"_linkType":"Link.document","author_name":"Sam Kottler","author_image":null,"_meta":{"uid":"sam_kottler"}},"blog_header_image":{"dimensions":{"width":784,"height":392},"alt":"Transparent huge pages and memory usage illustration of paper ","copyright":null,"url":"https://images.prismic.io/www-static/2e69f132-7800-41e7-992c-25deb946f219_image.png?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"Transparent Huge Pages and Alternative Memory Allocators: A Cautionary Tale","spans":[]}],"blog_post_content":[{"type":"paragraph","text":"Recently, our site reliability engineering team started getting alerted about memory pressure on some of our Redis instances which have very small working sets *1. As we started digging into the issue, it became clear that there were problems with freeing memory after initial allocation because there were a relatively small number of keys but a comparatively large amount of memory allocated by `redis-server` processes. Despite initially looking like a leak, the problem was actually an issue between an alternative memory allocator and transparent huge pages.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"heading2","text":"Background","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"If you already know what transparent huge pages are and how `madvise(2)` works, you can skim this section. For those who don't, read on.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"heading3","text":"Hold on — what are pages?","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"A page is a chunk of memory that a processor allocates for use, typically in 4kb chunks. When an application has to access virtual memory, it has to resolve its virtual memory address to the physical address of the page. The intermediary between physical addresses and mapped virtual memory is called the page table. For every 1GB of memory allocated in 4kb pages, there are 262,144 entries in the page table — and, of course, the more pages in the page table, the longer it takes to translate addresses.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"Virtual memory makes page management even more complicated by allowing applications to address pages which don't actually exist in main memory. When this happens, it causes a fault, but the kernel knows how to handle faults in virtual memory and will pull pages off of secondary storage (e.g. local spinning rust or flash, NAS, etc.) without the application knowing the fault happened.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"heading3","text":"Okay, what are (transparent) huge pages?","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"Huge pages are exactly what they sound like — pages that are much larger than 4kb in size. They cut down on the number of entries in the page table, thereby reducing the number of table lookups needed to find where a specific range of virtual memory is mapped.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"Linux implements support for huge pages *2, which requires changes in software running in user space to take advantage of these potential performance benefits. They come in two varieties (2MB and 1GB — the available sizes depend upon the CPU in use) and have to get configured at boot time via parameters that get passed to the kernel.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"The implementation of huge pages itself is pretty boring, so let's talk about transparent huge pages. This is where the fun begins.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"User space software has traditionally had to implement its own support for huge pages, but it's difficult to do and requires lots of testing to be utilized effectively. Rather than having these user space applications manage their interactions with huge pages, transparent huge pages allow applications to use huge pages…. well, transparently. This manifests itself as the kernel doing some additional management of memory being allocated, marked, and subsequently freed with (in our case) 2MB underlying pages.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"This all sounds useful, but it turns out that some alternative memory allocators don't play nicely with transparent huge pages.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"heading3","text":" madvise(2)","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"`madvise(2)` is not part of POSIX, but it is inspired by the POSIX function `posix_fadvise(2)`*3. It gives advice to the kernel about what it should do with a specific range of memory when it comes time to evict pages. The advice must be given for a specific range of memory starting at an address for `n` bytes after that address.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"It also passes a parameter around the piece of advice, like \"free this address and `n` bytes after it whenever you're ready\" (`MADV_DONTNEED`) or \"this address and `n` bytes after it are going to be used soon, so you should probably read some pages ahead\" (`MADV_WILLNEED`).","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"Some memory allocators, like the one included as part of glibc, don't deal with marking pages using `madvise(2)`. However, `jemalloc(3)`*does* mark ranges with `madvise(..., MADV_DONTNEED)`, but it's important to note that it's on a range rather than at the \"left\" and \"right\" edges of a specific page or group of pages.","spans":[{"start":137,"end":141,"type":"em"}]},{"type":"paragraph","text":"","spans":[]},{"type":"heading2","text":"So what happened?","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"This rabbit hole began when a `redis-server` process, which had recently been moved over to `LD_PRELOAD``jemalloc.so`, began using significant amounts of memory. Initial signs pointed to the fact that using an alternative allocator might be part of the issue, so that's where we started digging.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"It turns out that `jemalloc(3)` uses `madvise(2)` extensively to notify the operating system that it's done with a range of memory which it had previously `malloc`'ed. Because the machine used transparent huge pages, the page size was 2MB. As such, a lot of the memory which was being marked with `madvise(..., MADV_DONTNEED)` was within ranges substantially smaller than 2MB. This meant that the operating system never was able to evict pages which had ranges marked as `MADV_DONTNEED` because the entire page would have to be unneeded to allow it to be reused.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"So despite initially looking like a leak, the operating system itself was unable to free memory because of `madvise(2)` and transparent huge pages. *4 This led to sustained memory pressure on the machine and `redis-server` eventually getting OOM killed.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"by Sam Kottler","spans":[{"start":3,"end":14,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/samkottler"}}]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"1. ","spans":[]},{"type":"paragraph","text":"Bugs around memory allocation often become more apparent with data stores because they tend to allocate and free memory at a relatively rapid pace. We use Redis as a cache and queue for ephemeral jobs, meaning that it allocates and frees substantial amounts of memory given that types of operations we are doing.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"2. ","spans":[]},{"type":"paragraph","text":"Huge pages are also incorporated into some other widely used Unix kernels, like FreeBSD, as superpages; the same concept is available on Windows as large pages. Despite the different names, the functionality is fundamentally the same. ","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"3. ","spans":[]},{"type":"paragraph","text":"undefined is specifically targeted towards file access rather than direct memory management, and takes a file descriptor as the first argument rather than a pointer to an address.","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"4. ","spans":[]},{"type":"paragraph","text":"Note that disabling transparent huge pages isn't possible via ","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"undefined. Rather, it requires manually echoing settings into ","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"undefined at or after boot. In ","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"undefined or by hand: ","spans":[]},{"type":"paragraph","text":"```[html]{`","spans":[]},{"type":"paragraph","text":"        if test -f /sys/kernel/mm/transparent_hugepage/enabled; then","spans":[]},{"type":"paragraph","text":"          echo never > /sys/kernel/mm/transparent_hugepage/enabled","spans":[]},{"type":"paragraph","text":"        fi","spans":[]},{"type":"paragraph","text":"    ","spans":[]},{"type":"paragraph","text":"        if test -f /sys/kernel/mm/transparent_hugepage/defrag; then","spans":[]},{"type":"paragraph","text":"          echo never > /sys/kernel/mm/transparent_hugepage/defrag","spans":[]},{"type":"paragraph","text":"        fi","spans":[]},{"type":"paragraph","text":"`}```    ","spans":[]}],"blog_post_date":"2015-06-15","tags":[{"tag1":{"tag":"Engineering","_linkType":"Link.document","_meta":{"uid":"engineering"}}}],"_meta":{"uid":"transparent-huge-pages-and-alternative-memory-allocators"}}},{"node":{"author":{"_linkType":"Link.document","author_name":"Edward Chiu","author_image":null,"_meta":{"uid":"edward_chiu"}},"blog_header_image":{"dimensions":{"width":784,"height":418},"alt":"Boat of people with fish illustration and text 'Introducing Team Accounts\" ","copyright":null,"url":"https://images.prismic.io/www-static/2157fc69435cb01dc2938b3f3b20c835f52ca20e_team_accounts_blog.jpg?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"Team Accounts: Share Resources Not Passwords","spans":[]}],"blog_post_content":[{"type":"paragraph","text":"As more and more applications get deployed on DigitalOcean's cloud, we've seen that many accounts have multiple developers using the same credentials. Anyone who has ever shared an account login with someone knows how frustrating it can be. We are proud to announce that Team Accounts are here!","spans":[]},{"type":"paragraph","text":"We're particularly excited about this release as it will better support teams of developers and companies working on large-scale and established applications.","spans":[]},{"type":"heading2","text":"Happiness in Simple Things","spans":[]},{"type":"paragraph","text":"At DigitalOcean, we pride ourselves in providing the simplest infrastructure experience. With Team Accounts, we wanted to create a feature that allows teams to seamlessly work together.","spans":[]},{"type":"paragraph","text":"Previously, a team shared a single login to access their DigitalOcean infrastructure, hardly the best scenario if the main account holder leaves or changes the password. Team Accounts now allows multiple individuals to have their own 2-Factor enabled login. Not only do they avoid sharing the password, but their own credentials remain secure.","spans":[]},{"type":"paragraph","text":"Development teams can also easily manage their infrastructure resources. In the case of exceptional traffic, anyone in the engineering group can scale the application to ensure that their users are unaffected.","spans":[]},{"type":"paragraph","text":"Additionally, Team Accounts creates a simpler process for Dev Shops. Rather than contending with a messy transition in billing information when they're first deploying or handing off the account to clients (sharing passwords, changing passwords, changing CC info, emailing customer support to remove devs from the account, changing the account owner), they can now send clients to this tutorial.","spans":[{"start":386,"end":394,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/how-to-invite-your-web-developer-to-set-up-your-digitalocean-server"}}]},{"type":"heading2","text":"Skip the Expense Reports","spans":[]},{"type":"paragraph","text":"After speaking with many users we discovered two simple truths: 1) It's a very awkward conversation to ask your \"finance\" person for the company credit card and 2) No one enjoys doing expense reports, especially when you have to front the money out of your own pocket.","spans":[]},{"type":"paragraph","text":"Now that you have the ability to invite multiple users to access and manage your account's resources using a shared billing profile, you can spend that extra savings on that other thing you've always wanted.","spans":[]},{"type":"heading2","text":"We Want More!","spans":[]},{"type":"paragraph","text":"We realize in most initial releases of any product there will be features missing for a particular use case. We couldn't have built this feature without the awesome feedback we received during user testing, and as we continue evolving Team Accounts to suit your needs, we hope you'll share your feedback on our Uservoice page.","spans":[{"start":311,"end":320,"type":"hyperlink","data":{"link_type":"Web","url":"https://digitalocean.uservoice.com/forums/136585-digitalocean"}}]},{"type":"paragraph","text":"This exciting new feature is possible because of a huge team effort inside and outside of DigitalOcean. We hope you'll enjoy being part of a TEAM as much as we do.","spans":[]},{"type":"paragraph","text":"You can read up on the specifics of Team Accounts in our tutorial.","spans":[{"start":57,"end":65,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/how-to-use-digitalocean-team-accounts"}}]},{"type":"paragraph","text":"by Edward Chiu","spans":[{"start":3,"end":14,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/edwardchiu"}}]}],"blog_post_date":"2015-06-08","tags":[{"tag1":{"tag":"News","_linkType":"Link.document","_meta":{"uid":"news"}}},{"tag1":{"tag":"Product Updates","_linkType":"Link.document","_meta":{"uid":"product-updates"}}}],"_meta":{"uid":"team-accounts-share-resources-not-passwords"}}},{"node":{"author":{"_linkType":"Link.document","author_name":"DigitalOcean","author_image":{"dimensions":{"width":600,"height":600},"alt":"Sammy avatar","copyright":null,"url":"https://images.prismic.io/www-static/a10e3c2eb15b74ee43f872be3044313423b1c9a9_sammy_avatar.png?auto=compress,format"},"_meta":{"uid":"digitalocean"}},"blog_header_image":null,"blog_headline":[{"type":"heading1","text":"Update on CVE-2015-3456, aka the VENOM Security Vulnerability","spans":[]}],"blog_post_content":[{"type":"paragraph","text":"Earlier today, CVE-2015-3456, a security vulnerability also known as VENOM was publicly announced. This bug in KVM/QEMU, our virtualization environment, could potentially exploit a VM's virtual floppy driver as described in detail here and here. DigitalOcean has conducted a thorough audit of our platform and taken steps to mitigate the issue.","spans":[{"start":231,"end":235,"type":"hyperlink","data":{"link_type":"Web","url":"https://access.redhat.com/articles/1444903"}},{"start":240,"end":244,"type":"hyperlink","data":{"link_type":"Web","url":"http://www.ubuntu.com/usn/usn-2608-1/"}}]},{"type":"paragraph","text":"On hypervisors running the latest version of our cloud, the QEMU process is confined by a mandatory access control profile which would prevent a would-be attacker from accessing the host system or other Droplets. We are rolling out updates across all of our infrastructure to ensure the latest QEMU security patches are applied on each server. In addition, we have implemented a number of other security and monitoring features in order to provide early warning of attempts to exploit similar vulnerabilities.","spans":[]},{"type":"paragraph","text":"In order to complete the process of applying the security patches, a small number of our hypervisors will require a reboot. Our team is currently working to schedule this in the least disruptive manner possible. We will keep you posted on our progress.","spans":[]},{"type":"paragraph","text":"If you have any additional questions, please reach out to our support team:","spans":[]},{"type":"paragraph","text":"https://cloud.digitalocean.com/support","spans":[{"start":0,"end":38,"type":"hyperlink","data":{"link_type":"Web","url":"https://cloud.digitalocean.com/support"}}]}],"blog_post_date":"2015-05-12","tags":[{"tag1":{"tag":"Engineering","_linkType":"Link.document","_meta":{"uid":"engineering"}}}],"_meta":{"uid":"update-on-cve-2015-3456"}}},{"node":{"author":{"_linkType":"Link.document","author_name":"DigitalOcean","author_image":{"dimensions":{"width":600,"height":600},"alt":"Sammy avatar","copyright":null,"url":"https://images.prismic.io/www-static/a10e3c2eb15b74ee43f872be3044313423b1c9a9_sammy_avatar.png?auto=compress,format"},"_meta":{"uid":"digitalocean"}},"blog_header_image":{"dimensions":{"width":784,"height":418},"alt":"Our 2014 Transparency Report text on top of illustration","copyright":null,"url":"https://images.prismic.io/www-static/764569d576ee40dd5ea18638e28b70b11dd0ab58_hero-1.jpg?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"DigitalOcean's 2014 Transparency Report","spans":[]}],"blog_post_content":[{"type":"paragraph","text":"Today we publish DigitalOcean's first ever Transparency Report. You can take a look here.","spans":[{"start":84,"end":88,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/legal/transparency/"}}]},{"type":"paragraph","text":"The Transparency Report allows us to inform our users of the exact number of government data requests we receive, and the laws used to justify those requests. As of today less than 0.05% of our users have ever had data requested. As you read the report, you'll notice that we frequently reject requests that are overly broad, or have inadequate authority. Now you'll be able to see all the details for yourself.","spans":[]},{"type":"image","url":"https://images.prismic.io/www-static/30ad8a58782c6ffd8e7dfffca340a706d3cc696f_requests-vs-droplets.jpg?auto=compress,format","alt":"Information Requests vs. Droplets","copyright":null,"dimensions":{"width":784,"height":490}},{"type":"paragraph","text":"The Transparency Report details a few things: definitions of the types of requests we receive, the number of each type of request, and how we responded (in aggregate). These data reflect activity in 2014, and currently count only the number of requests received, not how many user accounts might be affected, although generally a request will impact only one account.","spans":[]},{"type":"paragraph","text":"Like many cloud computing companies, DigitalOcean occasionally receives requests from law enforcement regarding one of the hundreds of thousands of servers hosted in our network. DigitalOcean's policy is to comply with law enforcement requests only when legally compelled. That means we stand with our users when the government asks us for data by not disclosing users' content without a warrant[^warrant], by informing users about government data requests unless legally prevented, and starting today, by publishing a transparency report.","spans":[]},{"type":"paragraph","text":"Privacy and data protection are challenging issues facing our society as more and more of our lives and data move to the cloud. If you'd like to read more about digital privacy, check out the fine work of EFF and Digital Due Process.","spans":[{"start":205,"end":208,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.eff.org/"}},{"start":213,"end":232,"type":"hyperlink","data":{"link_type":"Web","url":"http://digitaldueprocess.org/"}}]},{"type":"paragraph","text":"Moving forward, we'll publish this report semi-annually. For more detail on how we process requests from law enforcement, we've also made public our Law Enforcement Guide. We've also created this FAQ. So, check back every six months to read the latest Transparency Report.","spans":[{"start":149,"end":170,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/legal/enforcement/"}},{"start":196,"end":199,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/help/privacy/"}},{"start":252,"end":271,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/legal/transparency/"}}]}],"blog_post_date":"2015-05-11","tags":[{"tag1":{"tag":"News","_linkType":"Link.document","_meta":{"uid":"news"}}}],"_meta":{"uid":"digitaloceans-transparency-report"}}},{"node":{"author":{"_linkType":"Link.document","author_name":"Erika Heidi","author_image":null,"_meta":{"uid":"erika_heidi"}},"blog_header_image":{"dimensions":{"width":784,"height":392},"alt":"Horizontally Scaling PHP Applications text on illustration of elephants walking linking trunks and tails","copyright":null,"url":"https://images.prismic.io/www-static/b8ae3d37c96d34df42840479b49ae13601411d0c_hero-2.jpg?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"Horizontally Scaling PHP Applications","spans":[]}],"blog_post_content":[{"type":"paragraph","text":"Shipping a website or application to production has its own challenges, but when it gets the right traction, it's a great accomplishment. It always feels good to see the visitor numbers going up, doesn't it? Except, of course, when your traffic increases so much that it crashes your little LAMP stack. No matter what time or day it is, the cost of your app being offline is just too high, and in many cases it brings irreversible losses to a business.","spans":[]},{"type":"paragraph","text":"But fear not! There are ways to make your PHP application much more reliable and consistent. If the term scalability crossed your mind, you've got the right idea.","spans":[]},{"type":"paragraph","text":"In a nutshell, scalability is the ability of a system to handle an increased amount of traffic or processing and accommodate growth while maintaining a desirable user experience. There are basically two ways of scaling a system: vertically, also known as scaling up, and horizontally, also known as scaling out.","spans":[{"start":15,"end":26,"type":"em"},{"start":255,"end":265,"type":"em"},{"start":299,"end":310,"type":"em"}]},{"type":"paragraph","text":"Vertical scaling is accomplished by increasing system resources, like adding more memory and processing power. Resizing a Droplet, for instance, is vertical scaling. While this can work as an immediate solution, it might be hiding the real problems underneath your application, and there's no guarantee a server twice as powerful will run your app twice as fast.","spans":[]},{"type":"paragraph","text":"Horizontal scaling, on the other hand, is accomplished by adding more servers to an existing cluster. Let's talk about exactly what that means.","spans":[]},{"type":"heading2","text":"What is Horizontal Scaling?","spans":[]},{"type":"paragraph","text":"A cluster is simply a group of servers. A load balancer distributes the workload between the servers in a cluster. At any point, a new web server can be added to the existing cluster to handle more requests from users accessing your application; this is horizontal scaling.","spans":[{"start":2,"end":9,"type":"em"},{"start":42,"end":55,"type":"em"},{"start":42,"end":55,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/products/load-balancer/"}}]},{"type":"paragraph","text":"Here's an example of horizontal scaling in a diagram:","spans":[]},{"type":"image","url":"https://images.prismic.io/www-static/76831544fbe08331f8e10fd4bbbf588b62cf2506_horizontal-scaling.png?auto=compress,format","alt":"Horizontal Scaling","copyright":null,"dimensions":{"width":745,"height":290}},{"type":"paragraph","text":"The load balancer has a single responsibility: deciding which server from the cluster will receive a request that was intercepted. It basically acts like a reverse proxy, making the process seamless to the user.","spans":[{"start":156,"end":169,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/how-to-configure-nginx-as-a-reverse-proxy-for-apache"}}]},{"type":"paragraph","text":"While horizontal scaling is usually the most reliable and efficient method of scalability, it's not as trivial as vertical scaling. In a nutshell, the main challenges of scaling web applications is keeping all the nodes in a cluster updated and synchronized. Consider the following scenario.","spans":[]},{"type":"image","url":"https://images.prismic.io/www-static/2fe03cbc25037e98fd32549bdbef40378f5868f8_scenario.png?auto=compress,format","alt":"Horizontal Scaling","copyright":null,"dimensions":{"width":745,"height":293}},{"type":"paragraph","text":"When user A makes a request to mydomain.com, the load balancer will forward requests to server1. User B, on the other hand, gets forwarded another node from the cluster, server2.","spans":[]},{"type":"paragraph","text":"What happens when user A makes changes to the application, like uploading files or updating content in the database? How do you maintain consistency across all nodes in the cluster? Further, PHP saves session information in disk by default. If user A logs in, how can we keep that user's session in subsequent requests, considering that the load balancer could send them to another server in the cluster?","spans":[]},{"type":"paragraph","text":"Let's discuss what can be done to overcome these issues and prepare your existing PHP application for horizontal scaling.","spans":[]},{"type":"heading2","text":"Decouple, Decouple, Decouple","spans":[]},{"type":"paragraph","text":"Preparing a system for scalability involves a lot of decoupling, because it's essential to have smaller servers with fewer responsibilities instead of one giant, all-inclusive server. This is really the essence of horizontal scaling. Breaking the application down into parts will also help you measure and identify the real bottlenecks you might have.","spans":[]},{"type":"paragraph","text":"Consider a PHP application where users can log in and upload photos. The app uses a basic LAMP stack, and the photos are stored in disk and referenced in the database. The challenge here is to keep consistency between multiple application servers sharing the same data (user uploaded files and user sessions).","spans":[]},{"type":"paragraph","text":"In order to make this example application scalable, there needs to be a separation between web server and database. This way, we can have multiple application nodes sharing the same database server. It's a first step, and it will give the app a small performance improvement by reducing the load of the web server. This tutorial can help you with that.","spans":[{"start":315,"end":328,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/how-to-set-up-a-remote-database-to-optimize-site-performance-with-mysql"}}]},{"type":"paragraph","text":"For further scalability, you should also consider implementing a load balancing environment for the database. This tutorial shows how to set up a load balancer for a MySQL cluster.","spans":[{"start":110,"end":123,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/how-to-use-haproxy-to-set-up-mysql-load-balancing--3"}}]},{"type":"heading2","text":"User Session Consistency","spans":[]},{"type":"paragraph","text":"Once the application is isolated from the database server, we can focus on issues specific to the PHP implementation. First, we need to figure out a way for handling the user sessions across the nodes. Let's talk about a few approaches.","spans":[]},{"type":"heading3","text":"Relational Databases and Network Filesystems","spans":[]},{"type":"paragraph","text":"Many people use the approach of saving the session data in relational databases, like MySQL, because it's fairly easy to implement. However, this is a less desirable solution because it adds a substantial overhead (reading and writing to the database for every single request), and in high-traffic incidents, the database is usually the first to go down.","spans":[]},{"type":"paragraph","text":"Similarly, using a network filesystem is another easy solution to implement as it doesn't require any changes to the codebase, but network filesystems are slow for I/O operations (again, reading and writing for each request made) and this might have a negative impact in the application performance.","spans":[]},{"type":"paragraph","text":"Sticky Sessions","spans":[]},{"type":"paragraph","text":"Sticky sessions are implemented in the load balancer and don't require any change in the application nodes, so this is the easiest way to handle user sessions. Sticky sessions make the load balancer always redirect a user to the same server, avoiding the need for sharing session information across nodes.","spans":[]},{"type":"paragraph","text":"However, this solution creates new problems. The load balancer now has more responsibilities, which can impact its performance and turn it into a single point of failure. This approach can also create cold and hot spots within the cluster; returning users will always access the same server, even when new nodes are added to the cluster.","spans":[]},{"type":"heading3","text":"Using a Memcached or Redis Server","spans":[]},{"type":"paragraph","text":"This solution requires setting up one or more additional servers to handle the user sessions, but it's the most reliable way for solving the sessions problem. Both Memcached and Redis are super fast key-value storage engines that provide session handling for PHP. In a nutshell, after setting up the Memcached or Redis server, you will need to configure each node to be able to connect to the server and use it as session handler. This includes installing a PHP extension and making a simple change in the php.ini settings.","spans":[{"start":164,"end":173,"type":"hyperlink","data":{"link_type":"Web","url":"http://memcached.org/"}},{"start":178,"end":183,"type":"hyperlink","data":{"link_type":"Web","url":"http://redis.io/"}}]},{"type":"paragraph","text":"More information about setting up the Memcached session handler for PHP can be found in the official PHP documentation. For Redis, you can find a detailed guide in this link.","spans":[{"start":92,"end":118,"type":"hyperlink","data":{"link_type":"Web","url":"http://php.net/manual/en/memcached.sessions.php"}},{"start":161,"end":173,"type":"hyperlink","data":{"link_type":"Web","url":"http://phpave.com/redis-as-a-php-session-handler/"}}]},{"type":"heading2","text":"User File Consistency","spans":[]},{"type":"paragraph","text":"So far, we've separated our application and database and dealt with the user session consistency problem. We still need to find a solution to keep consistency between the files uploaded by users, because they could be stored in any of the application nodes.","spans":[]},{"type":"paragraph","text":"There are different methods for solving this problem. In some ways it is similar to the user sessions case, but fortunately, it's actually much simpler. The files are not written to or read from disk for each request, which makes the file sharing not as resource intensive. A solution like GlusterFS can work really well here, which creates a shared storage that will replicate any contents saved into one node to other nodes in the cluster. You can find detailed instructions on how to use GlusterFS to set up such an environment in this tutorial.","spans":[{"start":290,"end":299,"type":"hyperlink","data":{"link_type":"Web","url":"http://www.gluster.org/"}},{"start":531,"end":547,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/how-to-create-a-redundant-storage-pool-using-glusterfs-on-ubuntu-servers"}}]},{"type":"paragraph","text":"Another popular solution is to use object storage to save the files. This can be implemented using different methods, from simple database blob storage to cloud storage services like AWS S3 and Google Cloud Storage. However, it might require a considerable amount of changes to the codebase, depending on how the application is implemented.","spans":[{"start":35,"end":49,"type":"hyperlink","data":{"link_type":"Web","url":"http://en.wikipedia.org/wiki/Object_storage"}},{"start":183,"end":189,"type":"hyperlink","data":{"link_type":"Web","url":"http://aws.amazon.com/s3/"}},{"start":194,"end":214,"type":"hyperlink","data":{"link_type":"Web","url":"https://cloud.google.com/storage/"}}]},{"type":"heading2","text":"Load Balancing","spans":[]},{"type":"paragraph","text":"With the application properly decoupled, it's finally possible to create replica nodes that will compose the app cluster. Our example app now has the following setup:","spans":[]},{"type":"image","url":"https://images.prismic.io/www-static/120f16e988bb674257d6445a4694f7b64932220e_load-balancing.png?auto=compress,format","alt":"Load Balancing","copyright":null,"dimensions":{"width":745,"height":286}},{"type":"paragraph","text":"Both App01 and App02 should be accessible and able to handle requests in the exact same way. The only thing left to do is set up the load balancer to act as the application entry point, redirecting users to the different nodes in the cluster.","spans":[]},{"type":"paragraph","text":"HAProxy (which stands for High Availability Proxy) is the standard open source choice for load balancing. It's used by high-profile environments like Twitter, Instagram, and Imgur. For a better understanding on how HAProxy works and different ways to configure it, check out this introductory tutorial.","spans":[{"start":0,"end":7,"type":"hyperlink","data":{"link_type":"Web","url":"http://www.haproxy.org/"}},{"start":275,"end":301,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/an-introduction-to-haproxy-and-load-balancing-concepts"}}]},{"type":"paragraph","text":"Another great tutorial from our community explains how to setup HAProxy as load balancer for WordPress servers. It's a good starting point to understand the practical steps necessary to horizontally scale PHP applications.","spans":[{"start":51,"end":110,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/how-to-use-haproxy-as-a-layer-4-load-balancer-for-wordpress-application-servers-on-ubuntu-14-04"}}]},{"type":"paragraph","text":"Final Considerations","spans":[]},{"type":"paragraph","text":"Preparing an application for horizontal scaling may look intimidating at first, but once you understand how the load balancer works, it gets easier to figure out what steps should be taken in order to get your environment ready for scale.","spans":[]},{"type":"paragraph","text":"Naturally, it's much easier to plan for scalability when you are building an application from scratch, but we don't always have this luxury. It also worth mentioning that scalability walks side by side with performance, but they are not the same thing, and not all applications need to be scalable. Speed, on the other hand, is something all apps can benefit from.","spans":[]},{"type":"paragraph","text":"If you want to learn more, take a look at our YouTube playlist with some of the best talks on PHP performance and scaling, and check out load balancers on DigitalOcean!","spans":[{"start":46,"end":62,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.youtube.com/playlist?list=PLseEp7p6EwiaiJx-AZqXgvpJNJgXuNeBx"}},{"start":137,"end":151,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/products/load-balancer/"}}]},{"type":"paragraph","text":"by Erika Heidi","spans":[{"start":3,"end":14,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/erikaheidi"}}]}],"blog_post_date":"2015-04-21","tags":[{"tag1":{"tag":"Engineering","_linkType":"Link.document","_meta":{"uid":"engineering"}}}],"_meta":{"uid":"horizontally-scaling-php-applications"}}},{"node":{"author":{"_linkType":"Link.document","author_name":"DigitalOcean","author_image":{"dimensions":{"width":600,"height":600},"alt":"Sammy avatar","copyright":null,"url":"https://images.prismic.io/www-static/a10e3c2eb15b74ee43f872be3044313423b1c9a9_sammy_avatar.png?auto=compress,format"},"_meta":{"uid":"digitalocean"}},"blog_header_image":{"dimensions":{"width":1633,"height":817},"alt":"frankfurt datacenter","copyright":null,"url":"https://images.prismic.io/www-static/7836ee78-aff4-405c-83cb-54b09714ad3c_fra1.jpg?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"Introducing Our New European Region: Frankfurt! (FRA1)","spans":[]}],"blog_post_content":[{"type":"paragraph","text":"We're opening the new German region for business! Our new FRA1 facility, located in Frankfurt am Main, Germany, gives us an unparalleled opportunity to serve the growing German startup community and developers around the world.","spans":[]},{"type":"paragraph","text":"We announced the new German region five months ago and after a month of build out, we are excited to open FRA1, co-located with Interxion. The new region features our latest cloud spec and the full range of DigitalOcean features including Metadata, CoreOS, and IPv6.","spans":[]},{"type":"paragraph","text":"New in FRA1:","spans":[{"start":0,"end":11,"type":"strong"}]},{"type":"list-item","text":"40GbE networking on each hypervisor","spans":[]},{"type":"list-item","text":"Enhanced storage on hypervisors using our fastest-yet SSDs","spans":[]},{"type":"paragraph","text":"We expect these features to provide the fast-growing German technology and information industry with DigitalOcean's fastest-ever connectivity and hardware.","spans":[]},{"type":"paragraph","text":"Due to its placement on the German Commercial Internet Exchange (DE-CIX), the largest Internet exchange point worldwide by peak traffic, this region also serves Germany's neighboring countries with unparalleled connectivity and speeds. Like our other European locations, the German region meets Safe Harbor regulations for storing data.","spans":[]},{"type":"paragraph","text":"The story of the German startup community is tremendous. We hope that by launching this new region, we can play our part in supporting innovation in Germany. You can try a server in FRA1 from the Droplet create page.","spans":[{"start":192,"end":215,"type":"hyperlink","data":{"link_type":"Web","url":"https://cloud.digitalocean.com/droplets/new"}}]}],"blog_post_date":"2015-04-14","tags":[{"tag1":{"tag":"News","_linkType":"Link.document","_meta":{"uid":"news"}}}],"_meta":{"uid":"introducing-our-new-european-region-frankfurt"}}},{"node":{"author":{"_linkType":"Link.document","author_name":"DigitalOcean","author_image":{"dimensions":{"width":600,"height":600},"alt":"Sammy avatar","copyright":null,"url":"https://images.prismic.io/www-static/a10e3c2eb15b74ee43f872be3044313423b1c9a9_sammy_avatar.png?auto=compress,format"},"_meta":{"uid":"digitalocean"}},"blog_header_image":{"dimensions":{"width":784,"height":392},"alt":"API v2 letters on illustration ","copyright":null,"url":"https://images.prismic.io/www-static/a5e8bb97b3671f4d3b85bd49704a7d026ac5b5b7_apiv2.png?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"API v2 Officially Leaves Beta","spans":[]}],"blog_post_content":[{"type":"paragraph","text":"We are very pleased to announce that API v2 is coming out of beta, nine months after its initial release. With this release we wanted to introduce new features not available in v1, while maintaining the level of simplicity developers loved in our first version. To help us keep it simple and stomp out bugs, we called on the community to collaborate with us in a public GitHub repository. The last nine months of collaboration with the community ensured our API remained awesome as we added these new features.","spans":[]},{"type":"paragraph","text":"Our previous API was simple and easy to use. However, it lacked features allowing developers to interact with DigitalOcean in more advanced ways. We knew we wanted to include new features like:","spans":[]},{"type":"list-item","text":"OAuth","spans":[]},{"type":"list-item","text":"Pagination","spans":[]},{"type":"list-item","text":"A (more) RESTful interface","spans":[]},{"type":"paragraph","text":"We wanted to add all of these features in v2, but were wary of increasing the complexity for our community. So, our first tactic was to introduce only new features the community was actually requesting. This involved taking internal and customer feedback even before launching in beta through UserVoice, internal dogfooding, and support tickets. Then during the beta, we received a constant stream of new feedback via the public GitHub repo.","spans":[{"start":293,"end":302,"type":"hyperlink","data":{"link_type":"Web","url":"https://digitalocean.uservoice.com/"}},{"start":422,"end":440,"type":"hyperlink","data":{"link_type":"Web","url":"https://github.com/digitalocean/api-v2"}}]},{"type":"paragraph","text":"Close collaboration with the community allowed us to fix several bugs as well as add a couple of very useful features. We received a high amount of feedback about the images endpoint, for example — specifically around filtering and maintaining an acceptable level of response time. Many of our users have a large number of snapshots and backups, so the ability to request different types of images via this endpoint proved very useful. Some other features which made it in thanks to community feedback include:","spans":[]},{"type":"list-item","text":"Increasing the base rate limit","spans":[]},{"type":"list-item","text":"Adding more information to the user endpoint","spans":[]},{"type":"list-item","text":"Clarifying the API documentation","spans":[]},{"type":"list-item","text":"Adding stronger validations to the Droplet creation process","spans":[]},{"type":"paragraph","text":"Our second tactic was to keep the API as consistent as possible to reduce the cognitive load on the developer. As an example, we made sure all region objects in JSON responses follow the same format.","spans":[]},{"type":"paragraph","text":"The final tactic was to beef up our API docs by launching our new developer portal. The new portal provides clear documentation, links to community tutorials to get started, and a centralized repository of API libraries.","spans":[{"start":62,"end":82,"type":"hyperlink","data":{"link_type":"Web","url":"https://developers.digitalocean.com/"}}]},{"type":"list-item","text":"API v2 Documentation includes example CURL requests paired with JSON responses","spans":[{"start":0,"end":20,"type":"hyperlink","data":{"link_type":"Web","url":"https://developers.digitalocean.com/documentation/v2/"}}]},{"type":"list-item","text":"Metadata API Documentation","spans":[{"start":0,"end":26,"type":"hyperlink","data":{"link_type":"Web","url":"https://developers.digitalocean.com/documentation/metadata/"}}]},{"type":"list-item","text":"OAuth API Documentation","spans":[{"start":0,"end":23,"type":"hyperlink","data":{"link_type":"Web","url":"https://developers.digitalocean.com/documentation/oauth/"}}]},{"type":"list-item","text":"Community Guides for using the API, including how-tos for beginners to get started","spans":[{"start":0,"end":16,"type":"hyperlink","data":{"link_type":"Web","url":"https://developers.digitalocean.com/guides/"}}]},{"type":"list-item","text":"Libraries written by DigitalOcean and the community","spans":[{"start":0,"end":9,"type":"hyperlink","data":{"link_type":"Web","url":"https://developers.digitalocean.com/libraries/"}}]},{"type":"list-item","text":"Changelog","spans":[{"start":0,"end":9,"type":"hyperlink","data":{"link_type":"Web","url":"https://developers.digitalocean.com/documentation/changelog/"}}]},{"type":"paragraph","text":"We would like to thank everyone who helped report bugs and suggest features during the beta period. Thanks to you, API v2 is finally launched! Try it out here.","spans":[{"start":154,"end":158,"type":"hyperlink","data":{"link_type":"Web","url":"https://developers.digitalocean.com/documentation/v2/"}}]}],"blog_post_date":"2015-04-01","tags":[{"tag1":{"tag":"Product Updates","_linkType":"Link.document","_meta":{"uid":"product-updates"}}}],"_meta":{"uid":"apiv2-officially-leaves-beta"}}}]}}}