Skip to main content

Origin shielding for video delivery

Origin Shielding places a shield, also called a precache server, between the video origin and CDN edge servers. Viewers receive video from nearby edges, while an edge cache miss reaches the shield before the origin.

Origin shielding request flow

Without shielding, every CDN edge that misses cache can request the same manifest, segment, or video file from the origin. A live event or a popular VOD release can create a large number of concurrent origin requests.

With Origin Shielding, edge servers pull missed objects through one shield location. The shield serves a cached copy when it has the object, and otherwise makes one origin request that other edges reuse.

Without shielding: Viewer -> CDN edge -> Origin
With shielding:    Viewer -> CDN edge -> Shield -> Origin

The origin still serves the first request for uncached or expired content.

Live events

A live event with a large concurrent audience requests the same playlists and segments at the same time from different regions. Origin Shielding concentrates those repeated edge misses on the shield, so the origin receives one pull instead of a pull from every edge.

VOD libraries

Hot titles are usually served from edge cache. A cold title, or a title evicted after it stops being hot, can miss on edges in different regions.

One miss warms the shield cache, so other edges reuse that copy.

Repeated misses from several regions show up as a low cache hit ratio. That is a reason to enable Origin Shielding for a live event or a VOD library.

Cache lifetime for video

For live streaming, use a short cacheable TTL for manifests and a longer TTL for segments when the workflow allows it. VOD files and segments need a TTL long enough for later requests to hit the shield.

Set a shield location on the CDN resource that delivers the video. The sequence lists locations, saves one, reads the resource, and clears the setting.

In the CDB Customer Portal, the same location is set from origin shielding.

An API token is required, along with the ID of the CDN resource that delivers the video.

export GCORE_API_KEY="{YOUR_API_KEY}"
export CDN_RESOURCE_ID="{YOUR_CDN_RESOURCE_ID}"
export SHIELDING_POP="{YOUR_SHIELDING_LOCATION_ID}"

Shield locations

Select the shield location closest to the video origin. A locations list returns its id, datacenter, city, and country, and that id is the value for SHIELDING_POP.

from gcore import CDB

client = CDB()
locations = client.cdn.shielding_location.list()
for item in locations:
    print(item.id, item.datacenter, item.city, item.country)
package main

import (
    "context"
    "fmt"

    gcore "github.com/G-Core/gcore-go"
    "github.com/G-Core/gcore-go/cdn"
)

func main() {
    client := gcore.NewClient()
    ctx := context.Background()

    page, err := client.CDN.ShieldingLocation.List(ctx, cdn.ShieldingLocationListParams{})
    if err != nil {
        panic(err)
    }
    for _, item := range page.Results {
        fmt.Println(item.ID, item.Datacenter, item.City, item.Country)
    }
}
curl "https://api.cdb-staging.cdn.orange.com/cdn/shieldingpop_v2" \
  -H "Authorization: APIKey $GCORE_API_KEY"

The API returns:

[
  {
    "id": 171,
    "datacenter": "SG1",
    "city": "Singapore",
    "country": "Singapore"
  }
]

Location update

A shielding update sets shielding_pop to a location id and returns that id. The id has to be one returned by the locations list.

import os

from gcore import CDB

client = CDB()
resource_id = int(os.environ["CDN_RESOURCE_ID"])
shielding_pop = int(os.environ["SHIELDING_POP"])

updated = client.cdn.cdn_resources.shield.replace(
    resource_id,
    shielding_pop=shielding_pop,
)
print(updated["shielding_pop"])
package main

import (
    "context"
    "fmt"
    "os"
    "strconv"

    gcore "github.com/G-Core/gcore-go"
    "github.com/G-Core/gcore-go/cdn"
)

func main() {
    client := gcore.NewClient()
    ctx := context.Background()
    resourceID, err := strconv.ParseInt(os.Getenv("CDN_RESOURCE_ID"), 10, 64)
    if err != nil {
        panic(err)
    }
    shieldingPop, err := strconv.ParseInt(os.Getenv("SHIELDING_POP"), 10, 64)
    if err != nil {
        panic(err)
    }

    updated, err := client.CDN.CDNResources.Shield.Replace(ctx, resourceID, cdn.CDNResourceShieldReplaceParams{
        OriginShielding: cdn.OriginShieldingParam{
            ShieldingPop: gcore.Int(shieldingPop),
        },
    })
    if err != nil {
        panic(err)
    }
    fmt.Println((*updated).(map[string]any)["shielding_pop"])
}
curl -X PUT "https://api.cdb-staging.cdn.orange.com/cdn/resources/$CDN_RESOURCE_ID/shielding_v2" \
  -H "Authorization: APIKey $GCORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"shielding_pop\": $SHIELDING_POP}"

The API returns:

{
  "shielding_pop": 171
}

An unknown location id returns HTTP 400 with the message Invalid pk "999999999" - object does not exist.

Resource fields

Read the CDN resource after the update. shielded is true and shield_dc is the datacenter name when the location is saved. shield_enabled is read-only and stays false until the shield is active.

Activation completes in under 15 minutes. Read the resource again, so shield_enabled true confirms that the shield is active and working.

import os

from gcore import CDB

