OCI NoSQL Database: Serverless Key-Value and Document Store with Terraform

OCI NoSQL Database is a serverless key-value and document store that scales read and write throughput independently, charges per operation rather than per instance, and delivers single-digit millisecond latency at any scale. It suits workloads like session stores, user preference storage, real-time leaderboards, IoT event ingestion, and any application that needs predictable low-latency access to structured data without the overhead of a relational schema. This post covers Terraform setup, table design, and TTL-based expiry.

Step 1: IAM Policy and Tables

resource "oci_identity_policy" "nosql_policy" {
  compartment_id = var.compartment_id
  name           = "nosql-database-policy"
  statements = [
    "Allow group AppDevelopers to manage nosql-family in compartment id COMPARTMENT_OCID",
    "Allow dynamic-group ApplicationInstances to use nosql-rows in compartment id COMPARTMENT_OCID where target.nosqltable.name != 'system-config'"
  ]
}

resource "oci_nosql_table" "user_sessions" {
  compartment_id = var.compartment_id
  name           = "UserSessions"

  ddl_statement = "CREATE TABLE IF NOT EXISTS UserSessions (session_id STRING, user_id LONG, data JSON, created_at TIMESTAMP(0), expires_at TIMESTAMP(0), PRIMARY KEY(session_id)) USING TTL 86400 SECONDS"

  table_limits {
    max_read_units    = 500
    max_write_units   = 250
    max_storage_in_gbs = 25
    capacity_mode     = "ON_DEMAND"  # Auto-scales, no pre-provisioning needed
  }

  is_auto_reclaimable = false
  defined_tags        = { "Operations.Environment" = "production", "Operations.ManagedBy" = "terraform" }
}

resource "oci_nosql_table" "product_catalog_cache" {
  compartment_id = var.compartment_id
  name           = "ProductCatalogCache"

  ddl_statement = "CREATE TABLE IF NOT EXISTS ProductCatalogCache (product_id LONG, region STRING, locale STRING, data JSON, cached_at TIMESTAMP(0), PRIMARY KEY(SHARD(product_id), region, locale)) USING TTL 3600 SECONDS"

  table_limits {
    max_read_units    = 2000
    max_write_units   = 500
    max_storage_in_gbs = 100
    capacity_mode     = "ON_DEMAND"
  }

  is_auto_reclaimable = false
}

resource "oci_nosql_table" "leaderboard" {
  compartment_id = var.compartment_id
  name           = "GameLeaderboard"

  ddl_statement = "CREATE TABLE IF NOT EXISTS GameLeaderboard (game_id STRING, score LONG, player_id STRING, player_name STRING, achieved_at TIMESTAMP(0), PRIMARY KEY(game_id, DESCENDING(score), player_id))"

  table_limits {
    max_read_units    = 1000
    max_write_units   = 1000
    max_storage_in_gbs = 50
    capacity_mode     = "PROVISIONED"  # Predictable load - provisioned is cheaper
  }
}

output "nosql_endpoint" {
  value = "nosql.me-jeddah-1.oci.oraclecloud.com"
}

Step 2: Secondary Index

resource "oci_nosql_index" "sessions_by_user" {
  table_name_or_id = oci_nosql_table.user_sessions.id
  compartment_id   = var.compartment_id
  name             = "idx_sessions_user_id"

  keys {
    column_name = "user_id"
  }
}

Step 3: Usage Alarms

resource "oci_monitoring_alarm" "nosql_read_units_high" {
  compartment_id        = var.compartment_id
  display_name          = "nosql-read-units-throttled"
  is_enabled            = true
  metric_compartment_id = var.compartment_id
  namespace             = "oci_nosql"
  query                 = "ThrottledRequests[5m]{tableId = 'NOSQL_TABLE_OCID'}.sum() > 100"
  severity              = "WARNING"
  pending_duration      = "PT5M"
  destinations          = [var.ops_notification_topic_id]
  body                  = "OCI NoSQL requests are being throttled. On-demand tables scale automatically but may need a few seconds to provision additional capacity. Investigate if throttling is sustained."
}

Operational Notes

ON_DEMAND capacity mode scales read and write units automatically within the table limits you define. You pay per operation rather than per provisioned unit. For workloads with unpredictable traffic patterns, ON_DEMAND eliminates the capacity planning exercise. PROVISIONED mode is cheaper for steady, predictable workloads where you know the read and write unit requirements in advance.

TTL expiry in OCI NoSQL deletes rows automatically after the specified number of seconds. This is the correct pattern for session stores, cache tables, and any data with a natural expiry. Avoid building expiry logic in application code or cleanup cron jobs. TTL expiry is background garbage collection that does not consume read or write units and does not affect query latency.

Regards,
Osama

#OCI #OracleCloud #NoSQL #Serverless #Terraform #IaC #TechBlog #Oracle #CloudDatabase #PlatformEngineering #OracleCloudInfrastructure #KeyValue #DocumentStore #TTL #SessionStore #LowLatency #OnDemand #CloudNative #RealTimeData #IoT

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.