<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Viktor Ardelean</title>
    <description>The latest articles on DEV Community by Viktor Ardelean (@viktorardelean).</description>
    <link>https://dev.to/viktorardelean</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1046360%2Fbc493e96-a5e9-4848-9014-d31bcc865e1d.jpeg</url>
      <title>DEV Community: Viktor Ardelean</title>
      <link>https://dev.to/viktorardelean</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/viktorardelean"/>
    <language>en</language>
    <item>
      <title>MCP: The REST Revolution of AI - Why This Protocol Changes Everything</title>
      <dc:creator>Viktor Ardelean</dc:creator>
      <pubDate>Wed, 16 Apr 2025 17:20:30 +0000</pubDate>
      <link>https://dev.to/viktorardelean/mcp-the-rest-revolution-of-ai-why-this-protocol-changes-everything-4p75</link>
      <guid>https://dev.to/viktorardelean/mcp-the-rest-revolution-of-ai-why-this-protocol-changes-everything-4p75</guid>
      <description>&lt;p&gt;You most probably looked up this post to clarify this new AI jargon, and I get you—it's not easy to keep up with all the terminology and know how everything fits together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Good news! You're at the right place!&lt;/strong&gt; &lt;br&gt;
Follow along and you'll understand what all this MCP buzz is about!&lt;/p&gt;
&lt;h2&gt;
  
  
  Before MCP: The Evolution of LLM Apps
&lt;/h2&gt;

&lt;p&gt;To better understand how MCP came to be, let's look at how LLM apps have evolved.&lt;/p&gt;
&lt;h3&gt;
  
  
  Simple LLM Interaction
&lt;/h3&gt;

&lt;p&gt;First, we built AI apps interacting directly with an LLM model. This was great for getting answers to general questions based on the knowledge the model was trained on.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F027usmygan5qd0lavj3i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F027usmygan5qd0lavj3i.png" alt="Image description" width="800" height="693"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The downside? &lt;strong&gt;The LLM model couldn't take any actions in the real world.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example, you could ask the LLM, "What are the best Caribbean islands with white sandy beaches?" and it might tell you about Turks and Caicos or Aruba. But if you then ask, "Can you book me a flight to Aruba for next weekend?" it would have to respond with something like "I don't have the ability to search or book flights" because it can't access real-time flight data or booking systems.&lt;/p&gt;
&lt;h3&gt;
  
  
  LLM with Tools
&lt;/h3&gt;

&lt;p&gt;To solve this limitation, we equipped LLMs with tools.&lt;br&gt;
&lt;strong&gt;Think of tools as separate services that execute specific actions&lt;/strong&gt; (search flights, book hotels, etc.).&lt;/p&gt;

&lt;p&gt;With tools ready, you could build an AI travel assistant where you first tell the LLM, "You have access to a flight_search tool that takes departure_city, destination_city, and dates as parameters, and a hotel_booking tool that takes location, check_in_date, check_out_date, and guests as parameters."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcof8qyj42jwol2ex8diy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcof8qyj42jwol2ex8diy.png" alt="Image description" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now when a user asks, "I want to go to Aruba next weekend from Chicago. Can you help me plan this trip?", the LLM might respond: "I'll help you plan your Aruba trip! Let me check flight options first."&lt;/p&gt;

&lt;p&gt;Then it would call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flight_search(departure_city='Chicago', destination_city='Aruba', departure_date='2025-04-25', return_date='2025-04-27')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After receiving flight results, it might say: "I found several flights! Now let me check hotels."&lt;/p&gt;

