This is the multi-page printable view of this section. Click here to print.
Use Cases
- 1: Route on GeoIP/ASN
- 2: Route on Subnet
- 3: Route on Content Type
- 4: Route on Content Popularity
- 5: Route on Selection Input
- 6: Adapt to multi-CDN
- 7: How to use ACD router for EDNS routing
- 8: How to use ESB3024 Router with Edgeware CDN Request Router
- 9: How to use ESB3024 Router with CoreDNS
- 10: How to use the Director as a replacement for Edgeware CDN Request Router
- 11: Use In-Stream Sessions
1 - Route on GeoIP/ASN
This page describes how to write configuration for GeoIP and ASN-based routing. For configuration in general, see Configuration.
For more details on session groups and classifiers, see Session Groups and Classification.
ASN
Routing on ASN is done through a combination of session group classifiers and Lua script weight functions. We need to create ASN classifier(s) and then associate them with a session group:
$ confcli services.routing.classifiers -w
Running wizard for resource 'classifiers'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
classifiers : [
classifier can be one of
1: anonymousIp
2: asnIds
3: contentUrlPath
4: contentUrlQueryParameters
5: geoip
6: hostName
7: ipranges
8: random
9: regexMatcher
10: stringMatcher
11: subnet
12: userAgent
Choose element index or name: geoip
Adding a 'geoip' element
classifier : {
name (default: ): allowed_asn_classifier
type (default: geoip): ⏎
inverted (default: False): ⏎
continent (default: ): ⏎
country (default: ): ⏎
cities : [
city (default: ): ⏎
Add another 'city' element to array 'cities'? [y/N]: ⏎
]
asn (default: ): Agile*ISP
}
Add another 'classifier' element to array 'classifiers'? [y/N]: ⏎
]
Generated config:
{
"classifiers": [
{
"name": "allowed_asn_classifier",
"type": "geoip",
"inverted": false,
"continent": "",
"country": "",
"cities": [],
"asn": "Agile*ISP"
}
]
}
Merge and apply the config? [y/n]: y
$ confcli services.routing.sessionGroups -w
Running wizard for resource 'sessionGroups'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
sessionGroups : [
sessionGroup : {
name (default: ): allowed_asn
classifiers : [
classifier (default: ): allowed_asn_classifier
Add another 'classifier' element to array 'classifiers'? [y/N]: ⏎
]
}
Add another 'sessionGroup' element to array 'sessionGroups'? [y/N]: ⏎
]
Generated config:
{
"sessionGroups": [
{
"name": "allowed_asn",
"classifiers": [
"allowed_asn_classifier"
]
}
]
}
Merge and apply the config? [y/n]: y
{
"session_groups": [
{
"id": 1,
"name": "allowed_asn",
"classifiers": [
[
{
"id": 1,
"inverted": false,
"name": "allowed_asn_classifier",
"rule": {
"rule_type": "geoip_rule",
"source": "session/client_ip",
"asn": "Agile*ISP"
}
}
]
]
}
]
}
The asn
value is a string, matching an ISP name or similar. It supports
wildcard matching using asterisks and is case insensitive.
Note that each ASN classifier has to be in its own list. This is because classifiers within the same inner list all have to match for the entire list to be true, and that is impossible for classifiers that match against different ASNs. When the classifiers are in their own lists, it’s enough that one of them matches for the outer classifier list to also match.
Simple Example
$ confcli services.routing.rules -w
Running wizard for resource 'rules'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
rules : [
rules : [
rule can be one of
1: allow
2: consistentHashing
3: contentPopularity
4: deny
5: firstMatch
6: random
7: rawGroup
8: rawHost
9: split
10: weighted
Choose element index or name: split
Adding a 'split' element
rule : {
name (default: ): asn_split_node
type (default: split): ⏎
rule (default: ): return in_session_group("allowed_asn")
onMatch (default: ): allowed-asn-host
onMiss (default: ): offload-host
}
Add another 'rule' element to array 'rules'? [y/N]: ⏎
]
Generated config:
{
"rules": [
{
"name": "asn_split_node",
"type": "split",
"condition": "in_session_group('allowed_asn')",
"onMatch": "allowed-asn-host",
"onMiss": "offload-host"
}
]
}
Merge and apply the config? [y/n]: y
{
"content_server": {
"http_enable": true,
"http_port": 80,
"https_enable": true,
"https_port": 443
},
"session_groups": [
{
"id": 1,
"name": "allowed_asn",
"classifiers": [
[
{
"id": 1,
"inverted": false,
"name": "allowed_asn_classifier_agile",
"rule": {
"rule_type": "geoip_rule",
"source": "session/client_ip",
"asn": "Agile*ISP"
}
}
],
[
{
"id": 1,
"inverted": false,
"name": "allowed_asn_classifier_edgeware",
"rule": {
"rule_type": "geoip_rule",
"source": "session/client_ip",
"asn": "Edgeware *"
}
}
]
]
}
],
"cdns": [
{
"id": "basic-cdn",
"http_port": 80,
"https_port": 443,
"redirecting": false,
"manifest_availability_check": {
"enabled": false,
"session_group_ids": []
}
},
{
"id": "offload-cdn",
"http_port": 80,
"https_port": 443,
"redirecting": false,
"manifest_availability_check": {
"enabled": false,
"session_group_ids": []
}
}
],
"hosts": [
{
"id": "default-host",
"cdn_id": "basic-cdn",
"address_family": "ipv4",
"host": "cdn-host.example"
},
{
"id": "offload-host",
"cdn_id": "offload-cdn",
"address_family": "ipv4",
"host": "offload-host.example"
}
],
"routing": {
"id": "routing_table",
"member_order": "sequential",
"members": [
{
"id": "default-node",
"host-id": "default-host",
"weight_function": "return in_session_group('allowed_asn')"
},
{
"id": "offload-node",
"host_id": "offload-host",
"weight_function": "return 1"
}
]
}
}
Geographical Location
Routing on geographical location is done in a similar fashion. Once again, we create location classifier(s) and associate them with a session group:
Geographical locations are provided by a MaxMind database.
$ confcli services.routing.classifiers -w
Running wizard for resource 'classifiers'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
classifiers : [
classifier can be one of
1: anonymousIp
2: asnIds
3: contentUrlPath
4: contentUrlQueryParameters
5: geoip
6: hostName
7: ipranges
8: random
9: regexMatcher
10: stringMatcher
11: subnet
12: userAgent
Choose element index or name: geoip
Adding a 'geoip' element
classifier : {
name (default: ): allowed_location
type (default: geoip): ⏎
inverted (default: False): ⏎
continent (default: ): ⏎
country (default: ): ⏎
cities : [
city (default: ): stockholm
Add another 'city' element to array 'cities'? [y/N]: ⏎
]
asn (default: ): ⏎
}
Add another 'classifier' element to array 'classifiers'? [y/N]: ⏎
]
Generated config:
{
"classifiers": [
{
"name": "allowed_location",
"type": "geoip",
"inverted": false,
"continent": "",
"country": "",
"cities": [
"stockholm"
],
"asn": ""
}
]
}
Merge and apply the config? [y/n]: y
"session_groups": [
{
"id": 1,
"name": "allowed_location",
"classifiers": [
[
{
"id": 1,
"inverted": false,
"name": "allowed_location_classifier",
"rule": {
"rule_type": "geoip_rule",
"source": "session/client_ip",
"continent": "",
"country": "",
"region": "",
"cities": ["stockholm"]
}
}
]
]
}
]
At least one of the optional fields continent
, country
, region
and
cities
are required. The classifier matches a request when all specified
fields do (for the cities
list, one matching member is sufficient). All
values support wildcard matching using asterisks and are case insensitive.
Note that each location classifier has to be in its own list. This is because classifiers within the same inner list all have to match for the entire list to be true, and that is impossible for classifiers that match against different locations. When the classifiers are in their own lists, it’s enough that one of them matches for the outer classifier list to also match.
Simple Example
confcli services.routing.rules -w
Running wizard for resource 'rules'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
rules : [
rules : [
rule can be one of
1: allow
2: consistentHashing
3: contentPopularity
4: deny
5: firstMatch
6: random
7: rawGroup
8: rawHost
9: split
10: weighted
Choose element index or name: split
Adding a 'split' element
rule : {
name (default: ): geographic_location_split_node
type (default: split): ⏎
rule (default: ): return in_session_group("allowed_location")
onMatch (default: ): allowed-location-host
onMiss (default: ): offload-host
}
Add another 'rule' element to array 'rules'? [y/N]: ⏎
]
Generated config:
{
"rules": [
{
"name": "geographic_location_split_node",
"type": "split",
"condition": "in_session_group('allowed_location')",
"onMatch": "allowed-location-host",
"onMiss": "offload-host"
}
]
}
Merge and apply the config? [y/n]: y
{
"content_server": {
"http_enable": true,
"http_port": 80,
"https_enable": true,
"https_port": 443
},
"session_groups": [
{
"id": 1,
"name": "allowed_location",
"classifiers": [
[
{
"id": 1,
"inverted": false,
"name": "allowed_location_classifier_sweden",
"rule": {
"rule_type": "geoip_rule",
"source": "session/client_ip",
"country": "Sweden"
}
}
],
[
{
"id": 1,
"inverted": false,
"name": "allowed_location_classifier_oslo",
"rule": {
"rule_type": "geoip_rule",
"source": "session/client_ip",
"country": "Norway",
"cities": ["Oslo"]
}
}
]
]
}
],
"cdns": [
{
"id": "basic-cdn",
"http_port": 80,
"https_port": 443,
"redirecting": false,
"manifest_availability_check": {
"enabled": false,
"session_group_ids": []
}
},
{
"id": "offload-cdn",
"http_port": 80,
"https_port": 443,
"redirecting": false,
"manifest_availability_check": {
"enabled": false,
"session_group_ids": []
}
}
],
"hosts": [
{
"id": "default-host",
"cdn_id": "basic-cdn",
"address_family": "ipv4",
"host": "cdn-host.example"
},
{
"id": "offload-host",
"cdn_id": "offload-cdn",
"address_family": "ipv4",
"host": "offload-host.example"
}
],
"routing": {
"id": "routing_table",
"member_order": "sequential",
"members": [
{
"id": "default-node",
"host_id": "default-host",
"weight_function": "return in_session_group('allowed_location')"
}
{
"id": "offload-node",
"host_id": "offload-host",
"weight_function": "return 1"
}
]
}
}
2 - Route on Subnet
This page describes how to write configuration for subnet-based routing. For configuration in general, see Configuration.
For details on the subnets API, see Subnets API.
Subnet-based routing can be done either by using session groups and classifiers or by using the subnets API, allowing large amounts of named subnets.
Session Group Classifiers
Routing on subnets can be done through a combination of session group classifiers and Lua script weight functions. Configuring session groups and classifiers based on subnets and using them in routing may look like:
$ confcli services.routing.classifiers -w
Running wizard for resource 'classifiers'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
classifiers : [
classifier can be one of
1: anonymousIp
2: asnIds
3: contentUrlPath
4: contentUrlQueryParameters
5: geoip
6: hostName
7: ipranges
8: random
9: regexMatcher
10: stringMatcher
11: subnet
12: userAgent
Choose element index or name: ipranges
Adding a 'ipranges' element
classifier : {
name (default: ): ip_ranges_classifier
type (default: ipranges): ⏎
inverted (default: False): ⏎
ipranges : [
iprange (default: ): 10.0.0.0/8
Add another 'iprange' element to array 'ipranges'? [y/N]: y
iprange (default: ): 192.168.0.0/16
Add another 'iprange' element to array 'ipranges'? [y/N]: y
iprange (default: ): 2001:0db8:85a3::/128
Add another 'iprange' element to array 'ipranges'? [y/N]: ⏎
]
}
Add another 'classifier' element to array 'classifiers'? [y/N]: ⏎
]
Generated config:
{
"classifiers": [
{
"name": "ip_ranges_classifier",
"type": "ipranges",
"inverted": false,
"ipranges": [
"10.0.0.0/8",
"192.168.0.0/16",
"2001:0db8:85a3::/128"
]
}
]
}
Merge and apply the config? [y/n]: y
$ confcli services.routing.sessionGroups -w
Running wizard for resource 'sessionGroups'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
sessionGroups : [
sessionGroup : {
name (default: ): allowed_subnets
classifiers : [
classifier (default: ): ip_ranges_classifier
Add another 'classifier' element to array 'classifiers'? [y/N]: ⏎
]
}
Add another 'sessionGroup' element to array 'sessionGroups'? [y/N]: ⏎
]
Generated config:
{
"sessionGroups": [
{
"name": "allowed_subnets",
"classifiers": [
"ip_ranges_classifier"
]
}
]
}
Merge and apply the config? [y/n]: y
{
"session_groups": [
{
"id": 1,
"name": "allowed_subnets",
"classifiers": [
[
{
"id": 1,
"inverted": false,
"name": "allowed_subnet_classifier",
"rule": {
"rule_type": "ip_ranges_rule",
"source": "session/client_ip",
"ip_ranges": ["10.0.0.0/8", "192.168.0.0/16", "2001:0db8:85a3::/128"]
}
}
]
]
}
]
}
The field ip_ranges
is a list of CIDR-notation strings, supporting both IPv4
and IPv6 format. Incoming requests have their IP tested against the listed
ranges. The classifier evaluates as true if any of the ranges in the
classifier’s list matches the IP address of the request.
These session groups can then be used in routing as follows:
$ confcli services.routing.rules -w
Running wizard for resource 'rules'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
rules : [
rule can be one of
1: allow
2: consistentHashing
3: contentPopularity
4: deny
5: firstMatch
6: random
7: rawGroup
8: rawHost
9: split
10: weighted
Choose element index or name: split
Adding a 'split' element
rule : {
name (default: ): subnet_split_node
type (default: split): ⏎
rule (default: ): return in_session_group('allowed_subnets')
onMatch (default: ): allowed-host
onMiss (default: ): offload-host
}
Add another 'rule' element to array 'rules'? [y/N]: ⏎
]
Generated config:
{
"rules": [
{
"name": "subnet_split_node",
"type": "split",
"condition": "in_session_group('allowed_subnets')",
"onMatch": "allowed-host",
"onMiss": "offload-host"
}
]
}
Merge and apply the config? [y/n]: y
$ confcli services.routing.entrypoint subnet_split_node
services.routing.entrypoint = 'subnet_split_node'
{
"content_server": {
"http_enable": true,
"http_port": 80,
"https_enable": true,
"https_port": 443
},
"cdns": [
{
"id": "allowed-cdn",
"http_port": 80,
"https_port": 443,
"redirecting": false,
"manifest_availability_check": {
"enabled": false,
"session_group_ids": []
}
},
{
"id": "offload-cdn",
"http_port": 80,
"https_port": 443,
"redirecting": false,
"manifest_availability_check": {
"enabled": false,
"session_group_ids": []
}
}
],
"hosts": [
{
"id": "allowed-host",
"cdn_id": "allowed-cdn",
"host": "allowed-host.example"
},
{
"id": "offload-host",
"cdn_id": "offload-cdn",
"host": "offload-host.example"
}
],
"routing": {
"id": "routing_table",
"member_order": "sequential",
"members": [
{
"id": "allowed-node",
"host_id": "allowed-host",
"weight_function": "return in_session_group('allowed_subnets')"
},
{
"id": "offload-node",
"host_id": "offload-host",
"weight_function": "return 1"
}
]
},
"session_groups": [
{
"id": 1,
"name": "allowed_subnets",
"classifiers": [
[
{
"id": 1,
"inverted": false,
"name": "allowed_subnet_classifier",
"rule": {
"rule_type": "ip_ranges_rule",
"source": "session/client_ip",
"ip_ranges": ["10.0.0.0/8", "192.168.0.0/16", "2001:0db8:85a3::/128"]
}
}
]
]
}
]
}
Named Subnets
Named subnets are injected into the router in the form of JSON payloads to the Subnets API. Once the subnet data has been fed to the router, Lua functions can access the subnet name associated with an incoming request and use the result when it performs routing.
Note that confcli
cannot be used to inject named subnets into the router.
Assume we have injected the following subnet configuration into the router:
{
"10.0.0.0/8": "test_net_4",
"192.168.0.0/16": "test_net_4",
"2001:0db8:85a3::/128": "test_net_6"
}
A router configuration using this subnet configuration can then be constructed as:
$ confcli services.routing.rules -w
Running wizard for resource 'rules'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
rules : [
rule can be one of
1: allow
2: consistentHashing
3: contentPopularity
4: deny
5: firstMatch
6: random
7: rawGroup
8: rawHost
9: split
10: weighted
Choose element index or name: split
Adding a 'split' element
rule : {
name (default: ): subnet_split_node
type (default: split): ⏎
rule (default: ): in_subnet('test_net_4')
onMatch (default: ): allowed-host-4
onMiss (default: ): offload-host
}
Add another 'rule' element to array 'rules'? [y/N]: ⏎
]
Generated config:
{
"rules": [
{
"name": "subnet_split_node",
"type": "split",
"condition": "in_subnet('test_net_4')",
"onMatch": "allowed-host-4",
"onMiss": "offload-host"
}
]
}
Merge and apply the config? [y/n]: y
$ confcli services.routing.entrypoint subnet_split_node
services.routing.entrypoint = 'subnet_split_node'
{
"content_server": {
"http_enable": true,
"http_port": 80,
"https_enable": true,
"https_port": 443
},
"cdns": [
{
"id": "allowed-cdn",
"http_port": 80,
"https_port": 443,
"redirecting": false,
"manifest_availability_check": {
"enabled": false,
"session_group_ids": []
}
},
{
"id": "offload-cdn",
"http_port": 80,
"https_port": 443,
"redirecting": false,
"manifest_availability_check": {
"enabled": false,
"session_group_ids": []
}
}
],
"hosts": [
{
"id": "allowed-host-4",
"cdn_id": "allowed-cdn",
"address_family": "ipv4",
"host": "allowed-host4.example"
},
{
"id": "allowed-host-6",
"cdn_id": "allowed-cdn",
"address_family": "ipv6",
"host": "allowed-host6.example"
},
{
"id": "offload-host",
"cdn_id": "offload-cdn",
"address_family": "ipv4",
"host": "offload-host.example"
}
],
"routing": {
"id": "routing_table",
"member_order": "sequential",
"members": [
{
"id": "allowed-node-4",
"host_id": "allowed-host-4",
"weight_function": "return in_subnet('test_net_4')"
},
{
"id": "allowed-node-6",
"host_id": "allowed-host-6",
"weight_function": "return in_subnet('test_net_6')"
},
{
"id": "offload-node",
"host_id": "offload-host",
"weight_function": "return 1"
}
]
}
}
Note the absence of session groups in this configuration, instead relying solely on the named subnet API to making routing decisions based on subnets.
3 - Route on Content Type
This page describes how to write configuration for content-based routing. For configuration in general, see Configuration.
Two ways to route on content type will be demonstrated: content path
based
and hostname
based using session groups and classifiers. For more details on
session groups and classifiers, see
Session Groups and Classification.
Content Path
Routing on content path is done through a combination of session group
classifiers and Lua script weight functions. Two suitable classifiers for
content path matching are string_match_rule
and regex_rule
.
The pattern is a string matching the path segment of a request URL, including
the file name. When selecting the string_match_rule
type, use asterisks for
wildcard matching. When selecting the regex_rule
follow the C++11 std::regex
ECMAScript
syntax to make valid patterns. Make sure to write patterns that match the
entire path segment, not just part of it.
Note that each content classifier normally has to be in its own list. This is because classifiers within the same inner list all have to match for the entire list to be true, and that is impossible for classifiers that match against different content paths. When the classifiers are in their own lists, it’s enough that one of them matches for the outer classifier list to also match.
Simple Example
$ confcli services.routing.classifiers -w
Running wizard for resource 'classifiers'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
classifiers : [
classifier can be one of
1: anonymousIp
2: asnIds
3: contentUrlPath
4: contentUrlQueryParameters
5: geoip
6: hostName
7: ipranges
8: random
9: regexMatcher
10: stringMatcher
11: subnet
12: userAgent
Choose element index or name: contentUrlPath
Adding a 'contentUrlPath' element
classifier : {
name (default: ): live_content_classifier
type (default: contentUrlPath): ⏎
inverted (default: False): ⏎
patternType (default: stringMatch): ⏎
pattern (default: ): *live_tv*
}
Add another 'classifier' element to array 'classifiers'? [y/N]: y
classifier can be one of
1: anonymousIp
2: asnIds
3: contentUrlPath
4: contentUrlQueryParameters
5: geoip
6: hostName
7: ipranges
8: random
9: regexMatcher
10: stringMatcher
11: subnet
12: userAgent
Choose element index or name: contentUrlPath
Adding a 'contentUrlPath' element
classifier : {
name (default: ): news_content_classifier
type (default: contentUrlPath): ⏎
inverted (default: False): ⏎
patternType (default: stringMatch): regex
pattern (default: ): /([^/]+/)?news_reports_\\d+/.*
}
Add another 'classifier' element to array 'classifiers'? [y/N]: y
classifier can be one of
1: anonymousIp
2: asnIds
3: contentUrlPath
4: contentUrlQueryParameters
5: geoip
6: hostName
7: ipranges
8: random
9: regexMatcher
10: stringMatcher
11: subnet
12: userAgent
Choose element index or name: contentUrlPath
Adding a 'contentUrlPath' element
classifier : {
name (default: ): hls_content_classifier
type (default: contentUrlPath): ⏎
inverted (default: False): ⏎
patternType (default: stringMatch): ⏎
pattern (default: ): *.m3u8
}
Add another 'classifier' element to array 'classifiers'? [y/N]: n
]
Generated config:
{
"classifiers": [
{
"name": "live_content_classifier",
"type": "contentUrlPath",
"inverted": false,
"patternType": "stringMatch",
"pattern": "*live_tv*"
},
{
"name": "news_content_classifier",
"type": "contentUrlPath",
"inverted": false,
"patternType": "regex",
"pattern": "/([^/]+/)?news_reports_\\\\d+/.*"
},
{
"name": "hls_content_classifier",
"type": "contentUrlPath",
"inverted": false,
"patternType": "stringMatch",
"pattern": "*.m3u8"
}
]
}
Merge and apply the config? [y/n]: y
confcli services.routing.sessionGroups -w
Running wizard for resource 'sessionGroups'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
sessionGroups : [
sessionGroup : {
name (default: ): live_content
classifiers : [
classifier (default: ): live_content_classifier
Add another 'classifier' element to array 'classifiers'? [y/N]: ⏎
]
}
Add another 'sessionGroup' element to array 'sessionGroups'? [y/N]: y
sessionGroup : {
name (default: ): news_content
classifiers : [
classifier (default: ): news_content_classifier
Add another 'classifier' element to array 'classifiers'? [y/N]: ⏎
]
}
Add another 'sessionGroup' element to array 'sessionGroups'? [y/N]: y
sessionGroup : {
name (default: ): hls_content
classifiers : [
classifier (default: ): hls_content_classifier
Add another 'classifier' element to array 'classifiers'? [y/N]: ⏎
]
}
Add another 'sessionGroup' element to array 'sessionGroups'? [y/N]: ⏎
]
Generated config:
{
"sessionGroups": [
{
"name": "live_content",
"classifiers": [
"live_content_classifier"
]
},
{
"name": "news_content",
"classifiers": [
"news_content_classifier"
]
},
{
"name": "hls_content",
"classifiers": [
"hls_content_classifier"
]
}
]
}
Merge and apply the config? [y/n]: y
{
"content_server": {
"http_enable": true,
"http_port": 80,
"https_enable": true,
"https_port": 443
},
"session_groups": [
{
"id": 1,
"name": "live_content",
"classifiers": [
[
{
"id": 1,
"inverted": false,
"name": "live_content_classifier",
"rule": {
"rule_type": "string_match_rule",
"source": "session/content_url_path",
"pattern": "*live_tv*"
}
}
]
],
[
[
{
"id": 2,
"inverted": false,
"name": "news_content_classifier",
"rule": {
"rule_type": "regex_rule",
"source": "session/content_url_path",
"pattern": "/([^/]+/)?news_reports_\\d+/.*"
}
}
]
]
},
{
"id": 2,
"name": "hls_content",
"classifiers": [
[
{
"id": 1,
"inverted": false,
"name": "hls_content_classifier",
"rule": {
"rule_type": "string_match_rule",
"source": "session/content_url_path",
"pattern": "*.m3u8"
}
}
]
]
}
],
"cdns": [
{
"id": "live-cdn",
"http_port": 80,
"https_port": 443,
"redirecting": false,
"manifest_availability_check": {
"enabled": false,
"session_group_ids": []
}
},
{
"id": "vod-hls-cdn",
"http_port": 80,
"https_port": 443,
"redirecting": false,
"manifest_availability_check": {
"enabled": false,
"session_group_ids": []
}
},
{
"id": "vod-cdn",
"http_port": 80,
"https_port": 443,
"redirecting": false,
"manifest_availability_check": {
"enabled": false,
"session_group_ids": []
}
}
],
"hosts": [
{
"id": "live-host",
"cdn_id": "live-cdn",
"address_family": "ipv4",
"host": "live-host.example"
},
{
"id": "vod-hls-host",
"cdn_id": "vod-hls-cdn",
"address_family": "ipv4",
"host": "vod-hls-host.example"
},
{
"id": "vod-host",
"cdn_id": "vod-cdn",
"address_family": "ipv4",
"host": "vod-host.example"
}
],
"routing": {
"id": "routing_table",
"member_order": "sequential",
"members": [
{
"id": "live-node",
"host_id": "live-host",
"weight_function": "return session_groups.live_content and 1 or 0"
},
{
"id": "vod-hls-node",
"host_id": "vod-hls-host",
"weight_function": "return session_groups.hls_content and 1 or 0"
},
{
"id": "vod-node",
"host_id": "vod-host",
"weight_function": "return 1"
}
]
}
}
Hostname
In cases where there are separate domain or subdomain names for different content types, it’s simple to make classifiers that filter on those names.
The pattern is a string matching the hostname segment of a request URL,
including the file name. When selecting the string_match_rule
type, use
asterisks for wildcard matching. When selecting the regex_rule
follow the
C++11 std::regex
ECMAScript
syntax to make valid patterns. Make sure to write patterns that match the
entire hostname segment, not just part of it.
Note that each hostname classifier has to be in its own list. This is because classifiers within the same inner list all have to match for the entire list to be true, and that is impossible for classifiers that match against different hostnames. When the classifiers are in their own lists, it’s enough that one of them matches for the outer classifier list to also match.
Simple example
$ confcli services.routing.classifiers -w
Running wizard for resource 'classifiers'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
classifiers : [
classifier can be one of
1: anonymousIp
2: asnIds
3: contentUrlPath
4: contentUrlQueryParameters
5: geoip
6: hostName
7: ipranges
8: random
9: regexMatcher
10: stringMatcher
11: subnet
12: userAgent
Choose element index or name: hostName
Adding a 'hostName' element
classifier : {
name (default: ): live_content_classifier
type (default: hostName): ⏎
inverted (default: False): ⏎
patternType (default: stringMatch): ⏎
pattern (default: ): live.example.com
}
Add another 'classifier' element to array 'classifiers'? [y/N]: y
classifier can be one of
1: anonymousIp
2: asnIds
3: contentUrlPath
4: contentUrlQueryParameters
5: geoip
6: hostName
7: ipranges
8: random
9: regexMatcher
10: stringMatcher
11: subnet
12: userAgent
Choose element index or name: hostName
Adding a 'hostName' element
classifier : {
name (default: ): news_content_classifier
type (default: hostName): ⏎
inverted (default: False): ⏎
patternType (default: stringMatch): regex
pattern (default: ): /([^\\.]+/)\\.news_reports_\\d+/\\.example\\.com
}
Add another 'classifier' element to array 'classifiers'? [y/N]: ⏎
]
Generated config:
{
"classifiers": [
{
"name": "live_content_classifier",
"type": "hostName",
"inverted": false,
"patternType": "stringMatch",
"pattern": "live.example.com"
},
{
"name": "news_content_classifier",
"type": "hostName",
"inverted": false,
"patternType": "regex",
"pattern": "/([^\\\\.]+/)\\\\.news_reports_\\\\d+/\\\\.example\\\\.com"
}
]
}
Merge and apply the config? [y/n]: y
$ confcli services.routing.sessionGroups -w
Running wizard for resource 'sessionGroups'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
sessionGroups : [
sessionGroup : {
name (default: ): live_content
classifiers : [
classifier (default: ): live_content_classifier
Add another 'classifier' element to array 'classifiers'? [y/N]: ⏎
]
}
Add another 'sessionGroup' element to array 'sessionGroups'? [y/N]: y
sessionGroup : {
name (default: ): news_content
classifiers : [
classifier (default: ): news_content_classifier
Add another 'classifier' element to array 'classifiers'? [y/N]: ⏎
]
}
Add another 'sessionGroup' element to array 'sessionGroups'? [y/N]: y
sessionGroup : {
name (default: ): hls_content
classifiers : [
classifier (default: ): hls_content_classifier
Add another 'classifier' element to array 'classifiers'? [y/N]: ⏎
]
}
Add another 'sessionGroup' element to array 'sessionGroups'? [y/N]: ⏎
]
Generated config:
{
"sessionGroups": [
{
"name": "live_content",
"classifiers": [
"live_content_classifier"
]
},
{
"name": "news_content",
"classifiers": [
"news_content_classifier"
]
},
{
"name": "hls_content",
"classifiers": [
"hls_content_classifier"
]
}
]
}
{
"content_server": {
"http_enable": true,
"http_port": 80,
"https_enable": true,
"https_port": 443
},
"session_groups": [
{
"id": 1,
"name": "live_content",
"classifiers": [
[
{
"id": 1,
"inverted": false,
"name": "live_content_classifier",
"rule": {
"rule_type": "string_match_rule",
"source": "session/hostname",
"pattern": "live.example.com"
}
}
],
[
{
"id": 2,
"inverted": false,
"name": "news_content_classifier",
"rule": {
"rule_type": "regex_rule",
"source": "session/hostname",
"pattern": "/([^\\.]+/)\\.news_reports_\\d+/\\.example\\.com"
}
}
]
]
}
],
"cdns": [
{
"id": "live-cdn",
"http_port": 80,
"https_port": 443,
"redirecting": false,
"manifest_availability_check": {
"enabled": false,
"session_group_ids": []
}
},
{
"id": "vod-cdn",
"http_port": 80,
"https_port": 443,
"redirecting": false,
"manifest_availability_check": {
"enabled": false,
"session_group_ids": []
}
}
],
"hosts": [
{
"id": "live-host",
"cdn_id": "live-cdn",
"address_family": "ipv4",
"host": "live-host.example"
},
{
"id": "vod-host",
"cdn_id": "vod-cdn",
"address_family": "ipv4",
"host": "vod-host.example"
}
],
"routing": {
"id": "routing_table",
"member_order": "sequential",
"members": [
{
"id": "live-node",
"host_id": "live-host",
"weight_function": "return session_groups.live_content and 1 or 0"
},
{
"id": "vod-node",
"host_id": "vod-host",
"weight_function": "return 1"
}
]
}
}
Using the session groups in confcli
The constructed session groups can be used in routing by creating a rule that references them:
$ confcli services.routing.rules -w
Running wizard for resource 'rules'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
rules : [
rule can be one of
1: allow
2: consistentHashing
3: contentPopularity
4: deny
5: firstMatch
6: random
7: rawGroup
8: rawHost
9: split
10: weighted
Choose element index or name: firstMatch
Adding a 'firstMatch' element
rule : {
name (default: ): classifier_routing_rule
type (default: firstMatch): ⏎
targets : [
target : {
onMatch (default: ): live-host
rule (default: ): in_all_session_groups('live_content', 'news_content')
}
Add another 'target' element to array 'targets'? [y/N]: y
target : {
onMatch (default: ): vod-hls-host
rule (default: ): in_session_group('hls_content')
}
Add another 'target' element to array 'targets'? [y/N]: y
target : {
onMatch (default: ): offload-host
rule (default: ): always()
}
Add another 'target' element to array 'targets'? [y/N]: ⏎
]
}
Add another 'rule' element to array 'rules'? [y/N]: ⏎
]
Generated config:
{
"rules": [
{
"name": "classifier_routing_rule",
"type": "firstMatch",
"targets": [
{
"onMatch": "live-host",
"condition": "in_all_session_groups('live_content', 'news_content')"
},
{
"onMatch": "vod-hls-host",
"condition": "in_session_group('hls_content')"
},
{
"onMatch": "offload-host",
"condition": "always()"
}
],
}
]
}
Merge and apply the config? [y/n]: y
$ confcli services.routing.entrypoint classifier_routing_rule
services.routing.entrypoint = classifier_routing_rule
4 - Route on Content Popularity
This page describes how to write configuration for content popularity routing. For configuration in general, see Configuration.
For more details on content popularity tuning and routing, see
Content Popularity
The router tracks content popularity which can be utilized for routing.
Using the configuration tool confcli
, creating a content popularity based
routing configuration for hierarchical and multi-edge scenarios will be
demonstrated.
Hierarchical
Consider a CDN setup with edge streamers that has cached popular content and a central streamer where all content is available. You can decide where to route clients based on the requested content’s popularity.
Assuming that appropriate streamer hosts have already been configured, configuration will look like:
$ confcli services.routing.rules -w
Running wizard for resource 'rules'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
rules : [
rule can be one of
1: allow
2: consistentHashing
3: contentPopularity
4: deny
5: firstMatch
6: random
7: rawGroup
8: rawHost
9: split
10: weighted
Choose element index or name: contentPopularity
Adding a 'contentPopularity' element
rule : {
name (default: ): contentPopularityHierarchy
type (default: contentPopularity): ⏎
popularityThreshold (default: 10): 2000
onPopular (default: ): edgeStreamer
onUnpopular (default: ): centralStreamer
}
Add another 'rule' element to array 'rules'? [y/N]: ⏎
]
Generated config:
{
"rules": [
{
"name": "contentPopularityHierarchy",
"type": "contentPopularity",
"popularityThreshold": 2000.0,
"onPopular": "edgeStreamer",
"onUnpopular": "offloadStreamer"
}
]
}
Merge and apply the config? [y/n]: y
where name
is the name of the rule, isPopular
is the rule to route to if
the content is popular, otherwise the rule isUnpopular
is routed to. Lastly,
popularityThreshold
is the threshold for which content is considered popular.
Configuring popularityThreshold
= 2001 means that the top 2000 most popular
assets will be routed to edgeStreamer
.
The rule contentPopularityHierarchy
can then be used to construct your routing
tree.
Multi-edge
Consider a CDN setup with three edge streamers, edge1
, edge2
and
edge3
, configured to cache very popular content, mildly popular content
and unpopular content respectively. Assuming that appropriate streamer
hosts have already been configured, the following configuration can be used for
correctly routing a request in this scenario:
$ confcli services.routing.rules -w
Running wizard for resource 'rules'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
rules : [
rule can be one of
1: allow
2: consistentHashing
3: contentPopularity
4: deny
5: firstMatch
6: random
7: rawGroup
8: rawHost
9: split
10: weighted
Choose element index or name: contentPopularity
Adding a 'contentPopularity' element
rule : {
name (default: ): mildlyAndUnpopular
type (default: contentPopularity): ⏎
popularityThreshold (default: 10): 2001
onPopular (default: ): edge2
onUnpopular (default: ): edge3
}
Add another 'rule' element to array 'rules'? [y/N]: y
rule can be one of
1: allow
2: consistentHashing
3: contentPopularity
4: deny
5: firstMatch
6: random
7: rawGroup
8: rawHost
9: split
10: weighted
Choose element index or name: contentPopularity
Adding a 'contentPopularity' element
rule : {
name (default: ): multiLevelPopularity
type (default: contentPopularity): ⏎
popularityThreshold (default: 10): 101
onPopular (default: ): edge1
onUnpopular (default: ): mildyAndUnpopular
}
Add another 'rule' element to array 'rules'? [y/N]: ⏎
]
Generated config:
{
"rules": [
{
"name": "mildlyAndUnpopular",
"type": "contentPopularity",
"popularityThreshold": 2001.0,
"onPopular": "edge2",
"onUnpopular": "edge3"
},
{
"name": "multiLevelPopularity",
"type": "contentPopularity",
"popularityThreshold": 101.0,
"onPopular": "edge1",
"onUnpopular": "mildyAndUnpopular"
}
]
}
Merge and apply the config? [y/n]: y
By configuring a rule to route to multiLevelPopularity
,
this configuration will route requests for the top 100 most popular content
to edge1
, popularity ranking 101-2000 to edge2
and popularity
ranking > 2000 to edge3
. Since the contentPopularity
rule offers a binary
routing choice of either isPopular
or isUnpopular
, multiple
contentPopularity
rules can be utilized to construct multi-leveled content
popularity based routing configurations.
Application
To use any of these two configurations in your installation, you’ll need to
configure either a rule or the entrypoint
to route to either
multiLevelPopularity
or contentPopularityHierarchy
.
5 - Route on Selection Input
This page describes how to write configuration for routing on bandwidth usage or number of ongoing sessions in Edgeware CDN:s by using the selection input API. For configuration in general, see Configuration.
For more details on the selection input API, see Selection Input.
Selection Input
The selection input API allows you to inject custom data, that can be used during routing, into the router. For this use case, we will use CDN bandwidth and the number of ongoing sessions to demonstrate the capabilities of the selection input API.
Imagine that we have a monitor constantly polling the bandwidth and ongoing sessions of hosts in a CDN. These values are injected into the selection input API as JSON packets:
{
"edge-host-available-bps": 1000000000,
"edge-host-ongoing-sessions": 300
}
These keys will end up in the router Lua context as “selection inputs”, arbitrary values or JSON objects that can be used to calculate routing weights.
The selection input variable edge-host-available-bps
will be available
through either selection_input.edge-host-available-bps
or
si('edge-host-available-bps')
. The function si(si_var)
fetches the selection input value if it exists, otherwise it returns 0.
However, when comparing selection input variables with numbers, there are a
number of built-in Lua functions that will simplify things, such as gt()
and
lt()
. For a complete list and more details on these functions, see
Built-in Functions.
Simple Example
$ confcli services.routing.rules -w
Running wizard for resource 'rules'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
rules : [
rule can be one of
1: allow
2: consistentHashing
3: contentPopularity
4: deny
5: firstMatch
6: random
7: rawGroup
8: rawHost
9: split
10: weighted
Choose element index or name: firstMatch
Adding a 'firstMatch' element
rule : {
name (default: ): selection-input-routing
type (default: firstMatch): ⏎
targets : [
target : {
onMatch (default: ): edge-host
rule (default: ): lt('edge_host_ongoing_sessions', 1000)
}
Add another 'target' element to array 'targets'? [y/N]: y
target : {
onMatch (default: ): edge-host
rule (default: ): gt('edge_host_available_bps', 5000000)
}
Add another 'target' element to array 'targets'? [y/N]: y
target : {
onMatch (default: ): offload-host
rule (default: ): always()
}
Add another 'target' element to array 'targets'? [y/N]: ⏎
]
onMiss (default: ): offload-host
}
Add another 'rule' element to array 'rules'? [y/N]: ⏎
]
Generated config:
{
"rules": [
{
"name": "selection-input-routing",
"type": "firstMatch",
"targets": [
{
"onMatch": "edge-host",
"condition": "lt('edge_host_ongoing_sessions', 1000)"
},
{
"onMatch": "edge-host",
"condition": "gt('edge_host_available_bps', 5000000)"
},
{
"onMatch": "offload-host",
"condition": "always()"
}
]
}
]
}
Merge and apply the config? [y/n]: y
$ confcli services.routing.entrypoint selection-input-routing
services.routing.entrypoint = 'selection-input-routing'
{
"content_server": {
"http_enable": true,
"http_port": 80,
"https_enable": true,
"https_port": 443
},
"cdns": [
{
"id": "edge-cdn",
"http_port": 80,
"https_port": 443,
"redirecting": false,
"manifest_availability_check": {
"enabled": false,
"session_group_ids": []
}
},
{
"id": "offload-cdn",
"http_port": 80,
"https_port": 443,
"redirecting": false,
"manifest_availability_check": {
"enabled": false,
"session_group_ids": []
}
}
],
"hosts": [
{
"id": "edge-host",
"cdn_id": "edge-cdn",
"host": "edge-host.example"
},
{
"id": "offload-host",
"cdn_id": "offload-cdn",
"host": "offload-host.example"
}
],
"routing": {
"id": "routing-table",
"member_order": "sequential",
"members": [
{
"id": "edge-host-sessions-available",
"host_id": "edge-host",
"weight_function": "return (lt('edge_host_ongoing_sessions', 1000) ~= 0) and 1 or 0"
},
{
"id": "edge-host-bandwith-available",
"host_id": "edge-host",
"weight_function": "return (gt('edge_host_available_bps', 5000000) ~= 0) and 1 or 0"
},
{
"id": "offload",
"host_id": "offload-host",
"weight_function": "return 1"
}
]
}
}
6 - Adapt to multi-CDN
This page describes how to write configuration for setups that require the URL sent back to the client to be rewritten based on routing results, for example by adding a token to the path or as a query string parameter. For configuration in general, see Configuration.
In order to change the redirect location URL, we need to add a response translation function to the confd configuration. By default, all translation functions are empty:
$ confcli services.routing.translationFunctions
{
"translationFunctions": {
"request": "",
"response": ""
}
}
For full documentation of the response translation function, please see Lua Hooks.
Simple example
Translation functions tend to become large, which makes it hard to write
them inside a single string. Instead, the function can be written in a separate
.lua
script file that is uploaded to the router and referenced from the
confd
configuration.
The following example will take this approach, adding a script called
"rewrite.lua"
to the configured custom Lua folder /tmp/custom_lua
on
the router. For more information see the Configuration JSON Overview.
Lua script
The following script assumes the existence of the function parse_url
that
returns an object with URL segments that can be altered and then combined into
a URL string using the tostring(obj)
function again.
Beware that the router does not validate the URL in the Location header, it is up to the Lua script writer to ensure that only URLs are returned.
function response_rewrite(Headers)
-- The live server has the token as part of the path, added first before the
-- path from the request.
local location = parse_url(response_headers.location)
if location.host == "live-host.example" then
location.path = "/live-prefix" .. location.path
return HTTPResponse(
{
Headers = {
{"location", tostring(location)}
}
}
)
end
-- The VOD server expects the token as a query string rather than as part
-- of the path segment.
-- Since VOD can be used for offload, check that session_groups.is_vod
-- is set as well.
if location.host == "vod-host.example" and session_groups.is_vod then
location.query["token"] = md5sum(secret_key .. request.path)
return HTTPResponse(
{
Headers = {
{"location", tostring(location)}
}
}
)
end
-- If the request was neither in the is_live session group, nor contained
-- the path element "vod", we return a nil object to indicate that we don't
-- want to change anything in the response.
return nil
end
Configuration
To configure a response translation function using with the custom Lua function
response_rewrite()
using confcli
, run the command:
$ confcli services.routing.translationFunctions.response 'return response_rewrite()'
services.routing.translationFunctions.response = 'return response_rewrite()'
An example confd
configuration utilizing this translation function based on
session groups would look like this:
$ confcli services.routing
{
"translationFunctions": {
"request": "",
"response": "return response_rewrite()"
},
"sessionGroups": [
{
"name": "is_live",
"classifiers": [
"is_live_classifier"
]
},
{
"name": "is_vod",
"classifiers": [
"is_vod_classifier"
]
}
],
"classifiers": [
{
"name": "is_live_classifier",
"type": "contentUrlPath",
"inverted": false,
"patternType": "stringMatch",
"pattern": "*/live/*"
},
{
"name": "is_vod_classifier",
"type": "contentUrlPath",
"inverted": false,
"patternType": "stringMatch",
"pattern": "*/vod/*"
}
],
"hostGroups": [
{
"name": "live-cdn",
"type": "host",
"httpPort": 80,
"httpsPort": 443,
"hosts": [
{
"name": "live-host",
"hostname": "live-host.example",
"ipv6_address": ""
}
]
},
{
"name": "vod-cdn",
"type": "host",
"httpPort": 80,
"httpsPort": 443,
"hosts": [
{
"name": "vod-host",
"hostname": "vod-host.example",
"ipv6_address": ""
}
]
}
],
"rules": [
{
"name": "multiCdnExample",
"type": "firstMatch",
"targets": [
{
"condition": "in_session_group('is_live')",
"onMatch": "live-host"
},
{
"condition": "in_session_group('is_vod')",
"onMatch": "vod-host"
},
// Use the vod-host as offload for any content, but don't set any
// token for requests not classified as vod.
{
"condition": "always()",
"onMatch": "vod-host"
}
]
}
],
"entrypoint": "multiCdnExample",
"applyConfig": true
}
7 - How to use ACD router for EDNS routing
This page describes how to write configuration for EDNS routing. For configuration in general, see Configuration.
EDNS routing
In your CDN architecture, you might utilize EDNS routing to redirect clients. Whether it’s your own CDN or a third party CDN, the ESB3024 Router supports creating EDNS requests and sending them to any DNS server.
Configuration
To configure EDNS routing, you first need to create a DNS type host.
Using confcli
:
[user@acd-router ~]# confcli services.routing.hostGroups -w
Running wizard for resource 'hostGroups'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
hostGroups : [
hostGroup can be one of
1: dns
2: host
3: redirecting
Choose element index or name: dns
Adding a 'dns' element
hostGroup : {
name (default: ): edns-cdn
type (default: dns): ⏎
hosts : [
host : {
name (default: ): edns-host
hostname (default: ): ednshost.com
ipv6_address (default: ): ⏎
}
Add another 'host' element to array 'hosts'? [y/N]: ⏎
]
}
Add another 'hostGroup' element to array 'hostGroups'? [y/N]: ⏎
]
Generated config:
{
"hostGroups": [
{
"name": "edns-cdn",
"type": "dns",
"hosts": [
{
"name": "edns-host",
"hostname": "ednshost.com",
"ipv6_address": ""
}
]
}
]
}
Merge and apply the config? [y/n]: y
Note that the hostname
is the name of the DNS server that will receive
the EDNS request. You can now use the DNS host when creating the routing tree,
e.g. in a random
type rule:
[user@router ~]# confcli services.routing.rules -w
Running wizard for resource 'rules'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
rules : [
rule can be one of
1: allow
2: consistentHashing
3: contentPopularity
4: deny
5: firstMatch
6: random
7: rawGroup
8: rawHost
9: split
10: weighted
Choose element index or name: random
Adding a 'random' element
rule : {
name (default: ): random-rule
type (default: random): ⏎
targets : [
target (default: ): edns-host
Add another 'target' element to array 'targets'? [y/N]: ⏎
]
}
Add another 'rule' element to array 'rules'? [y/N]: ⏎
]
Generated config:
{
"rules": [
{
"name": "random-rule",
"type": "random",
"targets": [
"edns-host"
]
}
]
}
Merge and apply the config? [y/n]: y
[user@router ~]# confcli services.routing.entrypoint random-rule
services.routing.entrypoint = 'random-rule'
Or simply use it as the entrypoint:
confcli services.routing.entrypoint edns-host
8 - How to use ESB3024 Router with Edgeware CDN Request Router
This page describes how to write configuration for using ESB3024 Router in conjunction with ESB3008 Request Router. It can request a host from an ESB3008 Request Router and forward the response to the client, perform load balancing between several Request Routers and handle fallback to an external CDN in case no Request Routers are able to service the request.
Simple Example
# The tuning parameter `target.requestAttempts` controls the number of attempts
# made to find a host. In this example we want to fallback to the external CDN
# in case both Request Routers are down, so we set it to at least 3.
$ confcli services.routing.tuning.target.requestAttempts 3
services.routing.tuning.target.requestAttempts = 3
# Create a classifier to filter incoming requests from Sweden.
$ confcli services.routing.classifiers -w
Running wizard for resource 'classifiers'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
classifiers : [
classifier can be one of
1: anonymousIp
2: asnIds
3: contentUrlPath
4: contentUrlQueryParameters
5: geoip
6: hostName
7: ipranges
8: random
9: regexMatcher
10: stringMatcher
11: subnet
12: userAgent
Choose element index or name: geoip
Adding a 'geoip' element
classifier : {
name (default: ): sweden_classifier
type (default: geoip): ⏎
inverted (default: False): ⏎
continent (default: ): ⏎
country (default: ): sweden
cities : [
city (default: ): ⏎
Add another 'city' element to array 'cities'? [y/N]: ⏎
]
asn (default: ): ⏎
}
Add another 'classifier' element to array 'classifiers'? [y/N]: ⏎
]
Generated config:
{
"classifiers": [
{
"name": "sweden_classifier",
"type": "geoip",
"inverted": false,
"continent": "",
"country": "sweden",
"cities": [
""
],
"asn": ""
}
]
}
Merge and apply the config? [y/n]: y
# Create a session group for the non-Swedish requests, to use in routing rules
$ confcli services.routing.sessionGroups -w
Running wizard for resource 'sessionGroups'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
sessionGroups : [
sessionGroup : {
name (default: ): sweden
classifiers : [
classifier (default: ): sweden_classifier
Add another 'classifier' element to array 'classifiers'? [y/N]: ⏎
]
}
Add another 'sessionGroup' element to array 'sessionGroups'? [y/N]: ⏎
]
Generated config:
{
"sessionGroups": [
{
"name": "sweden",
"classifiers": [
"sweden_classifier"
]
}
]
}
Merge and apply the config? [y/n]: y
# The internal CDN uses Edgeware Request Routers that return a redirect
# location. The router takes the content from the client request,
# and makes its own request to the Request Router using that same
# content. The returned location is then forwarded to the client.
#
# In case the Request Router responds with an error code, or times out,
# the router will continue traversing the routing tree until a
# successful route is found or the entire tree has been evaluated.
$ confcli services.routing.hostGroups -w
Running wizard for resource 'hostGroups'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
hostGroups : [
hostGroup can be one of
1: dns
2: host
3: redirecting
Choose element index or name: redirecting
Adding a 'redirecting' element
hostGroup : {
name (default: ): internal-cdn
type (default: redirecting): ⏎
httpPort (default: 80): ⏎
httpsPort (default: 443): ⏎
hosts : [
host : {
name (default: ): internal-host-1
hostname (default: ): internal-host-1.example.com
ipv6_address (default: ): ⏎
}
Add another 'host' element to array 'hosts'? [y/N]: y
host : {
name (default: ): internal-host-2
hostname (default: ): internal-host-2.example.com
ipv6_address (default: ): ⏎
}
Add another 'host' element to array 'hosts'? [y/N]: ⏎
]
}
Add another 'hostGroup' element to array 'hostGroups'? [y/N]: ⏎
]
Generated config:
{
"hostGroups": [
{
"name": "internal-cdn",
"type": "redirecting",
"httpPort": 80,
"httpsPort": 443,
"hosts": [
{
"name": "internal-host-1",
"hostname": "internal-host-1.example.com",
"ipv6_address": ""
},
{
"name": "internal-host-2",
"hostname": "internal-host-2.example.com",
"ipv6_address": ""
}
]
}
]
}
Merge and apply the config? [y/n]: y
# The offload CDN is non-redirecting, meaning that router does not
# make any request to its associated hosts to ask for a redirect location
# to forward to the clients, instead it simply returns a location using
# one of the CDN's hosts substituted for the router's host in the
# client request possibly with some kind of respsonse translation to add
# e.g. tokens or path prefixes.
$ confcli services.routing.hostGroups -w
Running wizard for resource 'hostGroups'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
hostGroups : [
hostGroup can be one of
1: dns
2: host
3: redirecting
Choose element index or name: host
Adding a 'host' element
hostGroup : {
name (default: ): offload-cdn
type (default: host): ⏎
httpPort (default: 80): ⏎
httpsPort (default: 443): ⏎
hosts : [
host : {
name (default: ): offload-host
hostname (default: ): offload-host.example.com
ipv6_address (default: ): ⏎
}
Add another 'host' element to array 'hosts'? [y/N]: ⏎
]
}
Add another 'hostGroup' element to array 'hostGroups'? [y/N]: ⏎
]
Generated config:
{
"hostGroups": [
{
"name": "offload-cdn",
"type": "host",
"httpPort": 80,
"httpsPort": 443,
"hosts": [
{
"name": "offload-host",
"hostname": "offload-host.example.com",
"ipv6_address": ""
}
]
}
]
}
Merge and apply the config? [y/n]: y
# Begin with adding a load balancing route rule between the two internal
# hosts. Let's make internal-host-2 have twice the capacity of
# internal-host-1 by using a weighted rule.
$ confcli services.routing.rules -w
Running wizard for resource 'rules'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
rules : [
rule can be one of
1: allow
2: consistentHashing
3: contentPopularity
4: deny
5: firstMatch
6: random
7: rawGroup
8: rawHost
9: split
10: weighted
Choose element index or name: weighted
Adding a 'weighted' element
rule : {
name (default: ): balancer
type (default: weighted): ⏎
targets : [
target : {
target (default: ): internal-host-1
weight (default: 100): 1,
rule (default: always()): always()
}
Add another 'target' element to array 'targets'? [y/N]: y
target : {
target (default: ): internal-host-2
weight (default: 100): 2,
rule (default: always()): always()
}
Add another 'target' element to array 'targets'? [y/N]: ⏎
]
}
Add another 'rule' element to array 'rules'? [y/N]: ⏎
]
Generated config:
{
"rules": [
{
"name": "balancer",
"type": "weighted",
"targets": [
{
"target": "internal-host-1",
"weight": "1",
"rule:": "always()"
},
{
"target": "internal-host-2",
"weight": "2",
"rule:": "always()"
}
]
}
]
}
Merge and apply the config? [y/n]: y
# Make an offload rule to route any traffic not in Sweden to the
# offload CDN.
$ confcli services.routing.rules -w
Running wizard for resource 'rules'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
rules : [
rule can be one of
1: allow
2: consistentHashing
3: contentPopularity
4: deny
5: firstMatch
6: random
7: rawGroup
8: rawHost
9: split
10: weighted
Choose element index or name: firstMatch
Adding a 'firstMatch' element
rule : {
name (default: ): offload
type (default: firstMatch): ⏎
targets : [
target : {
onMatch (default: ): offload-host
rule (default: ): not in_session_group('sweden')
}
Add another 'target' element to array 'targets'? [y/N]: y
target : {
onMatch (default: ): balancer
rule (default: ): in_session_group('sweden')
}
Add another 'target' element to array 'targets'? [y/N]: ⏎
]
onMiss (default: ): offload-host
}
Add another 'rule' element to array 'rules'? [y/N]: ⏎
]
Generated config:
{
"rules": [
{
"name": "offload",
"type": "firstMatch",
"targets": [
{
"onMatch": "offload-host",
"condition": "not in_session_group('sweden')"
},
{
"onMatch": "balancer",
"condition": "in_session_group('sweden')"
}
],
"onMiss": "offload-host"
}
]
}
Merge and apply the config? [y/n]: y
{
"tuning": {
// "target_request_attempts" controls the number of attempts to find a host.
// In this example we want to fallback to the external CDN in case both
// Request Routers are down, so we set it to 3.
"target_request_attempts": 3
},
"session_groups": [
{
"id": 1,
"name": "not_sweden",
"classifiers": [
[
{
"id": 1,
"inverted": true,
"name": "not_sweden_classifier",
"rule": {
"rule_type": "geoip_rule",
"source": "session/client_ip",
"country": "Sweden"
}
}
]
]
}
],
"cdns": [
{
"id": "internal-cdn",
"http_port": 80,
"https_port": 443,
// The internal CDN uses Edgeware Request Routers that return a redirect
// location. The router takes the content from the client request,
// and makes its own request to the Request Router using that same
// content. The returned location is then forwarded to the client.
//
// In case the Request Router responds with an error code, or times out,
// the router will continue traversing the routing tree until a
// successful route is found or the entire tree has been evaluated.
"redirecting": true,
"manifest_availability_check": {
"enabled": false,
"session_group_ids": []
}
},
{
"id": "offload-cdn",
"http_port": 80,
"https_port": 443,
// The offload CDN is non-redirecting, meaning that router does not
// make any request to its associated hosts to ask for a redirect location
// to forward to the clients, instead it simply returns a location using
// one of the CDN's hosts substituted for the router's host in the
// client request possibly with some kind of respsonse translation to add
// e.g. tokens or path prefixes.
"redirecting": false,
"manifest_availability_check": {
"enabled": false,
"session_group_ids": []
}
}
],
"hosts": [
{
"id": "internal-host-1",
"cdn_id": "internal-cdn",
"address_family": "ipv4",
"host": "internal-host-1.example"
},
{
"id": "internal-host-2",
"cdn_id": "internal-cdn",
"address_family": "ipv4",
"host": "internal-host-2.example"
},
{
"id": "offload-host",
"cdn_id": "offload-cdn",
"address_family": "ipv4",
"host": "offload-host.example"
}
],
"routing": {
"id": "routing_table",
// "sequential" - Go through the rules at this level one by one, and pick
// the first that returns a positive weight.
"member_order": "sequential",
"members": [
{
"id": "reject-node",
"host_id": "offload-host",
// Send filtered-out clients to an offload host.
"weight_function": "return session_groups.not_sweden and 1 or 0"
},
{
"id": "internal_routing",
// Return 1 to make sure this tree is evaluated at all.
"weight_function": "return 1"
// "weighted" - Evaluate all the rules at this level, and pick one of
// them randomly based on their respective weights.
//
// In this example host 1 has half the capacity of host 2, so we just
// randomly route twice as many clients to host 2.
"member_order": "weighted",
"members": [
{
"id": "internal-node-1",
"host_id": "internal-host-1",
// Half the weight of the other host -> half as likely to be picked.
"weight_function": "return 1"
},
{
"id": "internal-node-2",
"host_id": "internal-host-2",
// Twice the weight of the other -> twice as likely to be picked.
"weight_function": "return 2"
}
]
},
{
// Add a non-redirecting offload host as the last target in case all the
// internal redirecting hosts are unavailable or respond with some kind
// of error code.
"id": "offload-node",
"host_id": "offload-host",
"weight_function": "return 1"
}
]
}
}
9 - How to use ESB3024 Router with CoreDNS
CoreDNS can be configured to work as a DNS server in front of ESB3024 Router. In this mode of operation the client DNS request is terminated by CoreDNS which requests an optimal streaming location from the router.
Contact Edgeware for detailed information on how to set this up, if you don’t already have an Edgeware Support account please contact us here.
10 - How to use the Director as a replacement for Edgeware CDN Request Router
This guide outlines how to replicate Convoy’s ESB3008 HTTP Request Router using the Director. This is accomplished using the Convoy Bridge, which is an integration service designed to allow the router and an existing Convoy installation to work together seamlessly.
Following the steps outlined below enables the replacement of existing ESB3008 HTTP Request Router instances with the Director. As of the current documentation, the Director is not a direct substitute for the ESB3008 HTTP Request Router. However, most of the functionality is available, and in the majority of cases, the Director can be used without any loss of functionality.
The purpose of this guide is to detail the process of transitioning from an existing Convoy installation, which includes one or more instances of ESB3008 HTTP Request Router, to a configuration utilizing the Director. This transition allows the existing Convoy installation to continue its role in CDN provisioning, content management, and analytics. Simultaneously, the router assumes responsibility for managing HTTP(S) redirects directly from clients to selected streamers.
One functional difference between ESB3008 HTTP Request Router and the Director is
in communication with the streamer to determine specific interface assignments.
ESB3008 uses a proprietary protocol to communicate with the streamer to help determine
the best interface for the client. For the Director, in order to work with both
streamers and third-party CDNs, the use of the proprietary protocol is not supported,
and the router’s rule engine must be used to accomplish the same result. It is for
this reason that it is recommended to configure each streaming interface as a distinct
host
entry in the router’s configuration. This allows the router to address each
interface separately.
Prerequisites
This guide assumes both an existing Convoy installation and a partiality configured
instance of the Director. The router should have all the necessary routing configuration
in place for hostGroups
, sessionGroups
and routing rules
to direct traffic
to the streaming interfaces of the streamers. It is also assumed that the proper
firewall rules are allowing the required traffic between the router, the Convoy
Bridge integration and the Convoy management nodes.
The minimum compatible version of Convoy which can be used with the analytics synchronization feature is Convoy 3.0.0. Previous versions may be used only if Convoy is not being used for analytics.
Firewall Configuration
Proper firewall configuration is required to allow both the router and Convoy to communicate through bidirectional connections established from the Convoy Bridge integration. The Convoy Bridge does not need to be enabled for each router instance, one instance of the Convoy Bridge can synchronize multiple instances of the router simultaneously. Only the router nodes with the Convoy Bridge enabled will need access through the firewall to establish outgoing connections to the Convoy management nodes, or whichever nodes are running MariaDB and Kafka. Additionally, if multiple router instances are to be synchronized by a single Convoy Bridge instance, the firewall must allow the Convoy Bridge to establish connections to each router instance on port 5001.
The following table outlines the necessary connections to be allowed through the firewall.
Source | Destination | Port | Description |
---|---|---|---|
Convoy Bridge | Convoy Management | 3306/TCP | Account Configuration |
Convoy Bridge | Convoy Management | 9092/TCP | Analytics Data |
Convoy Bridge | The router | 5001/TCP | Rest API |
Response Translation Functions
In order to have the router generate a redirect URL which is compatible with the
format generated by the ESB3008 HTTP Request Router, a response translation function
must be used to modify the redirect URL before it is returned to the client. A built-in
function convoy_compatibility_response
is available to be
used for this purpose. This function appends both the session-id
and storage-prefix
based on the account and distribution information in Convoy.
On the Director, set the response translation function as follows:
> confcli services.routing.translationFunctions.response "return convoy_compatibility_response(Headers, '')"
This function depends on the account synchronization feature of the Convoy bridge to
determine the correct storage prefix based on the incoming Host
header value. It works
by using the Host
header to lookup the storage prefix from the account configuration,
and then modifying the redirect URL to prepend /session/<session-id>/<prefix>
. The
streamer can then use this information for both origin selection and session tracking.
Enabling the Convoy Bridge
Before using the Convoy Bridge integration, a valid configuration must first be applied.
All configuration for the Convoy Bridge is available in confd
under the key
integration.convoy.bridge
. The configuration is divided into three main sections:
The account synchronization feature, the convoy analytics integration, and a list of
additional router instances to synchronize.
By default, the Convoy Bridge will include the current local router instance in the synchronization process. The connection details are hard-wired into the container at startup, and do not need to be specified in the configuration. Because one Convoy Bridge can serve multiple instances of the router, it is not necessary to configure the Convoy Bridge on each node separately. However, if multiple Convoy Bridge instances are used, it is recommended to configure them so that one router is served by multiple instances of the Convoy Bridge. This provides high-availability in a production environment.
As an example, if there are 4 router instances, A, B, C, and D, and 4 Convoy Bridge instances, configuring them such that Bridge 1 synchronizes A & B, 2, synchronizes B & C, 3, synchronizes C & D and 4 synchronizes D & A will provide fault tolerance in the event that one bridge is unavailable.
The account synchronization feature of the Convoy Bridge watches the MariaDB database on the
Convoy management node for changes to the account and distribution configuration, and if
the configuration differs from what is currently known to the router the configuration
will be updated. This feature is required by both the router for use with the
convoy_compatibility_response
response translation function, and within the Convoy
Bridge integration for setting the correct account
, storage
, and distribution
fields
with the analytics integration feature.
The analytics integration feature monitors monitors the router’s Event API for
newly established sessions, and produces session-record
messages over the Kafka
message broker for use by Convoy. This feature requires that Convoy is both licensed
and configured for use with the analytics feature. The integration works by establishing
a persistent connection to each router, and listening for new session events. Due to the
protocol in use by the Event API to send the events, only one instance of the Convoy
Bridge will have the ability to receive each event, and only that instance will produce
the session-record
to the Kafka message brokers.
Synchrnoizing multiple routers with the same instance of the Convoy Bridge is performed
by configuring the otherRouters
section of the Convoy Bridge configuration. In addition
to the local router, each otherRouter
entry will have the same account and distribution
information updated simultaneously, and will be used as an event source for the analytics
integration. The otherRouters
entries require the URL to the router’s Rest API, an
optional API key, and a flag to indicate if SSL certificate validation should be enforced.
Enable the account synchronization feature by running the following command:
> confcli integration.convoy.bridge.accounts -w
Running wizard for resource 'accounts'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
accounts : {
enabled (default: False): true
dbUrl (default: mysql://user:pass@localhost:3306): mysql://convoy:password@convoy-mgmt1:3306
cmsUrl (default: http://localhost:5555): http://convoy-mgmt1:5555
pollInterval (default: 60):
}
Generated config:
{
"accounts": {
"enabled": true,
"dbUrl": "mysql://convoy:password@convoy-mgmt1:3306",
"cmsUrl": "http://convoy-mgmt1:5555",
"pollInterval": 60
}
}
Merge and apply the config? [y/n]:
This will result in the Convoy Bridge continuously polling the Convoy instance running on
convoy-mgmt1
every 60 seconds for changes to the account configuration. Only when the
account configuration differs from the current configuration on the router will it be
updated with the change.
The pollInterval
parameter can be used to control how frequently the Convoy Bridge will
attempt to poll the database for changes. Setting this value too high will result in a longer delay
between changes being made in Convoy and the changes being reflected in the router. Setting this
value too low will result in unnecessary load on the Convoy database. The default value of 60 seconds
should be sufficient for most use cases.
To enable the analytics integration feature, run the following command:
> confcli integration.convoy.bridge.analytics -w
Running wizard for resource 'analytics'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
analytics : {
enabled (default: False): true
brokers : [
broker (default: ): convoy-mgmt1:9092
Add another 'broker' element to array 'brokers'? [y/N]: y
broker (default: ): convoy-mgmt2:9092
Add another 'broker' element to array 'brokers'? [y/N]: y
broker (default: ): convoy-mgmt3:9092
Add another 'broker' element to array 'brokers'? [y/N]: n
]
batchInterval (default: 10):
maxBatchSize (default: 500):
}
Generated config:
{
"analytics": {
"enabled": true,
"brokers": [
"convoy-mgmt1:9092",
"convoy-mgmt2:9092",
"convoy-mgmt3:9092"
],
"batchInterval": 10,
"maxBatchSize": 500
}
}
Merge and apply the config? [y/n]:
This will enable the analytics integration, which will produce session-record
messages
to the configured Kafka
brokers. The brokers
configuration list is used to bootstrap the
initial set of brokers which will be contacted by the Convoy Bridge to then obtain the
current set of active brokers. It is not necessary to include all brokers here, as the
initial connection will automatically negotiate the correct broker list.
The batchInterval
parameter must be set to a value much less than 60 seconds, since the
streamer will send session-sample
messages to Kafka every 60 seconds, and if the
corresponding session-record
message is not received within that time, the sample will
be dropped, resulting in potentially inaccurate bandwidth statistics.
> confcli integration.convoy.bridge.otherRouters -w
Running wizard for resource 'otherRouters'
<Other routers which will be kept in sync (default: [])>
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
otherRouters <Other routers which will be kept in sync (default: [])>: [
otherRouter : {
url (default: ): https://router-2:5001
apiKey (default: ): 1234
validateCerts (default: True): false
}
Add another 'otherRouter' element to array 'otherRouters'? [y/N]: y
otherRouter : {
url (default: ): https://router-3:5001
apiKey (default: ):
validateCerts (default: True):
}
Add another 'otherRouter' element to array 'otherRouters'? [y/N]: n
]
Generated config:
{
"otherRouters": [
{
"url": "https://router-2:5001",
"apiKey": "1234",
"validateCerts": false
},
{
"url": "https://router-3:5001",
"apiKey": "",
"validateCerts": true
}
]
}
Merge and apply the config? [y/n]:
11 - Use In-Stream Sessions
In-Stream sessions is a routing mode where the router keeps control of the session for the full session lifetime instead of only routing the session to the preferred CDN (or cache node) once. Technically it works by letting the client return to the router for manifest and segments and redirect each segment to the preferred CDN. This enables changing CDN in the middle of a session.
Configure In-Stream Sessions
In-Stream routing for all incoming requests can be enabled by running
$ confcli services.routing.translationFunctions.session "return set_session_type('instream')"
services.routing.translationFunctions.session = "return set_session_type('instream')"
See Session Translation Function for more details on controlling session types.
The following example illustrate the request flow for in-stream session
$ curl -i http://test-acd-router/content/playlist.m3u8
HTTP/1.1 302 Found
Access-Control-Allow-Origin: *
Content-Length: 0
Location: http://test-acd-router/__s/test-acd-router-a4fd86-0000004f_WyIvY2RuL3BsYXlsaXN0Lm0zdTgiLDAsImRldmNkbjEiLCJkZXZjZG4xLnN0cmVhbXBpbG90LnR2Iiw4MCwiL2Nkbi9wbGF5bGlzdC5tM3U4IiwwLDE2ODAyNjQwOTNd_c1e3fc663a47156e0894b30eddf995bb/content/playlist.m3u8
X-Service-Identity:
$ curl -i http://test-acd-router/__s/test-acd-router-a4fd86-0000004f_WyIvY2RuL3BsYXlsaXN0Lm0zdTgiLDAsImRldmNkbjEiLCJkZXZjZG4xLnN0cmVhbXBpbG90LnR2Iiw4MCwiL2Nkbi9wbGF5bGlzdC5tM3U4IiwwLDE2ODAyNjQwOTNd_c1e3fc663a47156e0894b30eddf995bb/content/playlist.m3u8
HTTP/1.1 200 OK
Accept-Ranges: bytes
Access-Control-Allow-Headers: DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Content-Length,Content-Range
Connection: keep-alive
Content-Length: 306
Content-Type: application/vnd.apple.mpegurl
Date: Fri, 31 Mar 2023 10:18:42 GMT
ETag: "5d711f08-132"
Last-Modified: Thu, 05 Sep 2019 14:43:20 GMT
Server: nginx/1.14.0 (Ubuntu)
X-Service-Identity:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-STREAM-INF:BANDWIDTH=500000,RESOLUTION=320x180
abr_500k.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1000000,RESOLUTION=640x360
abr_1000k.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1700000,RESOLUTION=1280x720
abr_1700k.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=3300000,RESOLUTION=1280x720
abr_3300k.m3u8
$ curl -i http://test-acd-router/__s/test-acd-router-a4fd86-0000004f_WyIvY2RuL3BsYXlsaXN0Lm0zdTgiLDAsImRldmNkbjEiLCJkZXZjZG4xLnN0cmVhbXBpbG90LnR2Iiw4MCwiL2Nkbi9wbGF5bGlzdC5tM3U4IiwwLDE2ODAyNjQwOTNd_c1e3fc663a47156e0894b30eddf995bb/content/abr_500k.m3u8
HTTP/1.1 200 OK
Accept-Ranges: bytes
Access-Control-Allow-Headers: DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Content-Length,Content-Range
Connection: keep-alive
Content-Length: 276
Content-Type: application/vnd.apple.mpegurl
Date: Fri, 31 Mar 2023 12:02:04 GMT
ETag: "6426cbbc-114"
Last-Modified: Fri, 31 Mar 2023 12:02:04 GMT
Server: nginx/1.14.0 (Ubuntu)
X-Service-Identity:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:1
#EXT-X-MEDIA-SEQUENCE:112583846
#EXTINF:0.834444,
abr_500k112583846.ts
#EXTINF:0.834444,
abr_500k112583847.ts
#EXTINF:0.834444,
abr_500k112583848.ts
#EXTINF:0.834444,
abr_500k112583849.ts
#EXTINF:0.834444,
abr_500k112583850.ts
$ curl -i http://test-acd-router/__s/test-acd-router-a4fd86-0000004f_WyIvY2RuL3BsYXlsaXN0Lm0zdTgiLDAsImRldmNkbjEiLCJkZXZjZG4xLnN0cmVhbXBpbG90LnR2Iiw4MCwiL2Nkbi9wbGF5bGlzdC5tM3U4IiwwLDE2ODAyNjQwOTNd_c1e3fc663a47156e0894b30eddf995bb/content/abr_500k112583846.ts
HTTP/1.1 302 Found
Access-Control-Allow-Origin: *
Content-Length: 0
Location: http://testcdn.tv/abr_500k112583846.ts
X-Service-Identity:
A Note on Confcli
Begin with configuring routing, classification and session groups in confcli, for example based on content types.
# Create a classifier for live sessions
$ confcli services.routing.classifiers -w
Running wizard for resource 'classifiers'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
classifiers : [
classifier can be one of
1: anonymousIp
2: asnIds
3: contentUrlPath
4: contentUrlQueryParameters
5: geoip
6: hostName
7: ipranges
8: random
9: regexMatcher
10: stringMatcher
11: subnet
12: userAgent
Choose element index or name: contentUrlPath
Adding a 'contentUrlPath' element
classifier : {
name (default: ): live
type (default: contentUrlPath): ⏎
inverted (default: False): ⏎
patternType (default: stringMatch): ⏎
pattern (default: ): *live*
}
Add another 'classifier' element to array 'classifiers'? [y/N]: ⏎
]
Generated config:
{
"classifiers": [
{
"name": "live",
"type": "contentUrlPath",
"inverted": false,
"patternType": "stringMatch",
"pattern": "*live*"
}
]
}
Merge and apply the config? [y/n]: y
# Create a session group called "live" using the classifier
$ confcli services.routing.sessionGroups -w
Running wizard for resource 'sessionGroups'
Hint: Hitting return will set a value to its default.
Enter '?' to receive the help string
sessionGroups : [
sessionGroup : {
name (default: ): live
classifiers : [
classifier (default: ): live
Add another 'classifier' element to array 'classifiers'? [y/N]: ⏎
]
}
Add another 'sessionGroup' element to array 'sessionGroups'? [y/N]: ⏎
]
Generated config:
{
"sessionGroups": [
{
"name": "live",
"classifiers": [
"live"
]
}
]
}
Merge and apply the config? [y/n]: y
# Make all sessions belonging to the session group "live" In-Stream sessions
$ confcli services.routing.translationFunctions.session "return set_session_type_if_in_group('instream', 'live')"
services.routing.translationFunctions.session = "return set_session_type_if_in_group('instream', 'live')"
Monitoring
If Grafana is installed together with the ESB-3024 installer, the number of started In-Stream sessions as well as currently active In-Stream sessions can be seen in a Dashboard.
Notes on Performance
Be aware that In-Stream sessions puts additional load on the request router since all clients continuously comes back to the router to fetch new manifests and to get segment redirects. The necessary router capacity therefore scaled both with number of started sessions and the average session length.