kvp 谱

tech2023-09-28  95

kvp 谱

A few weeks ago, I wrote about getting started with Amazon’s SDK for PHP. This article assumes you’re familiar with the basic concepts of using the SDK. Now we’re going to build on that knowledge to create something cool: a light, but powerful data storage system that can scale forever.

几周前,我写过关于Amazon SDK for PHP入门的文章 。 本文假定您熟悉使用SDK的基本概念。 现在,我们将基于这些知识来创建一些很棒的东西:一个轻便但功能强大的数据存储系统,可以永久扩展。

When you think of cloud storage, most of the time you think of media, such as photos, videos, and other content files. But cloud storage is also a great place to store other data.

当您想到云存储时,大多数时候您都会想到媒体,例如照片,视频和其他内容文件。 但是云存储还是存储其他数据的好地方。

In this article I’ll describe how to create a high-performance system for storing extraneous item-specific data using cloud storage instead of a database.

在本文中,我将介绍如何创建一个高性能系统,以使用云存储而不是数据库来存储无关的特定于项目的数据。

For example, let’s say you’re building a user account system. Sure, you’ll have the basics, including email address, password, first name and last name, etc. You might have a number of of details about the user, such as address, birthday, and much more. Many of these fields need to be stored in the database because you will want to be able to search and filter your users.

例如,假设您正在构建一个用户帐户系统。 当然,您将拥有基本知识,包括电子邮件地址,密码,名字和姓氏等。您可能会拥有许多有关用户的详细信息,例如地址,生日等。 这些字段中的许多字段都需要存储在数据库中,因为您将希望能够搜索和过滤用户。

But some data you might want to add doesn’t need to be searchable, or it might be too big to be stored efficiently in a database. For example, perhaps you’d like to allow the user to customize the look and feel of your web app. They will be able to select a few colors, upload a logo, and configure other display options. These options don’t need to be searchable in a database, but you do need a way to easily and reliably access this information when each user signs in.

但是,您可能要添加的某些数据不必是可搜索的,或者可能太大而无法有效地存储在数据库中。 例如,也许您想允许用户自定义Web应用程序的外观。 他们将能够选择几种颜色,上载徽标以及配置其他显示选项。 这些选项不需要在数据库中进行搜索,但是您确实需要一种在每个用户登录时轻松可靠地访问此信息的方法。

Amazon’s S3 storage solution provides an extremely easy solution. Here’s how to do it:

亚马逊的S3存储解决方案提供了极为简单的解决方案。 方法如下:

要求 (Requirements)

S3 Service – You’ll need an Amazon AWS account with S3 enabled.

S3 服务 –您需要启用了S3的Amazon AWS帐户。

S3 Bucket – You’ll need to create an S3 bucket (discussed in my previous article). In our code, we’ll refer to this bucket as “my-unique-bucket-name”. You’ll use your own bucket name instead.

S3存储桶 –您需要创建一个S3存储桶(在我的上一篇文章中讨论过 )。 在我们的代码中,我们将此存储桶称为“ my-unique-bucket-name”。 您将使用自己的存储桶名称。

Web Hosting – You’ll need a regular web host. However, for this particular use case, it is advisable to host your application in the cloud at Amazon on an Amazon EC2 virtual server. The reason is that, when you host your website on an Amazon EC2 instance, all traffic between your server and Amazon S3 is completely free. Hosting anywhere else will incur charges. For testing and setup, these charges are insignificant (and will most likely fall under Amazon’s free usage tiers), but for the long term it’s a good idea to setup on EC2.

虚拟主机 –您需要常规的虚拟主机。 但是,对于此特定用例,建议将您的应用程序托管在Amazon EC2虚拟服务器上的Amazon云中。 原因是,当您在Amazon EC2实例上托管网站时,服务器与Amazon S3之间的所有流量都是完全免费的。 在其他任何地方托管都会产生费用。 对于测试和设置,这些费用微不足道(很可能属于Amazon的免费使用级别),但从长远来看,在EC2上进行设置是一个好主意。

潜入守则 (Diving into the Code)

Time to get our feet wet…

是时候让我们的脚湿了……

Basic PHP Class

基本PHP类

In order to make this system as easy as possible, we’re going to be building a simple PHP class. This will make it easy for us to use a KVP (Key-value-pair) concept for almost anything you can imagine. So to start, create a minimal class that 1) accepts an argument called “itemName” and 2) automatically creates an Amazon S3 object with the AWS SDK. Again, if you’re not sure where we are, start by reading this article.