&lt;p&gt;Then call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hotel_booking(location='Aruba', check_in_date='2025-04-25', check_out_date='2025-04-27', guests=1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works and enables the LLM to take actions, but there's a major downside: &lt;strong&gt;complexity!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For every tool you want to use, you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write custom code and maintain it&lt;/li&gt;
&lt;li&gt;Handle API authentication and error cases&lt;/li&gt;
&lt;li&gt;Process response formats&lt;/li&gt;
&lt;li&gt;Update your code when APIs change&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Behind the scenes, your AI app needs code that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;flight_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;departure_city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;destination_city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;departure_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;return_date&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Connect to airline API with authentication
&lt;/span&gt;    &lt;span class="n"&gt;api_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AIRLINE_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;# Format request
&lt;/span&gt;    &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt;  &lt;span class="c1"&gt;# Format parameters correctly
&lt;/span&gt;
    &lt;span class="c1"&gt;# Make API call
&lt;/span&gt;    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://airline-api.com/search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Handle errors
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;handle_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Process and format response
&lt;/span&gt;    &lt;span class="n"&gt;flights&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;process_flight_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;flights&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you need similar code for every single integration. When the airline API changes, you have to update your code. It's a maintenance nightmare!&lt;/p&gt;

&lt;h3&gt;
  
  
  Cloud Provider Solutions (Like AWS Bedrock Agents)
&lt;/h3&gt;

&lt;p&gt;Cloud providers recognized this complexity and started offering solutions like AWS Bedrock Agents to simplify the process.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2aul5sragec09ag9df5g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2aul5sragec09ag9df5g.png" alt="Image description" width="800" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With these solutions, much of the orchestration is abstracted away. But &lt;strong&gt;you still need to write custom code&lt;/strong&gt; to execute the actions. If the airline API changes its parameters or response format, you still need to update your code.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem MCP Solves
&lt;/h2&gt;

&lt;p&gt;Did you notice the pattern? There's a &lt;strong&gt;hard dependency between the AI app/agent and the tools it uses&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;If something changes in an external API, your tool code breaks. &lt;strong&gt;Everything is tightly coupled.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  MCP - A Paradigm Shift in AI Architecture
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;MCP (Model Context Protocol) introduces a fundamental change in paradigm.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of AI developers writing custom tool code for every integration, MCP provides a standardized protocol for LLMs to communicate with external services.&lt;/p&gt;

&lt;p&gt;With MCP, there's a clear separation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;LLMs focus on understanding user requests and reasoning&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MCP servers handle the specific domain functionality&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff2zkr2zu73xc62vg38tb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff2zkr2zu73xc62vg38tb.png" alt="Image description" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's see how our travel planning example changes with MCP:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User asks: "I want to go to Aruba next weekend from Chicago"&lt;/li&gt;
&lt;li&gt;Your AI app connects to a travel MCP server&lt;/li&gt;
&lt;li&gt;The LLM says to the MCP server: "I need flight options from Chicago to Aruba for next weekend"&lt;/li&gt;
&lt;li&gt;The MCP server handles all the API calls, authentication, and formatting&lt;/li&gt;
&lt;li&gt;The MCP server returns structured results to the LLM&lt;/li&gt;
&lt;li&gt;The LLM presents the options to the user&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;You don't need to write any custom integration code.&lt;/strong&gt; The MCP server handles all those details for you!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's like the difference between building your own payment processing from scratch versus integrating with Stripe.&lt;/strong&gt; MCP servers do for AI what API providers did for web development - they provide ready-made capabilities that you can simply plug into.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why MCP is the New REST
&lt;/h2&gt;

&lt;p&gt;Just like services communicate with each other through REST APIs, &lt;strong&gt;LLMs now communicate with servers through MCP.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Remember when REST revolutionized web development by providing a standard way for systems to talk to each other? &lt;strong&gt;MCP is doing the same thing for AI systems.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It creates a clean separation of concerns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AI apps focus on reasoning and user interaction&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MCP servers focus on providing specific capabilities&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As an AI developer, you don't need to write and maintain custom tool code. And since the MCP server handles the integration details, you're insulated from changes in the underlying systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Future: MCP Alongside REST, Then Beyond
&lt;/h2&gt;

&lt;p&gt;Today, most digital services expose REST APIs. My prediction is that &lt;strong&gt;we'll soon see services offering both REST APIs and MCP servers side by side.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Just as REST largely replaced SOAP for most web service integrations, &lt;strong&gt;MCP could eventually replace traditional REST APIs&lt;/strong&gt; for many AI-driven use cases.&lt;/p&gt;

&lt;p&gt;Why? Because MCP is designed specifically for the way modern AI needs to interact with services—with rich context and semantic understanding rather than just rigid data structures.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Big Picture
&lt;/h2&gt;

&lt;p&gt;MCP servers are like interfaces. Your LLM only needs to know what the server offers and doesn't depend on the concrete implementation.&lt;/p&gt;

&lt;p&gt;This is huge for AI development because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Reduced complexity&lt;/strong&gt; - No more custom tool code for every integration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better maintenance&lt;/strong&gt; - MCP servers handle API changes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Standardization&lt;/strong&gt; - A common protocol that works across different AI systems&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Specialization&lt;/strong&gt; - LLMs can focus on what they do best&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;The next time you hear about MCP, remember: &lt;strong&gt;it's not just another AI buzzword. It's a fundamental architectural pattern that's reshaping how AI systems interact with the world&lt;/strong&gt;—just like REST did for web services years ago.&lt;/p&gt;

&lt;p&gt;Are you building AI applications? &lt;strong&gt;MCP might just be the abstraction you've been waiting for.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>aws</category>
      <category>ai</category>
      <category>genai</category>
    </item>
    <item>
      <title>DynamoDB Transactions with AWS Step Functions</title>
      <dc:creator>Viktor Ardelean</dc:creator>
      <pubDate>Sat, 19 Oct 2024 14:56:24 +0000</pubDate>
      <link>https://dev.to/viktorardelean/dynamodb-transactions-with-aws-step-functions-3k7d</link>
      <guid>https://dev.to/viktorardelean/dynamodb-transactions-with-aws-step-functions-3k7d</guid>
      <description>&lt;h2&gt;
  
  
  1. Overview
&lt;/h2&gt;

&lt;p&gt;In this post, we'll explore how to leverage direct service integrations in &lt;em&gt;AWS Step Functions&lt;/em&gt; to build a workflow for executing &lt;em&gt;DynamoDB&lt;/em&gt; transactions. &lt;em&gt;AWS Step Functions&lt;/em&gt; are an excellent tool for breaking down business workflows into individual steps, promoting separation of concerns and encapsulating discrete actions within each step.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The Use Case
&lt;/h2&gt;

&lt;p&gt;Let's consider a real-life scenario to demonstrate this approach. We start with an object stored in &lt;em&gt;Amazon S3&lt;/em&gt;. &lt;strong&gt;When the file is deleted, we must remove an item from two &lt;em&gt;DynamoDB&lt;/em&gt; tables&lt;/strong&gt;. To ensure data consistency, we'll wrap both delete operations inside a transaction, preventing a situation where one delete succeeds while the other fails.&lt;/p&gt;

&lt;p&gt;Here's an example of an &lt;em&gt;Amazon EventBridge&lt;/em&gt; rule that captures all &lt;em&gt;delete&lt;/em&gt; events from a specific &lt;em&gt;Amazon S3&lt;/em&gt; bucket:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "detail": {
    "bucket": {
      "name": ["bucket_name"]
    },
    "deletion-type": ["Permanently Deleted"]
  },
  "detail-type": ["Object Deleted"],
  "source": ["aws.s3"]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. The Traditional Lambda Solution
