MM-29980: Optimize profilesInChannels cache to fast path (#16116)

* MM-29980: Optimize profilesInChannels cache to fast path

We add one more message type to the fast path- profiles in channels. There
are 2 primary reasons for this:

- This is not really a new model type, but just a map of users. And users already use
the fast path. So we can get some more gains without really investing much more code.
- A more important reason is that with the upcoming striped mutex changes, we will get
a higher throughput at the cost of a bit more CPU utilization. The reason being that
since less amount of time will be spent in lock-contention, the CPU is free to do more
stuff. So this change is to counter that increase.

As usual, this gives much better performance than the original decoder.

Micro-benchmark results
```
name               old time/op    new time/op    delta
LRU/UserMap=new-8    16.6µs ± 3%     3.9µs ± 4%  -76.15%  (p=0.000 n=10+10)

name               old alloc/op   new alloc/op   delta
LRU/UserMap=new-8    4.78kB ± 0%    2.74kB ± 0%  -42.65%  (p=0.000 n=10+10)

name               old allocs/op  new allocs/op  delta
LRU/UserMap=new-8      38.0 ± 0%      30.0 ± 0%  -21.05%  (p=0.000 n=10+10)
```

https://mattermost.atlassian.net/browse/MM-29980

Here are some results from a load test. The comparison is done with a 2 node cluster; one running master
and one running with this patch so that it's easier to compare. The total users are 2000.

<See PR>

```release-note
NONE
```

* Fix gofmt

* Trigger CI
Этот коммит содержится в:
Agniva De Sarker
2020-11-04 10:08:10 +05:30
коммит произвёл GitHub
родитель 4758408699
Коммит 66731e2740
5 изменённых файлов: 213 добавлений и 1 удалений

5
services/cache/lru.go поставляемый
Просмотреть файл

@@ -221,6 +221,11 @@ func (l *LRU) get(key string, value interface{}) error {
_, err := s.UnmarshalMsg(e.value)
*v = &s
return err
case *map[string]*model.User:
var u model.UserMap
_, err := u.UnmarshalMsg(e.value)
*v = u
return err
}
// Slow path for other structs.

44
services/cache/lru_test.go поставляемый
Просмотреть файл

@@ -279,6 +279,17 @@ func TestLRUMarshalUnMarshal(t *testing.T) {
// This does not make an actual difference in terms of functionality.
u.Timezone = nil
require.Equal(t, user, u)
tt := make(map[string]*model.User)
tt["1"] = u
err = l.Set("mm", model.UserMap(tt))
require.Nil(t, err)
var out map[string]*model.User
err = l.Get("mm", &out)
require.Nil(t, err)
out["1"].Timezone = nil
require.Equal(t, tt, out)
}
func BenchmarkLRU(b *testing.B) {
@@ -434,6 +445,39 @@ func BenchmarkLRU(b *testing.B) {
}
})
uMap := map[string]*model.User{
"id1": {
Id: "id1",
CreateAt: 1111,
UpdateAt: 1112,
Username: "user1",
Password: "pass",
},
"id2": {
Id: "id2",
CreateAt: 1113,
UpdateAt: 1114,
Username: "user2",
Password: "pass2",
},
}
b.Run("UserMap=new", func(b *testing.B) {
for i := 0; i < b.N; i++ {
l2 := NewLRU(&LRUOptions{
Size: 1,
DefaultExpiry: 0,
InvalidateClusterEvent: "",
})
err := l2.Set("test", model.UserMap(uMap))
require.Nil(b, err)
var val map[string]*model.User
err = l2.Get("test", &val)
require.Nil(b, err)
}
})
post := &model.Post{
Id: "id",
CreateAt: 11111,