client = CDB()
resource_id = int(os.environ["CDN_RESOURCE_ID"])

resource = client.cdn.cdn_resources.get(resource_id)
print(resource.shielded, resource.shield_dc, resource.shield_enabled)
package main

import (
    "context"
    "fmt"
    "os"
    "strconv"

    gcore "github.com/G-Core/gcore-go"
)

func main() {
    client := gcore.NewClient()
    ctx := context.Background()
    resourceID, err := strconv.ParseInt(os.Getenv("CDN_RESOURCE_ID"), 10, 64)
    if err != nil {
        panic(err)
    }

    resource, err := client.CDN.CDNResources.Get(ctx, resourceID)
    if err != nil {
        panic(err)
    }
    fmt.Println(resource.Shielded, resource.ShieldDc, resource.ShieldEnabled)
}
curl "https://api.cdb-staging.cdn.orange.com/cdn/resources/$CDN_RESOURCE_ID" \
  -H "Authorization: APIKey $GCORE_API_KEY"

The first read includes:

{
  "shielded": true,
  "shield_dc": "SG1",
  "shield_enabled": false
}

Cleared location

The same update sets shielding_pop to null. The resource then reports shielded as false and shield_dc as null. shield_enabled can stay true until the shield stops, and a later read reports it as false.

import os

from gcore import CDB

client = CDB()
resource_id = int(os.environ["CDN_RESOURCE_ID"])

updated = client.cdn.cdn_resources.shield.replace(
    resource_id,
    shielding_pop=None,
)
print(updated["shielding_pop"])
package main

import (
    "context"
    "fmt"
    "os"
    "strconv"

    gcore "github.com/G-Core/gcore-go"
    "github.com/G-Core/gcore-go/cdn"
    "github.com/G-Core/gcore-go/packages/param"
)

func main() {
    client := gcore.NewClient()
    ctx := context.Background()
    resourceID, err := strconv.ParseInt(os.Getenv("CDN_RESOURCE_ID"), 10, 64)
    if err != nil {
        panic(err)
    }

    updated, err := client.CDN.CDNResources.Shield.Replace(ctx, resourceID, cdn.CDNResourceShieldReplaceParams{
        OriginShielding: cdn.OriginShieldingParam{
            ShieldingPop: param.Null[int64](),
        },
    })
    if err != nil {
        panic(err)
    }
    fmt.Println((*updated).(map[string]any)["shielding_pop"])
}
curl -X PUT "https://api.cdb-staging.cdn.orange.com/cdn/resources/$CDN_RESOURCE_ID/shielding_v2" \
  -H "Authorization: APIKey $GCORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"shielding_pop": null}'

The API returns:

{
  "shielding_pop": null
}

Route video edge misses through a shield location with the Terraform provider v2, so a live event or a cold VOD title misses on one shield instead of on the origin from every edge. Select the location closest to the video origin. For live streaming, use a short cacheable TTL for manifests and a longer TTL for segments, while VOD files need a TTL long enough for later requests to hit the shield.

Shield location

Select the location by city and set shielding_pop on the CDN resource. An unknown location id returns HTTP 400 with the message Invalid pk "999999999" - object does not exist. The apply leaves shielded false until the next terraform plan, which records shielded as true and shield_dc as the datacenter name. shield_enabled stays false until the shield is active. Activation completes in under 15 minutes, and a later plan records shield_enabled as true.

data "gcore_cdn_shielding_locations" "available" {}

locals {
  shielding_pop = one([
    for location in data.gcore_cdn_shielding_locations.available.items :
    location.id if location.city == "Singapore"
  ])
}

resource "gcore_cdn_origin_group" "example" {
  name = "my-origin-group"

  sources = [
    {
      source  = "example.com"
      enabled = true
    }
  ]
}

resource "gcore_cdn_resource" "example" {
  cname           = "video-shield.mywebsite.com"
  origin_group    = gcore_cdn_origin_group.example.id
  origin_protocol = "HTTPS"
}

resource "gcore_cdn_origin_shielding" "example" {
  resource_id   = gcore_cdn_resource.example.id
  shielding_pop = local.shielding_pop
}

Cleared location

Remove the gcore_cdn_origin_shielding block and run terraform apply, so shielding_pop becomes null. The next terraform plan records shielded as false and shield_dc as null. shield_enabled can stay true on that plan, and a later plan records it as false.

data "gcore_cdn_shielding_locations" "available" {}

locals {
  shielding_pop = one([
    for location in data.gcore_cdn_shielding_locations.available.items :
    location.id if location.city == "Singapore"
  ])
}

resource "gcore_cdn_origin_group" "example" {
  name = "my-origin-group"

  sources = [
    {
      source  = "example.com"
      enabled = true
    }
  ]
}

resource "gcore_cdn_resource" "example" {
  cname           = "video-shield.mywebsite.com"
  origin_group    = gcore_cdn_origin_group.example.id
  origin_protocol = "HTTPS"
}

# Remove or comment out this block:
# resource "gcore_cdn_origin_shielding" "example" {
#   resource_id   = gcore_cdn_resource.example.id
#   shielding_pop = local.shielding_pop
# }
terraform apply