mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-20 09:16:40 +00:00
cached compaction
This commit is contained in:
@@ -1198,3 +1198,130 @@ func BenchmarkGetPeerNetworkMapCompact(b *testing.B) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetPeerNetworkMapCompactCached(t *testing.T) {
|
||||
account, err := createAccountFromFile()
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := context.Background()
|
||||
validatedPeersMap := make(map[string]struct{}, len(account.Peers))
|
||||
for _, peer := range account.Peers {
|
||||
validatedPeersMap[peer.ID] = struct{}{}
|
||||
}
|
||||
dnsDomain := account.Settings.DNSDomain
|
||||
customZone := account.GetPeersCustomZone(ctx, dnsDomain)
|
||||
|
||||
builder := types.NewNetworkMapBuilder(account, validatedPeersMap)
|
||||
|
||||
testingPeerID := "d3knp53l0ubs738a3n6g"
|
||||
|
||||
regularNm := builder.GetPeerNetworkMap(ctx, testingPeerID, customZone, validatedPeersMap, nil)
|
||||
compactCachedNm := builder.GetPeerNetworkMapCompactCached(ctx, testingPeerID, customZone, validatedPeersMap, nil)
|
||||
|
||||
compactedJSON, err := json.MarshalIndent(compactCachedNm, "", " ")
|
||||
require.NoError(t, err)
|
||||
|
||||
compactedBeforeUncompact := filepath.Join("testdata", "compact_cached_before_uncompact.json")
|
||||
err = os.MkdirAll(filepath.Dir(compactedBeforeUncompact), 0755)
|
||||
require.NoError(t, err)
|
||||
err = os.WriteFile(compactedBeforeUncompact, compactedJSON, 0644)
|
||||
require.NoError(t, err)
|
||||
|
||||
compactCachedNm.UncompactRoutes()
|
||||
compactCachedNm.UncompactFirewallRules()
|
||||
|
||||
normalizeAndSortNetworkMap(regularNm)
|
||||
normalizeAndSortNetworkMap(compactCachedNm)
|
||||
|
||||
regularJSON, err := json.MarshalIndent(regularNm, "", " ")
|
||||
require.NoError(t, err)
|
||||
|
||||
regularLn := len(regularJSON)
|
||||
compactLn := len(compactedJSON)
|
||||
|
||||
t.Logf("compacted less on %d percents", 100-int32((float32(compactLn)/float32(regularLn))*100))
|
||||
|
||||
regular := filepath.Join("testdata", "regular_nmap_cached.json")
|
||||
|
||||
err = os.MkdirAll(filepath.Dir(regular), 0755)
|
||||
require.NoError(t, err)
|
||||
err = os.WriteFile(regular, regularJSON, 0644)
|
||||
require.NoError(t, err)
|
||||
|
||||
uncompactedJSON, err := json.MarshalIndent(compactCachedNm, "", " ")
|
||||
require.NoError(t, err)
|
||||
|
||||
uncompacted := filepath.Join("testdata", "compacted_cached_nmap.json")
|
||||
|
||||
err = os.MkdirAll(filepath.Dir(regular), 0755)
|
||||
require.NoError(t, err)
|
||||
err = os.WriteFile(uncompacted, uncompactedJSON, 0644)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.JSONEq(t, string(regularJSON), string(uncompactedJSON), "regular and uncompacted network maps should be equal")
|
||||
}
|
||||
|
||||
func BenchmarkGetPeerNetworkMapCompactCached(b *testing.B) {
|
||||
account, err := createAccountFromFile()
|
||||
require.NoError(b, err)
|
||||
|
||||
ctx := context.Background()
|
||||
validatedPeersMap := make(map[string]struct{}, len(account.Peers))
|
||||
for _, peer := range account.Peers {
|
||||
validatedPeersMap[peer.ID] = struct{}{}
|
||||
}
|
||||
dnsDomain := account.Settings.DNSDomain
|
||||
customZone := account.GetPeersCustomZone(ctx, dnsDomain)
|
||||
|
||||
builder := types.NewNetworkMapBuilder(account, validatedPeersMap)
|
||||
|
||||
testingPeerID := "d3knp53l0ubs738a3n6g"
|
||||
|
||||
regularNm := builder.GetPeerNetworkMap(ctx, testingPeerID, customZone, validatedPeersMap, nil)
|
||||
compactNm := builder.GetPeerNetworkMapCompact(ctx, testingPeerID, customZone, validatedPeersMap, nil)
|
||||
compactCachedNm := builder.GetPeerNetworkMapCompactCached(ctx, testingPeerID, customZone, validatedPeersMap, nil)
|
||||
|
||||
regularJSON, err := json.Marshal(regularNm)
|
||||
require.NoError(b, err)
|
||||
|
||||
compactJSON, err := json.Marshal(compactNm)
|
||||
require.NoError(b, err)
|
||||
|
||||
compactCachedJSON, err := json.Marshal(compactCachedNm)
|
||||
require.NoError(b, err)
|
||||
|
||||
regularSize := len(regularJSON)
|
||||
compactSize := len(compactJSON)
|
||||
compactCachedSize := len(compactCachedJSON)
|
||||
savingsPercent := 100 - int(float64(compactCachedSize)/float64(regularSize)*100)
|
||||
|
||||
b.ReportMetric(float64(regularSize), "regular_bytes")
|
||||
b.ReportMetric(float64(compactCachedSize), "compact_cached_bytes")
|
||||
b.ReportMetric(float64(savingsPercent), "savings_%")
|
||||
|
||||
b.Logf("Regular network map: %d bytes", regularSize)
|
||||
b.Logf("Compact network map: %d bytes", compactSize)
|
||||
b.Logf("Compact cached network map: %d bytes", compactCachedSize)
|
||||
b.Logf("Data savings: %d%% (%d bytes saved)", savingsPercent, regularSize-compactCachedSize)
|
||||
|
||||
b.Run("Regular", func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = builder.GetPeerNetworkMap(ctx, testingPeerID, customZone, validatedPeersMap, nil)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("CompactOnDemand", func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = builder.GetPeerNetworkMapCompact(ctx, testingPeerID, customZone, validatedPeersMap, nil)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("CompactCached", func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = builder.GetPeerNetworkMapCompactCached(ctx, testingPeerID, customZone, validatedPeersMap, nil)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -42,9 +42,11 @@ type NetworkMapCache struct {
|
||||
groupToRoutes map[string][]*route.Route
|
||||
peerToRoutes map[string][]*route.Route
|
||||
|
||||
peerACLs map[string]*PeerACLView
|
||||
peerRoutes map[string]*PeerRoutesView
|
||||
peerDNS map[string]*nbdns.Config
|
||||
peerACLs map[string]*PeerACLView
|
||||
peerRoutes map[string]*PeerRoutesView
|
||||
peerDNS map[string]*nbdns.Config
|
||||
peerFirewallRulesCompact map[string][]*FirewallRule
|
||||
peerRoutesCompact map[string][]*route.Route
|
||||
|
||||
resourceRouters map[string]map[string]*routerTypes.NetworkRouter
|
||||
resourcePolicies map[string][]*Policy
|
||||
@@ -93,10 +95,12 @@ func NewNetworkMapBuilder(account *Account, validatedPeers map[string]struct{})
|
||||
groupToPolicies: make(map[string][]*Policy),
|
||||
groupToRoutes: make(map[string][]*route.Route),
|
||||
peerToRoutes: make(map[string][]*route.Route),
|
||||
peerACLs: make(map[string]*PeerACLView),
|
||||
peerRoutes: make(map[string]*PeerRoutesView),
|
||||
peerDNS: make(map[string]*nbdns.Config),
|
||||
globalResources: make(map[string]*resourceTypes.NetworkResource),
|
||||
peerACLs: make(map[string]*PeerACLView),
|
||||
peerRoutes: make(map[string]*PeerRoutesView),
|
||||
peerDNS: make(map[string]*nbdns.Config),
|
||||
peerFirewallRulesCompact: make(map[string][]*FirewallRule),
|
||||
peerRoutesCompact: make(map[string][]*route.Route),
|
||||
globalResources: make(map[string]*resourceTypes.NetworkResource),
|
||||
acgToRoutes: make(map[string]map[route.ID]*RouteOwnerInfo),
|
||||
noACGRoutes: make(map[route.ID]*RouteOwnerInfo),
|
||||
},
|
||||
@@ -253,6 +257,9 @@ func (b *NetworkMapBuilder) buildPeerACLView(account *Account, peerID string) {
|
||||
}
|
||||
|
||||
b.cache.peerACLs[peerID] = view
|
||||
|
||||
compactedRules := compactFirewallRules(firewallRules)
|
||||
b.cache.peerFirewallRulesCompact[peerID] = compactedRules
|
||||
}
|
||||
|
||||
func (b *NetworkMapBuilder) getPeerConnectionResources(account *Account, peer *nbpeer.Peer,
|
||||
@@ -659,6 +666,10 @@ func (b *NetworkMapBuilder) buildPeerRoutesView(account *Account, peerID string)
|
||||
}
|
||||
}
|
||||
|
||||
otherRouteIDs := slices.Concat(view.NetworkResourceIDs, view.InheritedRouteIDs)
|
||||
compactedRoutes := b.compactRoutesForPeer(peerID, view.OwnRouteIDs, otherRouteIDs)
|
||||
b.cache.peerRoutesCompact[peerID] = compactedRoutes
|
||||
|
||||
b.cache.peerRoutes[peerID] = view
|
||||
}
|
||||
|
||||
@@ -1045,6 +1056,45 @@ func (b *NetworkMapBuilder) assembleNetworkMap(
|
||||
}
|
||||
}
|
||||
|
||||
func (b *NetworkMapBuilder) GetPeerNetworkMapCompactCached(
|
||||
ctx context.Context, peerID string, peersCustomZone nbdns.CustomZone,
|
||||
validatedPeers map[string]struct{}, metrics *telemetry.AccountManagerMetrics,
|
||||
) *NetworkMap {
|
||||
start := time.Now()
|
||||
account := b.account.Load()
|
||||
|
||||
peer := account.GetPeer(peerID)
|
||||
if peer == nil {
|
||||
return &NetworkMap{Network: account.Network.Copy()}
|
||||
}
|
||||
|
||||
b.cache.mu.RLock()
|
||||
defer b.cache.mu.RUnlock()
|
||||
|
||||
aclView := b.cache.peerACLs[peerID]
|
||||
routesView := b.cache.peerRoutes[peerID]
|
||||
dnsConfig := b.cache.peerDNS[peerID]
|
||||
|
||||
if aclView == nil || routesView == nil || dnsConfig == nil {
|
||||
return &NetworkMap{Network: account.Network.Copy()}
|
||||
}
|
||||
|
||||
nm := b.assembleNetworkMapCompactCached(account, peer, aclView, routesView, dnsConfig, peersCustomZone, validatedPeers)
|
||||
|
||||
if metrics != nil {
|
||||
objectCount := int64(len(nm.Peers) + len(nm.OfflinePeers) + len(nm.Routes) + len(nm.FirewallRules) + len(nm.RoutesFirewallRules))
|
||||
metrics.CountNetworkMapObjects(objectCount)
|
||||
metrics.CountGetPeerNetworkMapDuration(time.Since(start))
|
||||
|
||||
if objectCount > 5000 {
|
||||
log.WithContext(ctx).Tracef("account: %s has a total resource count of %d objects from cache",
|
||||
account.Id, objectCount)
|
||||
}
|
||||
}
|
||||
|
||||
return nm
|
||||
}
|
||||
|
||||
func (b *NetworkMapBuilder) GetPeerNetworkMapCompact(
|
||||
ctx context.Context, peerID string, peersCustomZone nbdns.CustomZone,
|
||||
validatedPeers map[string]struct{}, metrics *telemetry.AccountManagerMetrics,
|
||||
@@ -1084,6 +1134,65 @@ func (b *NetworkMapBuilder) GetPeerNetworkMapCompact(
|
||||
return nm
|
||||
}
|
||||
|
||||
func (b *NetworkMapBuilder) assembleNetworkMapCompactCached(
|
||||
account *Account, peer *nbpeer.Peer, aclView *PeerACLView, routesView *PeerRoutesView,
|
||||
dnsConfig *nbdns.Config, customZone nbdns.CustomZone, validatedPeers map[string]struct{},
|
||||
) *NetworkMap {
|
||||
|
||||
var peersToConnect []*nbpeer.Peer
|
||||
var expiredPeers []*nbpeer.Peer
|
||||
|
||||
for _, peerID := range aclView.ConnectedPeerIDs {
|
||||
if _, ok := validatedPeers[peerID]; !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
peerItem := b.cache.globalPeers[peerID]
|
||||
if peerItem == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
expired, _ := peerItem.LoginExpired(account.Settings.PeerLoginExpiration)
|
||||
if account.Settings.PeerLoginExpirationEnabled && expired {
|
||||
expiredPeers = append(expiredPeers, peerItem)
|
||||
} else {
|
||||
peersToConnect = append(peersToConnect, peerItem)
|
||||
}
|
||||
}
|
||||
|
||||
routes := b.cache.peerRoutesCompact[peer.ID]
|
||||
|
||||
firewallRules := b.cache.peerFirewallRulesCompact[peer.ID]
|
||||
|
||||
var routesFirewallRules []*RouteFirewallRule
|
||||
for _, ruleID := range routesView.RouteFirewallRuleIDs {
|
||||
if rule := b.cache.globalRouteRules[ruleID]; rule != nil {
|
||||
routesFirewallRules = append(routesFirewallRules, rule)
|
||||
}
|
||||
}
|
||||
|
||||
finalDNSConfig := *dnsConfig
|
||||
if finalDNSConfig.ServiceEnable && customZone.Domain != "" {
|
||||
var zones []nbdns.CustomZone
|
||||
records := filterZoneRecordsForPeers(peer, customZone, peersToConnect, expiredPeers)
|
||||
zones = append(zones, nbdns.CustomZone{
|
||||
Domain: customZone.Domain,
|
||||
Records: records,
|
||||
})
|
||||
finalDNSConfig.CustomZones = zones
|
||||
}
|
||||
|
||||
return &NetworkMap{
|
||||
Peers: peersToConnect,
|
||||
Network: account.Network.Copy(),
|
||||
Routes: routes,
|
||||
DNSConfig: finalDNSConfig,
|
||||
OfflinePeers: expiredPeers,
|
||||
FirewallRules: firewallRules,
|
||||
RoutesFirewallRules: routesFirewallRules,
|
||||
}
|
||||
}
|
||||
|
||||
func (b *NetworkMapBuilder) assembleNetworkMapCompact(
|
||||
account *Account, peer *nbpeer.Peer, aclView *PeerACLView, routesView *PeerRoutesView,
|
||||
dnsConfig *nbdns.Config, customZone nbdns.CustomZone, validatedPeers map[string]struct{},
|
||||
@@ -1189,6 +1298,44 @@ func splitRouteAndPeer(r *route.Route) (string, string) {
|
||||
return parts[0], parts[1]
|
||||
}
|
||||
|
||||
func (b *NetworkMapBuilder) compactRoutesForPeer(peerID string, ownRouteIDs []route.ID, otherRouteIDs []route.ID) []*route.Route {
|
||||
var routes []*route.Route
|
||||
|
||||
for _, routeID := range ownRouteIDs {
|
||||
if rt := b.cache.globalRoutes[routeID]; rt != nil {
|
||||
routes = append(routes, rt)
|
||||
}
|
||||
}
|
||||
|
||||
type crt struct {
|
||||
route *route.Route
|
||||
peerIds []string
|
||||
}
|
||||
rtfilter := make(map[string]crt)
|
||||
|
||||
for _, routeID := range otherRouteIDs {
|
||||
if rt := b.cache.globalRoutes[routeID]; rt != nil {
|
||||
rid, pid := splitRouteAndPeer(rt)
|
||||
if pid == peerID || len(pid) == 0 {
|
||||
routes = append(routes, rt)
|
||||
continue
|
||||
}
|
||||
crt := rtfilter[rid]
|
||||
crt.peerIds = append(crt.peerIds, pid)
|
||||
crt.route = rt.CopyClean()
|
||||
rtfilter[rid] = crt
|
||||
}
|
||||
}
|
||||
|
||||
for rid, crt := range rtfilter {
|
||||
crt.route.ApplicablePeerIDs = crt.peerIds
|
||||
crt.route.ID = route.ID(rid)
|
||||
routes = append(routes, crt.route)
|
||||
}
|
||||
|
||||
return routes
|
||||
}
|
||||
|
||||
func compactFirewallRules(expandedRules []*FirewallRule) []*FirewallRule {
|
||||
type peerKey struct {
|
||||
PolicyID string
|
||||
|
||||
Reference in New Issue
Block a user