为了使该系统尽可能简单,我们将构建一个简单PHP类。 这将使我们可以轻松将KVP(键值对)概念用于几乎您可以想象的任何事情。 因此,首先创建一个最小类,该最小类包括1)接受称为“ itemName”的参数,以及2)使用AWS开发工具包自动创建Amazon S3对象。 同样,如果您不确定我们在哪里,请先阅读本文 。

class s3Kvp { private $itemName = Null; // Property to store item name throughout the class. private $awsS3 = Null; // Property to store an instance of the S3 Object // Construct runs when we create the class. public function __construct($itemName) { $this->itemName = $itemName; // Store item name as class property. $this->awsS3 = new AmazonS3(); // Create s3 object as class property. } } // Create a new instance of the class // Submitting 'user101' as the item name // will allow us to store KVP data specifically // for User with ID 101. $myKvp = new s3Kvp('user101'); // We can create a separate instance of this class // submitting a different itemName. In this case, // data will be stored specifcially for User with ID 335. $anotherKvp = new s3Kvp('user335'); // Of course, none of this does anything quite yet...

Loading the Data

加载数据

Now we’re going to add a few new essentials to our class, including two new properties: one to store the actual data while the class is in use, and one to tell us if the data is dirty (if it has changed since we loaded it). We’re also going to try to load our data from S3. It’s starting to look a little complicated, but you can follow the comments for all the new functionality we’re adding:

现在,我们将向我们的类添加一些新的要点,包括两个新属性:一个用于在使用该类时存储实际数据,另一个用于告诉数据是否脏了(如果自从我们修改之后,数据是否已更改)加载)。 我们还将尝试从S3加载数据。 它看起来似乎有点复杂,但是您可以按照注释中的说明添加所有新功能:

