You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Open-IM-Server/internal/msgtransfer/online_history_msg_handler.go

253 lines
9.7 KiB

2 years ago
package msgtransfer
import (
2 years ago
"context"
2 years ago
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/config"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/constant"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/controller"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/kafka"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/log"
2 years ago
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/mcontext"
2 years ago
pbMsg "github.com/OpenIMSDK/Open-IM-Server/pkg/proto/msg"
"github.com/OpenIMSDK/Open-IM-Server/pkg/utils"
"github.com/Shopify/sarama"
"github.com/golang/protobuf/proto"
3 years ago
"sync"
3 years ago
"time"
)
2 years ago
const ConsumerMsgs = 3
const AggregationMessages = 4
const MongoMessages = 5
const ChannelNum = 100
type MsgChannelValue struct {
3 years ago
aggregationID string //maybe userID or super groupID
2 years ago
ctx context.Context
ctxMsgList []*ContextMsg
3 years ago
lastSeq uint64
}
2 years ago
type TriggerChannelValue struct {
2 years ago
ctx context.Context
cMsgList []*sarama.ConsumerMessage
}
2 years ago
type Cmd2Value struct {
3 years ago
Cmd int
Value interface{}
}
2 years ago
type ContextMsg struct {
message *pbMsg.MsgDataToMQ
ctx context.Context
}
2 years ago
type OnlineHistoryRedisConsumerHandler struct {
2 years ago
historyConsumerGroup *kafka.MConsumerGroup
chArrays [ChannelNum]chan Cmd2Value
3 years ago
msgDistributionCh chan Cmd2Value
2 years ago
singleMsgSuccessCount uint64
singleMsgFailedCount uint64
singleMsgSuccessCountMutex sync.Mutex
singleMsgFailedCountMutex sync.Mutex
2 years ago
//producerToPush *kafka.Producer
//producerToModify *kafka.Producer
//producerToMongo *kafka.Producer
2 years ago
2 years ago
msgDatabase controller.MsgDatabase
}
2 years ago
func NewOnlineHistoryRedisConsumerHandler(database controller.MsgDatabase) *OnlineHistoryRedisConsumerHandler {
var och OnlineHistoryRedisConsumerHandler
och.msgDatabase = database
3 years ago
och.msgDistributionCh = make(chan Cmd2Value) //no buffer channel
go och.MessagesDistributionHandle()
for i := 0; i < ChannelNum; i++ {
3 years ago
och.chArrays[i] = make(chan Cmd2Value, 50)
go och.Run(i)
}
2 years ago
//och.producerToPush = kafka.NewKafkaProducer(config.Config.Kafka.Ms2pschat.Addr, config.Config.Kafka.Ms2pschat.Topic)
//och.producerToModify = kafka.NewKafkaProducer(config.Config.Kafka.MsgToModify.Addr, config.Config.Kafka.MsgToModify.Topic)
//och.producerToMongo = kafka.NewKafkaProducer(config.Config.Kafka.MsgToMongo.Addr, config.Config.Kafka.MsgToMongo.Topic)
2 years ago
och.historyConsumerGroup = kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{KafkaVersion: sarama.V2_0_0_0,
OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false}, []string{config.Config.Kafka.Ws2mschat.Topic},
config.Config.Kafka.Ws2mschat.Addr, config.Config.Kafka.ConsumerGroupID.MsgToRedis)
2 years ago
//statistics.NewStatistics(&och.singleMsgSuccessCount, config.Config.ModuleName.MsgTransferName, fmt.Sprintf("%d second singleMsgCount insert to mongo", constant.StatisticsTimeInterval), constant.StatisticsTimeInterval)
2 years ago
return &och
}
2 years ago
func (och *OnlineHistoryRedisConsumerHandler) Run(channelID int) {
for {
select {
case cmd := <-och.chArrays[channelID]:
switch cmd.Cmd {
3 years ago
case AggregationMessages:
msgChannelValue := cmd.Value.(MsgChannelValue)
2 years ago
ctxMsgList := msgChannelValue.ctxMsgList
ctx := msgChannelValue.ctx
storageMsgList := make([]*pbMsg.MsgDataToMQ, 0, 80)
2 years ago
storagePushMsgList := make([]*ContextMsg, 0, 80)
notStoragePushMsgList := make([]*ContextMsg, 0, 80)
log.ZDebug(ctx, "msg arrived channel", "channel id", channelID, "msgList length", len(ctxMsgList), "aggregationID", msgChannelValue.aggregationID)
2 years ago
var modifyMsgList []*pbMsg.MsgDataToMQ
2 years ago
//ctx := mcontext.NewCtx("redis consumer")
//mcontext.SetOperationID(ctx, triggerID)
for _, v := range ctxMsgList {
2 years ago
log.ZDebug(ctx, "msg come to storage center", "message", v.message.String())
2 years ago
isHistory := utils.GetSwitchFromOptions(v.message.MsgData.Options, constant.IsHistory)
isSenderSync := utils.GetSwitchFromOptions(v.message.MsgData.Options, constant.IsSenderSync)
if isHistory {
2 years ago
storageMsgList = append(storageMsgList, v.message)
storagePushMsgList = append(storagePushMsgList, v)
3 years ago
} else {
2 years ago
if !(!isSenderSync && msgChannelValue.aggregationID == v.message.MsgData.SendID) {
3 years ago
notStoragePushMsgList = append(notStoragePushMsgList, v)
3 years ago
}
}
2 years ago
if v.message.MsgData.ContentType == constant.ReactionMessageModifier || v.message.MsgData.ContentType == constant.ReactionMessageDeleter {
modifyMsgList = append(modifyMsgList, v.message)
2 years ago
}
}
if len(modifyMsgList) > 0 {
2 years ago
och.msgDatabase.MsgToModifyMQ(ctx, msgChannelValue.aggregationID, "", modifyMsgList)
}
2 years ago
log.ZDebug(ctx, "msg storage length", "storageMsgList", len(storageMsgList), "push length", len(notStoragePushMsgList))
if len(storageMsgList) > 0 {
2 years ago
lastSeq, err := och.msgDatabase.BatchInsertChat2Cache(ctx, msgChannelValue.aggregationID, storageMsgList)
if err != nil {
2 years ago
log.ZError(ctx, "batch data insert to redis err", err, "storageMsgList", storageMsgList)
2 years ago
och.singleMsgFailedCountMutex.Lock()
och.singleMsgFailedCount += uint64(len(storageMsgList))
och.singleMsgFailedCountMutex.Unlock()
} else {
2 years ago
och.singleMsgSuccessCountMutex.Lock()
och.singleMsgSuccessCount += uint64(len(storageMsgList))
och.singleMsgSuccessCountMutex.Unlock()
2 years ago
och.msgDatabase.MsgToMongoMQ(ctx, msgChannelValue.aggregationID, "", storageMsgList, lastSeq)
for _, v := range storagePushMsgList {
och.msgDatabase.MsgToPushMQ(v.ctx, msgChannelValue.aggregationID, v.message)
}
2 years ago
for _, v := range notStoragePushMsgList {
2 years ago
och.msgDatabase.MsgToPushMQ(v.ctx, msgChannelValue.aggregationID, v.message)
}
}
} else {
2 years ago
for _, v := range notStoragePushMsgList {
2 years ago
p, o, err := och.msgDatabase.MsgToPushMQ(v.ctx, msgChannelValue.aggregationID, v.message)
if err != nil {
log.ZError(v.ctx, "kafka send failed", err, "msg", v.message.String(), "pid", p, "offset", o)
}
}
}
}
}
}
}
func (och *OnlineHistoryRedisConsumerHandler) MessagesDistributionHandle() {
3 years ago
for {
2 years ago
aggregationMsgs := make(map[string][]*ContextMsg, ChannelNum)
3 years ago
select {
case cmd := <-och.msgDistributionCh:
switch cmd.Cmd {
case ConsumerMsgs:
triggerChannelValue := cmd.Value.(TriggerChannelValue)
2 years ago
ctx := triggerChannelValue.ctx
2 years ago
consumerMessages := triggerChannelValue.cMsgList
3 years ago
//Aggregation map[userid]message list
2 years ago
log.ZDebug(ctx, "batch messages come to distribution center", "length", len(consumerMessages))
3 years ago
for i := 0; i < len(consumerMessages); i++ {
2 years ago
ctxMsg := &ContextMsg{}
3 years ago
msgFromMQ := pbMsg.MsgDataToMQ{}
err := proto.Unmarshal(consumerMessages[i].Value, &msgFromMQ)
if err != nil {
2 years ago
log.ZError(ctx, "msg_transfer Unmarshal msg err", err, string(consumerMessages[i].Value))
3 years ago
return
}
2 years ago
ctxMsg.ctx = kafka.GetContextWithMQHeader(consumerMessages[i].Headers)
ctxMsg.message = &msgFromMQ
log.ZDebug(ctx, "single msg come to distribution center", msgFromMQ.String(), string(consumerMessages[i].Key))
3 years ago
if oldM, ok := aggregationMsgs[string(consumerMessages[i].Key)]; ok {
2 years ago
oldM = append(oldM, ctxMsg)
3 years ago
aggregationMsgs[string(consumerMessages[i].Key)] = oldM
3 years ago
} else {
2 years ago
m := make([]*ContextMsg, 0, 100)
m = append(m, ctxMsg)
3 years ago
aggregationMsgs[string(consumerMessages[i].Key)] = m
3 years ago
}
}
2 years ago
log.ZDebug(ctx, "generate map list users len", "length", len(aggregationMsgs))
3 years ago
for aggregationID, v := range aggregationMsgs {
3 years ago
if len(v) >= 0 {
2 years ago
hashCode := utils.GetHashCode(aggregationID)
3 years ago
channelID := hashCode % ChannelNum
2 years ago
log.ZDebug(ctx, "generate channelID", "hashCode", hashCode, "channelID", channelID, "aggregationID", aggregationID)
och.chArrays[channelID] <- Cmd2Value{Cmd: AggregationMessages, Value: MsgChannelValue{aggregationID: aggregationID, ctxMsgList: v, ctx: ctx}}
3 years ago
}
}
}
}
}
}
2 years ago
func (och *OnlineHistoryRedisConsumerHandler) Setup(_ sarama.ConsumerGroupSession) error { return nil }
func (och *OnlineHistoryRedisConsumerHandler) Cleanup(_ sarama.ConsumerGroupSession) error {
return nil
}
2 years ago
func (och *OnlineHistoryRedisConsumerHandler) ConsumeClaim(sess sarama.ConsumerGroupSession, claim sarama.ConsumerGroupClaim) error { // a instance in the consumer group
3 years ago
for {
if sess == nil {
log.NewWarn("", " sess == nil, waiting ")
time.Sleep(100 * time.Millisecond)
} else {
break
}
3 years ago
}
3 years ago
rwLock := new(sync.RWMutex)
2 years ago
log.ZDebug(context.Background(), "online new session msg come", "highWaterMarkOffset",
claim.HighWaterMarkOffset(), "topic", claim.Topic(), "partition", claim.Partition())
3 years ago
cMsg := make([]*sarama.ConsumerMessage, 0, 1000)
t := time.NewTicker(time.Duration(100) * time.Millisecond)
3 years ago
go func() {
3 years ago
for {
select {
case <-t.C:
if len(cMsg) > 0 {
rwLock.Lock()
ccMsg := make([]*sarama.ConsumerMessage, 0, 1000)
for _, v := range cMsg {
ccMsg = append(ccMsg, v)
}
cMsg = make([]*sarama.ConsumerMessage, 0, 1000)
rwLock.Unlock()
split := 1000
2 years ago
ctx := mcontext.WithTriggerIDContext(context.Background(), utils.OperationIDGenerator())
2 years ago
log.ZDebug(ctx, "timer trigger msg consumer start", "length", len(ccMsg))
3 years ago
for i := 0; i < len(ccMsg)/split; i++ {
//log.Debug()
och.msgDistributionCh <- Cmd2Value{Cmd: ConsumerMsgs, Value: TriggerChannelValue{
2 years ago
ctx: ctx, cMsgList: ccMsg[i*split : (i+1)*split]}}
3 years ago
}
if (len(ccMsg) % split) > 0 {
och.msgDistributionCh <- Cmd2Value{Cmd: ConsumerMsgs, Value: TriggerChannelValue{
2 years ago
ctx: ctx, cMsgList: ccMsg[split*(len(ccMsg)/split):]}}
3 years ago
}
2 years ago
log.ZDebug(ctx, "timer trigger msg consumer end", "length", len(ccMsg))
3 years ago
}
3 years ago
}
}
3 years ago
}()
3 years ago
for msg := range claim.Messages() {
rwLock.Lock()
2 years ago
if len(msg.Value) != 0 {
cMsg = append(cMsg, msg)
}
3 years ago
rwLock.Unlock()
sess.MarkMessage(msg, "")
}
return nil
}