&lt;/h2&gt;

&lt;p&gt;A classic design would involve enabling &lt;em&gt;Amazon S3&lt;/em&gt; event notifications to &lt;em&gt;Amazon EventBridge&lt;/em&gt;. Once the event reaches the event bus, an &lt;em&gt;Amazon EventBridge&lt;/em&gt; rule would trigger a &lt;em&gt;AWS Lambda&lt;/em&gt; function to execute the &lt;em&gt;DynamoDB&lt;/em&gt; transaction. Here's what this architecture might look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiuobquzw9p8o1tfmb60n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiuobquzw9p8o1tfmb60n.png" alt="Image description" width="771" height="256"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's examine a potential &lt;em&gt;AWS Lambda&lt;/em&gt; function implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def lambda_handler(event, context):
    # Extract the S3 object key from the EventBridge event
    s3_key = event.get["detail"]["object"]["key"]

    # Construct your DynamoDB delete operations
    delete_item_in_table_A = {
        'Delete': {
            'TableName': "ddb_table_a",
            'Key': {
                'YourPrimaryKeyAttributeName': {'S': s3_key}
            }
        }
    }

    delete_item_in_table_B = {
        'Delete': {
            'TableName': "ddb_table_b",
            'Key': {
                'YourPrimaryKeyAttributeName': {'S': s3_key}
            }
        }
    }

    # Perform a DynamoDB transaction to ensure both deletes happen together
    response = dynamodb.transact_write_items(
        TransactItems=[delete_item_in_table_A, delete_item_in_table_B]
    )

    return {     
        'statusCode': 200,     
        'body': json.dumps('Delete transaction succeeded'  
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this solution is concise and functional, it has some drawbacks. The &lt;em&gt;AWS Lambda&lt;/em&gt; function merely receives an event and performs an API call, without any substantial business logic. It serves as a simple connector in a data pipeline chain, executing some delete operations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;AWS Lambda&lt;/em&gt; functions that primarily connect different services or transform events without complex business logic can often be replaced with service integrations.&lt;/strong&gt; &lt;br&gt;
Let's explore this alternative approach.&lt;/p&gt;
&lt;h2&gt;
  
  
  4. The &lt;em&gt;AWS Step Functions&lt;/em&gt; Solution
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Amazon EventBridge&lt;/em&gt; supports &lt;em&gt;AWS Step Functions&lt;/em&gt; as a target, allowing us to replace the &lt;em&gt;AWS Lambda&lt;/em&gt; function with a &lt;em&gt;AWS Step Functions&lt;/em&gt; workflow. This approach enables us to build a no-code solution using &lt;em&gt;DynamoDB&lt;/em&gt; direct service integrations within the workflow.&lt;/p&gt;

&lt;p&gt;Here's an overview of this solution:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fli4lyy7o5wysj7utbfi1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fli4lyy7o5wysj7utbfi1.png" alt="Image description" width="771" height="256"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let's dive into the implementation of the &lt;em&gt;AWS Step Functions&lt;/em&gt; workflow.&lt;/p&gt;
&lt;h3&gt;
  
  
  4.1 &lt;em&gt;AWS Step Functions&lt;/em&gt; Service Integrations
&lt;/h3&gt;

&lt;p&gt;Since our use case doesn't involve complex logic, we can build our workflow using service integrations. &lt;em&gt;AWS Step Functions&lt;/em&gt; offer two types of integrations with other AWS services:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;AWS SDK Integrations:&lt;/strong&gt; These cover over 200 services and are similar to API calls you'd make in a &lt;em&gt;AWS Lambda&lt;/em&gt; function.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimized Integrations:&lt;/strong&gt; Available for about 20 core services, these add convenience by automatically converting output to JSON and handling asynchronous tasks, eliminating the need for custom polling mechanisms.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We have two AWS SDK integration options, &lt;em&gt;DynamoDB:TransactWriteItems&lt;/em&gt; and &lt;em&gt;DynamoDB:ExecuteTransaction&lt;/em&gt;, to wrap both delete statements in a transaction.&lt;/p&gt;

&lt;p&gt;Let's explore both implementations.&lt;/p&gt;
&lt;h3&gt;
  
  
  4.1 &lt;em&gt;DynamoDB:TransactWriteItems&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;em&gt;TransactWriteItems&lt;/em&gt; API allows for synchronous, atomic write operations across multiple items. It supports up to 100 actions (Put, Update, Delete, or ConditionCheck) in different tables within the same AWS account and region. &lt;strong&gt;This API doesn't allow read operations within the transaction and ensures all actions either succeed or fail together.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Using this approach, we need just a single step in our workflow:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj0lhh3eq21pzau1hae76.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj0lhh3eq21pzau1hae76.png" alt="Image description" width="428" height="344"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's the workflow's ASL (Amazon State Language) definition for the transaction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "Comment": "DynamoDB Transaction for Delete Statements",
  "StartAt": "DeleteTransaction",
  "States": {
    "DeleteTransaction": {
      "Type": "Task",
      "Parameters": {
        "TransactItems": [
          {
            "Delete": {
              "TableName": "ddb_table_a",
              "Key": {
                "PK": {
                  "S.$": "$.detail.object.key"
                }
              }
            }
          },
          {
            "Delete": {
              "TableName": "ddb_table_b",
              "Key": {
                "PK": {
                  "S.$": "$.detail.object.key"
                }
              }
            }
          }
        ]
      },
      "Resource": "arn:aws:states:::aws-sdk:dynamodb:transactWriteItems",
      "End": true
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.2 &lt;em&gt;DynamoDB:ExecuteTranscation&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;em&gt;ExecuteTransaction&lt;/em&gt; API allows for transactional reads or writes using PartiQL statements. A transaction can contain up to 100 statements, &lt;strong&gt;but all operations must be either reads or writes, not a mix&lt;/strong&gt;. It ensures that all statements in the transaction are executed atomically.&lt;/p&gt;

&lt;p&gt;Our workflow would look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fszkvgum1e1cmsvdt88k4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fszkvgum1e1cmsvdt88k4.png" alt="Image description" width="423" height="334"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Defining the delete statements for this approach can be tricky. Here's an example implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "Comment": "DynamoDB Transaction for Delete Statements",
  "StartAt": "ExecuteTransaction",
  "States": {
    "ExecuteTransaction": {
      "Type": "Task",
      "Parameters": {
        "TransactStatements": [
          {
            "Statement": "DELETE FROM \"ddb_table_a\" WHERE PK = ?",
            "Parameters": [
              {
                "S.$": "$.detail.object.key"
              }
            ]
          },
          {
            "Statement": "DELETE FROM \"ddt_table_b\" WHERE PK = ?",
            "Parameters": [
              {
                "S.$": "$.detail.object.key"
              }
            ]
          }
        ]
      },
      "Resource": "arn:aws:states:::aws-sdk:dynamodb:executeTransaction",
      "End": true
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In both cases, we only need to define a single state with the delete statements. This approach eliminates the need for maintaining code, dealing with cold starts, or managing runtime updates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost Considerations
&lt;/h2&gt;

&lt;p&gt;When it comes to costs, choosing the Express workflow type is the most economical option for such a simple and fast workflow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An often overlooked fact is that &lt;em&gt;AWS Step Functions Express&lt;/em&gt; offers a minimum 64 MB configuration option, which is more cost-effective than the minimum 128 MB &lt;em&gt;AWS Lambda&lt;/em&gt; function.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To illustrate, let's consider a scenario with 3 million invocations, each lasting 100ms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A 128 MB &lt;em&gt;AWS Lambda&lt;/em&gt; function in us-east-1 would cost $0.51&lt;/li&gt;
&lt;li&gt;A 64 MB &lt;em&gt;Express Step Function&lt;/em&gt; in the same region would cost $0.31&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This demonstrates the potential for significant cost savings when using &lt;em&gt;AWS Step Functions&lt;/em&gt; for simple workflows. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By leveraging &lt;em&gt;AWS Step Functions&lt;/em&gt; with direct service integrations, we can create efficient, no-code solutions for executing &lt;em&gt;DynamoDB&lt;/em&gt; transactions. This approach offers several advantages over traditional &lt;em&gt;AWS Lambda&lt;/em&gt;-based implementations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Simplified architecture with reduced code maintenance&lt;/li&gt;
&lt;li&gt;Improved separation of concerns&lt;/li&gt;
&lt;li&gt;Potential cost savings, especially for simple, high-volume workflows&lt;/li&gt;
&lt;li&gt;Elimination of cold starts and runtime management&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As we've seen, both &lt;em&gt;TransactWriteItems&lt;/em&gt; and &lt;em&gt;ExecuteTransaction&lt;/em&gt; APIs provide robust options for implementing transactional operations in &lt;em&gt;DynamoDB&lt;/em&gt; through &lt;em&gt;AWS Step Functions&lt;/em&gt;. The choice between them depends on your specific use case and whether you need to include read operations in your transactions.&lt;/p&gt;

&lt;p&gt;By adopting this serverless, no-code approach, you can simplify your data pipeline processes and focus more on building scalable, maintainable applications in AWS.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>dynamodb</category>
      <category>stepfunctions</category>
    </item>
    <item>
      <title>Unleashing OpenSearch: Best Practices for 1 Billion Documents on AWS</title>
      <dc:creator>Viktor Ardelean</dc:creator>
      <pubDate>Wed, 05 Jul 2023 15:11:14 +0000</pubDate>
      <link>https://dev.to/viktorardelean/unleashing-opensearch-best-practices-for-1-billion-documents-on-aws-2gi9</link>
      <guid>https://dev.to/viktorardelean/unleashing-opensearch-best-practices-for-1-billion-documents-on-aws-2gi9</guid>
      <description>&lt;h2&gt;
  
  
  1. Introduction:
&lt;/h2&gt;

&lt;p&gt;Setting up an OpenSearch cluster in AWS to handle big data volumes is crucial in ensuring optimal performance, scalability, and availability. &lt;/p&gt;

&lt;p&gt;In this blog post, we will explore important considerations and recommendations for configuring an OpenSearch cluster specifically designed to manage 1 billion documents, each sized at 2KB. &lt;/p&gt;

&lt;p&gt;By following these recommendations, such as properly allocating resources and implementing appropriate indexing strategies, we can ensure efficient ingestion and management of the 2TB data set. &lt;/p&gt;

&lt;p&gt;This will enable us to harness the full potential of OpenSearch and effectively process and analyze the extensive data at hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Optimizing Performance and Scalability
&lt;/h2&gt;

&lt;h3&gt;
  
  
  2.1 Dedicated Master Nodes
&lt;/h3&gt;

&lt;p&gt;It is recommended to use Multi-AZ with Standby and deploy three dedicated master nodes for optimal stability and fault tolerance.&lt;/p&gt;

&lt;p&gt;Avoid choosing an even number of dedicated master nodes to ensure the necessary quorum for electing a new master in case of failures. &lt;strong&gt;Three dedicated master nodes offer two backup nodes and the required quorum, providing a reliable configuration.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The following table provides recommended minimum dedicated master instance types for efficient management of OpenSearch clusters, considering factors like instance count and shard count.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Instance count&lt;/th&gt;
&lt;th&gt;Master node RAM size&lt;/th&gt;
&lt;th&gt;Maximum supported shard count&lt;/th&gt;
&lt;th&gt;Recommended minimum dedicated master instance type&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1–10&lt;/td&gt;
&lt;td&gt;8 GiB&lt;/td&gt;
&lt;td&gt;10K&lt;/td&gt;
&lt;td&gt;m5.large.search or m6g.large.search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11–30&lt;/td&gt;
&lt;td&gt;16 GiB&lt;/td&gt;
&lt;td&gt;30K&lt;/td&gt;
&lt;td&gt;c5.2xlarge.search or c6g.2xlarge.search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;31–75&lt;/td&gt;
&lt;td&gt;32 GiB&lt;/td&gt;
&lt;td&gt;40K&lt;/td&gt;
&lt;td&gt;r5.2xlarge.search or r6g.2xlarge.search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;76–125&lt;/td&gt;
&lt;td&gt;64 GiB&lt;/td&gt;
&lt;td&gt;75K&lt;/td&gt;
&lt;td&gt;r5.2xlarge.search or r6g.2xlarge.search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;126–200&lt;/td&gt;
&lt;td&gt;128 GiB&lt;/td&gt;
&lt;td&gt;75K&lt;/td&gt;
&lt;td&gt;r5.4xlarge.search or r6g.4xlarge.search&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Based on our specific use case, we can opt for a configuration consisting of three m6g.large.search master nodes. &lt;/p&gt;

&lt;h3&gt;
  
  
  2.2 Scaling Data Nodes
&lt;/h3&gt;

&lt;p&gt;When dealing with substantial data volumes, such as the massive 2TB dataset we have, it becomes crucial to appropriately scale the number of data nodes in our OpenSearch cluster.&lt;/p&gt;

&lt;p&gt;Scaling the data nodes allows us to distribute the data across multiple nodes, ensuring efficient storage, retrieval, and processing of the extensive dataset.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To efficiently manage a 2TB dataset in OpenSearch, we can start with three data nodes and conduct thorough performance testing.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Monitoring metrics such as indexing throughput and response times during testing will determine if additional nodes are necessary.&lt;/p&gt;

&lt;p&gt;By gradually adding nodes based on performance analysis, we can effectively distribute the workload and ensure optimal dataset management.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.3 Shard Count
&lt;/h3&gt;

&lt;p&gt;To optimize search performance in OpenSearch, careful consideration of the shard count in our index is crucial. Increasing the number of shards can significantly improve efficiency, particularly when dealing with large datasets. &lt;strong&gt;For search-focused workloads, aiming for shard sizes between 10-30 GB is recommended, while sizes between 30-50 GB work well for write-heavy scenarios.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For instance, let's consider a use case where both reads and writes occur equally. In such cases, aiming for a shard size of around 30 GB is ideal. &lt;/p&gt;

&lt;p&gt;We can approximate the number of primary shards required using the formula &lt;strong&gt;(source_data) * (1 + indexing_overhead) / desired_shard_size&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For our example, the approximate number of primary shards would be (2000) * 1.1 / 30 ≈ 73.33&lt;/p&gt;

&lt;p&gt;To ensure an even distribution of shards across our three data nodes, a suitable shard count would be 72. This allocation helps balance the workload and maximizes the utilization of resources within our OpenSearch cluster. &lt;/p&gt;

&lt;p&gt;As our data volume grows, adjusting the shard count to maintain optimal performance becomes essential. Adapting the shard count based on the evolving data volume ensures efficient distribution and processing of data across the cluster. We can achieve optimal search performance in OpenSearch by continuously monitoring and optimizing the shard count. &lt;/p&gt;

&lt;h3&gt;
  
  
  2.4 Adding Replicas
&lt;/h3&gt;

&lt;p&gt;In OpenSearch, replica shards are exact copies of primary shards within an index distributed across data nodes in a cluster. The presence of replica shards ensures data redundancy and increases read capacity. &lt;/p&gt;

&lt;p&gt;When indexing data, requests are sent to all data nodes containing primary and replica shards. At the same time, search queries are directed to either primary or replica shards, resulting in a different number of shards being involved in each operation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using at least one replica is strongly recommended, as it enhances redundancy and improves read capacity&lt;/strong&gt;. Additional replicas increase these benefits, offering even greater data redundancy and improving the ability to handle read operations efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Storage Considerations:
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.1 Estimating Storage Requirements:
&lt;/h3&gt;

&lt;p&gt;To account for replicas and various storage considerations in OpenSearch, we must allocate approximately 6 TB of total storage (2 TB for the primary shard and two replicas of 2 TB each). &lt;/p&gt;

&lt;p&gt;However, it's important to consider additional factors that affect storage requirements. OpenSearch Service reserves 20% of storage space for segment merges, logs, and other internal operations, with a maximum of 20 GiB per instance. This means that the total reserved space can vary depending on the number of instances in your domain.&lt;/p&gt;

&lt;p&gt;To calculate the minimum storage requirement for our example with 2 replicas and 2TB of source data, we can use the simplified formula provided:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source data * (1 + number of replicas) * 1.45 = minimum storage requirement&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Substituting the values:&lt;/p&gt;

&lt;p&gt;2TB * (1 + 2) * 1.45 = 8.7TB&lt;/p&gt;

&lt;p&gt;Therefore, the minimum storage requirement for replicas and other factors would be approximately 8.7TB.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.2 Handling Full Reindex
&lt;/h3&gt;

&lt;p&gt;Handling a full reindex is an important aspect of managing data in Elasticsearch. In scenarios where we need to reindex our data, it becomes necessary to have two indices concurrently: one containing the current data and another for the new data. &lt;/p&gt;

&lt;p&gt;This approach allows us to perform the reindexing process seamlessly without any downtime. However, it's essential to consider that this scenario requires allocating twice the storage estimated in the previous chapter. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To simultaneously accommodate both indices, we need to ensure sufficient storage capacity to store the existing and newly reindexed data.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Considering the increased storage requirement, we must allocate a minimum of 2 * 8.7TB = 17.4TB.&lt;/p&gt;

&lt;p&gt;Additionally, it's worth noting that Elasticsearch allows for dynamic scaling of storage during a full reindex. This means we can add storage capacity specifically for the reindexing process and later scale it down once it is complete. This dynamic allocation prevents us from continuously paying for unused storage and optimizes cost efficiency. &lt;/p&gt;

&lt;h3&gt;
  
  
  3.3 Instance Type Selection:
&lt;/h3&gt;

&lt;p&gt;When selecting hardware for our OpenSearch cluster, it's crucial to consider storage requirements, shard count, and workload characteristics. The number of shards per data node should align with the node's JVM heap memory, &lt;strong&gt;typically aiming for 25 shards or fewer per GiB&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To ensure efficient processing, &lt;strong&gt;it's recommended to have an initial scale point of 1.5 vCPUs per shard&lt;/strong&gt;. For instance, with 72 shards per node, we would need approximately 108 vCPUs.&lt;/p&gt;

&lt;p&gt;To accommodate this, scaling our data nodes to 5 would be suitable, resulting in a shard count of approximately 43.2 per node. In this case, selecting a robust instance type like the m6g.12xlarge.search with 48 CPUs and 192 RAM would be advisable.&lt;/p&gt;

&lt;p&gt;However, additional instances may be required if performance falls short of expectations, tests fail, or CPUUtilization or JVMMemoryPressure indicators are high. As instances are added, OpenSearch automatically redistributes the shard distribution throughout the cluster, helping to balance the workload and optimize performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Monitoring:
&lt;/h2&gt;

&lt;h3&gt;
  
  
  4.1 Monitor Resource Utilization
&lt;/h3&gt;

&lt;p&gt;It is essential to implement continuous monitoring of CPU, memory, and storage usage in our OpenSearch cluster to ensure optimal performance. By monitoring these metrics, we can identify any resource bottlenecks or imbalances and take appropriate actions to address them. &lt;/p&gt;

&lt;p&gt;Regularly reviewing resource utilization allows us to make informed decisions regarding resource allocation, ensuring that our cluster operates efficiently and effectively.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.2 Configure CloudWatch Alarms
&lt;/h3&gt;

&lt;p&gt;Setting up CloudWatch alarms is a proactive approach to staying informed about the health and performance of our OpenSearch cluster. &lt;/p&gt;

&lt;p&gt;By defining thresholds for key metrics such as CPU utilization, storage usage, and search latency, we can receive timely alerts when any of these metrics breach the specified limits. These alarms enable us to quickly identify and address potential issues before impacting overall cluster performance. &lt;/p&gt;

&lt;p&gt;Regularly reviewing the cluster and instance metrics provides valuable insights into the behavior and patterns of our cluster, allowing us to fine-tune and optimize its configuration for optimal performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Deployment Best Practices
&lt;/h2&gt;

&lt;h3&gt;
  
  
  5.1 Multi-AZ Deployment
&lt;/h3&gt;

&lt;p&gt;We should deploy our data nodes across multiple Availability Zones (AZs) to achieve high availability and fault tolerance. &lt;/p&gt;

&lt;p&gt;By evenly distributing our data nodes across AZs, we ensure redundancy and resilience in our OpenSearch cluster. &lt;/p&gt;

&lt;p&gt;This approach safeguards against AZ failures, reducing the risk of downtime and ensuring the continuous operation of our cluster.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.2 Subnet Distribution:
&lt;/h3&gt;

&lt;p&gt;Dividing our data nodes into multiple subnets distributed across different AZs is advisable to ensure high availability and fault tolerance. &lt;/p&gt;

&lt;p&gt;Distributing our data nodes across subnets enhances the cluster's resilience to network-related issues within a specific AZ. This practice improves fault isolation capabilities and minimizes the impact of potential subnet-level disruptions.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Enable Log Publishing
&lt;/h2&gt;

&lt;p&gt;To effectively troubleshoot performance, stability, and user activity in our OpenSearch cluster, enabling log publishing and utilizing relevant logs for analysis is crucial. We can direct OpenSearch error logs, search slow logs, indexing slow logs, and audit logs to CloudWatch Logs by enabling log publishing.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Restrict Wildcard Usage
&lt;/h2&gt;

&lt;p&gt;We must implement access controls and permissions in our OpenSearch cluster to ensure data security and prevent accidental data loss. &lt;/p&gt;

&lt;p&gt;Specifically, we must enforce restrictions on destructive wildcard operations by requiring explicit action names.&lt;/p&gt;

&lt;p&gt;This measure mitigates the risk of unintentional data loss by ensuring that users must explicitly specify the action name when performing destructive operations.&lt;/p&gt;

&lt;p&gt;By making the following API call, we enable the setting that ensures a specific action name is required for destructive operations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PUT /_cluster/settings
{
  "persistent": {
    "action.destructive_requires_name": true
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  8. Conclusion
&lt;/h2&gt;

&lt;p&gt;Careful planning and configuration are essential when setting up our OpenSearch cluster in AWS to handle 1 billion documents. By following these best practices, we can optimize our cluster's performance, scalability, and availability, ensuring efficient management of large data volumes. Implementing dedicated master nodes, scaling data nodes, configuring shards and replicas, estimating storage requirements, and monitoring resource utilization are key factors for a robust and reliable OpenSearch deployment.&lt;/p&gt;

&lt;p&gt;Customizing the calculations and configurations mentioned in this blog post is important according to our specific requirements and workload characteristics. Regular monitoring, log analysis, and optimization will enable us to maintain a high-performing OpenSearch cluster capable of effectively handling extensive data volumes.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloud</category>
      <category>awscommunitybuilders</category>
      <category>elasticsearch</category>
    </item>
  </channel>
</rss>