class s3Kvp { private $itemName = Null; private $awsS3 = Null; private $data = Null; // We'll store our item data here. private $isDirty = false; // We'll track whether or not anything changed here. private $bucket = 'my-unique-bucket-name'; // This is the "bucket", or domain where your data is stored. public function __construct($itemName) { $this->itemName = $itemName; $this->awsS3 = new AmazonS3(); // Here we're trying to get an object matching our item name // located in the folder 'kvpdata'. // Start by Creating a Secure URL to Access Your Data $url = $this->awsS3->get_object_url('my-unique-bucket-name', 'kvpdata/'.$this->itemName, '10 Days'); // Then grab the contents of the URL // The @ will allow the script to continue // if the URL cannot be reached. $responseData = false; $responseData = @file_get_contents($url); // If we got something back in our response data, // load it into the "data" property of this class. if ($responseData) { // We're going to store our data as an array encoded JSON, // so if we get anything we know we can // decode it back to an array. $responseAsArray = json_decode($responseData, true); // Check if the data is valid. if (is_array($responseAsArray)) { // It's valid! Load it up. $this->data = $responseAsArray; } else { // Not valid! Load an empty array. // A good app would do some error handling here. $this->data = array(); } } else { // If we don't get anything back, // it means this item is new so we're just going to // load 'data' as an empty array. $this->data = array(); } } }

Object Overloading

对象重载

Overloading in PHP provides means to dynamically “create” properties and methods. It’s really fun, and we’re going to use it to dynamically store item data.

PHP中的重载提供了动态“创建”属性和方法的方法。 这真的很有趣,我们将使用它来动态存储项目数据。

We’re going to create two new methods in our class. One, called “__get”, will allow us to easily retrieve information stored in our item data. The other, “__set”, will allow us to update existing data and store new data.

我们将在类中创建两个新方法。 一个名为“ __get”的文件将使我们能够轻松检索存储在商品数据中的信息。 另一个“ __set”将使我们能够更新现有数据并存储新数据。

Here’s how it works:

运作方式如下:

If you created a new instance of our s3Kvp class called $myKvp and you want to access the property customBackgroundColor (so $myKvp->customBackgroundColor), you will get an error because that property doesn’t exist.

如果您创建了一个名为$ myKvp的s3Kvp类的新实例,并且想要访问属性customBackgroundColor(因此$ myKvp-> customBackgroundColor),则会收到错误消息,因为该属性不存在。

But if we create a method called “__get” in our class, PHP will run that function before getting an error. This allows us to dynamically access data. The same thing works with “__set”. If a property doesn’t exist, but you try to set it, the “__set” method will be called if it exists.

但是,如果我们在类中创建一个名为“ __get”的方法,PHP将在出现错误之前运行该函数。 这使我们能够动态访问数据。 “ __set”同样适用。 如果一个属性不存在,但是您尝试设置它,则“ __set”方法将被调用(如果存在)。

Here’s the code:

这是代码:

class s3Kvp { // This function will be called anytime // we try to RETRIEVE properties of our class // that do not exist. public function __get($propertName) { // Check to see if we have that property in our // data array. if (isset($this->data[$propertName])) { // If we have it, return it. // Simple, right!? return $this->data[$propertName]; } else { // If not, return false; return false; } } // This function will be called anytime // we try to SET properties of our class // that do not exist. public function __set($propertName, $propertyValue) { // Simply set the propertyName submitted // in our data array to the value submitted. $this->data[$propertName] = $propertyValue; // One more thing... // We want to know if something is ever "set" // so we can mark the data as "dirty". // We'll use this later... $this->isDirty = true; } private $itemName = Null; private $awsS3 = Null; private $data = Null; private $isDirty = false; private $bucket = 'my-unique-bucket-name'; public function __construct($itemName) { $this->itemName = $itemName; $this->awsS3 = new AmazonS3(); $url = $this->awsS3->get_object_url('my-unique-bucket-name', 'kvpdata/'.$this->itemName, '10 Days'); $responseData = false; $responseData = @file_get_contents($url); if ($responseData) { $responseAsArray = json_decode($responseData, true); if (is_array($responseAsArray)) { $this->data = $responseAsArray; } else { $this->data = array(); } } else { $this->data = array(); } }

Save that Baby

救那个宝贝

Now our class is starting to take shape. We can load data from S3, and we can set and retrieve data values. But something is still missing—saving the data. We need to send it back up to S3.

现在我们的班级开始形成。 我们可以从S3加载数据,并且可以设置和检索数据值。 但是仍然缺少一些东西–保存数据。 我们需要将其发送回S3。

To do this, we’re going to utilize the __destruct method built into PHP classes. This method, if it exists, is called right before PHP terminates the class. So if we create the method, it will be called each time we use an instance of the class, once PHP knows we’re done with it.

为此,我们将利用内置在PHP类中的__destruct方法。 此方法(如果存在)在PHP终止类之前立即调用。 因此,如果我们创建该方法,则一旦PHP知道我们已完成处理,则每次使用该类的实例时都会调用该方法。

In the __destruct method, we’re going to check if our class “isDirty”, and if so we’ll save our changes up to S3. Before we save, however, we’re going to convert our data to JSON. This makes it easy to store and, if we ever need to, easy to access by other systems.

在__destruct方法中,我们将检查类是否为“ isDirty”,如果是,我们将所做的更改保存到S3。 但是,在保存之前,我们将数据转换为JSON。 这使得它易于存储,并且,如果需要,可以方便地被其他系统访问。

class s3Kvp { // The __destruct is called by PHP as // each instance of this class is destroyed. public function __destruct() { // Check if "isDirty" is true, // which tells us that at some point // during the script execution // data was changed. if ($this->isDirty) { // Encode our data as JSON. $dataToSave = json_encode($this->data); // Use "create_object" to upload the data // back to S3. If the object already exists, // this will simply replace it. $options = array('body' => $dataToSave); $this->awsS3->create_object('my-unique-bucket-name', 'kvpdata/'.$this->itemName, $options); } } public function __get($propertName) { if (isset($this->data[$propertName])) { return $this->data[$propertName]; } else { return false; } } public function __set($propertName, $propertyValue) { $this->data[$propertName] = $propertyValue; $this->isDirty = true; } private $itemName = Null; private $awsS3 = Null; private $data = Null; private $isDirty = false; private $bucket = 'my-unique-bucket-name'; public function __construct($itemName) { $this->itemName = $itemName; $this->awsS3 = new AmazonS3(); $url = $this->awsS3->get_object_url('my-unique-bucket-name', 'kvpdata/'.$this->itemName, '10 Days'); $responseData = false; $responseData = @file_get_contents($url); if ($responseData) { $responseAsArray = json_decode($responseData, true); if (is_array($responseAsArray)) { $this->data = $responseAsArray; } else { $this->data = array(); } } else { $this->data = array(); } } }

使用课程 (Using the Class)

Here’s the final class:

这是最后一堂课:

class s3Kvp { private $itemName = Null; private $awsS3 = Null; private $data = Null; private $isDirty = false; private $bucket = 'my-unique-bucket-name'; public function __construct($itemName) { $this->itemName = $itemName; $this->awsS3 = new AmazonS3(); $url = $this->awsS3->get_object_url('my-unique-bucket-name', 'kvpdata/'.$this->itemName, '10 Days'); $responseData = false; $responseData = @file_get_contents($url); if ($responseData) { $responseAsArray = json_decode($responseData, true); if (is_array($responseAsArray)) { $this->data = $responseAsArray; } else { $this->data = array(); } } else { $this->data = array(); } } public function __get($propertName) { if (isset($this->data[$propertName])) { return $this->data[$propertName]; } else { return false; } } public function __set($propertName, $propertyValue) { $this->data[$propertName] = $propertyValue; $this->isDirty = true; } public function __destruct() { if ($this->isDirty) { $dataToSave = json_encode($this->data); $options = array('body' => $dataToSave); $this->awsS3->create_object('my-unique-bucket-name', 'kvpdata/'.$this->itemName, $options); } } }

Of course, now that we did all the work, we want to use this thing! Here are a couple of examples:

当然,既然我们已经完成了所有工作,我们想使用这个东西! 以下是几个示例:

User Account System

用户帐号系统

If you’re building a user account system, you might want to store substantial information that is user-specific. In this example, we’re assuming you have a shopping interface with categories. You allow users to decide how many products they want to view per page. When they make a selection, you update their preference using the user-specific KVP class we created:

如果要构建用户帐户系统,则可能要存储特定于用户的大量信息。 在此示例中,我们假设您具有带有类别的购物界面。 您可以让用户决定每页要查看多少产品。 当他们做出选择时,您可以使用我们创建的特定于用户的KVP类来更新其首选项:

// Include the class we just created. require_once 's3kvp.php'; // Create an instance of s4Kvp // using the current User's ID; $userId = 12301; //This might be stored in cookie or session variable. $userKvp = new s3Kvp('user'.$userId); // In this example, // We're setting the "prefsItemsPerPage" // equal to whatever we received in the // "prefsItemsPerPage" querystring variable; $submittedPreference = $_GET['prefsItemsPerPage']; $userKvp->prefsItemsPerPage = $submittedPreference; echo 'test'; // Include the class we just created. require_once 's3kvp.php'; $userId = 12301; $userKvp = new s3Kvp('user'.$userId); echo $userKvp->prefsItemsPerPage;

Shopping Cart System

购物车系统

I’ve built entire shopping cart systems that use only a KVP class like this. With the advent of Google Analytics, I no longer need to track “partial” or “incomplete” orders. Using a system like this allows me to store tons of shopping details, including robust information about cart items, promotions, checkout data, and much more. All of this is stored in cloud storage until the time of checkout, at which point I copy the specific data I need to be searchable into a database. I never have to worry about increasing my database size with anything but finalized orders.

我建立了整个购物车系统,它们只使用这样的KVP类。 随着Google Analytics(分析)的出现,我不再需要跟踪“部分”或“不完整”的订单。 使用这样的系统,我可以存储大量的购物详细信息,包括有关购物车项目,促销,结帐数据等的强大信息。 所有这些都存储在云存储中,直到结帐时为止,这时我将需要搜索的特定数据复制到数据库中。 除了敲定的订单外,我永远不必担心增加数据库大小。

Of course, for this type of example, I need to create a more robust KVP class—one that can handle lists of items and other features. But the idea is the same: Store item-specific data in cloud storage.

当然,对于这种类型的示例,我需要创建一个更强大的KVP类-一个可以处理项目列表和其他功能的类。 但是想法是相同的:将特定于项目的数据存储在云存储中。

那么现在我们在哪里? (So Now Where Are We?)

In fewer than 50 lines of code, we’ve created a robust system for storing itemspecific data; this system is fast and scalable.

我们用不到50行的代码创建了一个健壮的系统,用于存储特定于项目的数据。 该系统快速且可扩展。

Since I’ve been using systems like this, I’ve been able to keep my database tables very light, only storing information that I know needs to be used in searching, filtering, or summary reports. I don’t have to worry about my database tables growing to enormous sizes, and with S3, I never have to worry about running out of storage or backing up my data.

由于我一直在使用这样的系统,因此我能够使我的数据库表保持非常轻巧,仅存储我知道在搜索,过滤或摘要报告中需要使用的信息。 我不必担心我的数据库表会变得很大,并且使用S3,我永远不必担心存储空间用完或备份数据。

A Few things To Remember

几件事要记住

Without some modifications, I don’t recommend a system like this to store data that will be read by multiple users under heavy load. I do use this concept under heavy load, but I add a caching layer to my KVP class.

如果不做一些修改,我不建议使用像这样的系统来存储将在重负载下被多个用户读取的数据。 我确实在繁重的工作中使用了这个概念,但是我在KVP类中添加了一个缓存层。

Also, you should store your data in an S3 bucket that does not have public access; this is critical for security.

另外,您应该将数据存储在没有公共访问权限的S3存储桶中; 这对于安全性至关重要。

下一步是什么? (What’s Next?)

Now that you have this basic class, you can add on to it to meet your needs. Here are a few things I’ve added to my own applications in the past:

既然您已经有了这个基础课,就可以添加它以满足您的需求。 这是我过去添加到自己的应用程序中的一些内容:

Encryption – For an extra layer of security, I add encryption to this class. I insert it in the __construct and __destruct so that anytime I load or save data, I’m decrypting and encrypting.

加密 –为了增加安全性,我将加密添加到此类。 我将其插入__construct和__destruct中,以便在每次加载或保存数据时都进行解密和加密。

Amazon SimpleDB – This type of system works great in combination with SimpleDB. Amazon SimpleDB is a highly available, flexible, and scalable non-relational data store that offloads the work of database administration. Using SimpleDB in combination with this S3 KVP storage concept allows you to create scalable, flexible systems that remove the concerns about performance or data backup.

Amazon SimpleDB –这种类型的系统与SimpleDB结合使用效果很好。 Amazon SimpleDB是高度可用,灵活且可扩展的非关系数据存储,可减轻数据库管理工作的负担。 结合使用SimpleDB和此S3 KVP存储概念,您可以创建可扩展的灵活系统,从而消除对性能或数据备份的担忧。

Default Data – In many cases, you don’t want to just return “false” when you don’t find specific user data. You can easily specify default values for various properties and return them in the __get function. Since they are defaults, you don’t even need to store them in the item-specific data in S3, which keeps your data lighter.

默认数据 –在许多情况下,当您找不到特定的用户数据时,您不希望仅返回“ false”。 您可以轻松地为各种属性指定默认值,然后在__get函数中将其返回。 由于它们是默认值,因此您甚至不需要将它们存储在S3中特定于项目的数据中,从而使数据更轻便。

Caching – I use caching all the time. Systems like memcached allow you to store data that needs to be accessed frequently on your web server. Adding a caching layer is very similar to adding an encryption layer. At the time of loading, you simply check to see if the data you’re looking for is in cache,and, if it is, load it from cache; otherwise, load it from S3. When you save, you update both the cached version and S3.

缓存 –我一直都在使用缓存。 诸如memcached之类的系统使您可以将需要经常访问的数据存储在Web服务器上。 添加缓存层与添加加密层非常相似。 在加载时,您只需检查要查找的数据是否在高速缓存中,如果是,则从高速缓存中加载; 否则,从S3加载它。 保存时,将同时更新缓存的版本和S3。

Validation – In many cases you’ll want to add data validation to your code. Sometimes you’ll add it right in this KVP class to ensure that data is at least formatted correctly. On the interface side, you’ll want to validate user input whenever it’s submitted before you save it using this KVP class.

验证 –在许多情况下,您需要向代码中添加数据验证。 有时您会在此KVP类中添加它,以确保至少正确格式化了数据。 在界面方面,使用此KVP类保存用户输入之前,您将需要对其进行验证。

Versioning – S3 provides a powerful way to track versions of your data. This is great for creating roll-back functionality. If you turn versioning on in your bucket, Amazon will store a backup version every time you save. You can then roll back to any previous version, anytime. I often use this simply as a backup—if I accidently write code that wipes out data, I can get it back if I have versioning on. There are many other uses. Versioning does increase storage requirements, however, so only use it if you really need it.

版本控制 – S3提供了一种强大的方法来跟踪数据的版本。 这对于创建回滚功能非常有用。 如果您在存储桶中打开版本控制,则每次保存时,Amazon都会存储一个备份版本。 然后,您可以随时回滚到任何以前的版本。 我经常将其简单地用作备份-如果我不小心编写了擦除数据的代码,则在启用版本控制的情况下可以将其取回。 还有许多其他用途。 但是,版本控制确实会增加存储需求,因此仅在确实需要时才使用它。

有什么问题吗 (Questions?)

If you have any questions or ideas about this concept, please start a conversation below. I’d be happy to respond!

如果您对此概念有任何疑问或想法,请在下面开始对话。 我很乐意回应!

翻译自: https://www.sitepoint.com/simple-kvp-system-with-amazon-s3/

kvp 谱

相关资源:kvp-源码
最新回复(0)