grpc-ile-mikroservis-mimarisi-golang-backend-entegrasyonu-2

gRPC ile Mikroservis Mimarisi: Golang Backend Entegrasyonu

İçindekiler

Modern mobil uygulamalar, güçlü ve ölçeklenebilir backend servisleri gerektirir. Chipode olarak, oyun verilerini yönetmek ve kullanıcı deneyimini optimize etmek için mikroservis mimarisi ve gRPC teknolojisini tercih ettik. Bu yazıda, neden bu teknolojileri seçtiğimizi ve nasıl implemente ettiğimizi detaylıca anlatacağız.

Mikroservis Mimarisi Nedir?

Mikroservis mimarisi, büyük ve karmaşık uygulamaları daha küçük, bağımsız servislere bölerek yönetmeyi sağlayan bir yaklaşımdır. Her bir servis:

– Kendi veritabanına sahip olabilir
– Bağımsız olarak deploy edilebilir
– Farklı programlama dilleriyle yazılabilir
– Yatay olarak ölçeklendirilebilir

1. Neden Mikroservis?

Sudoku uygulamamız için mikroservis mimarisini seçmemizin nedenleri:
1. Bağımsız ölçeklendirme (örn: skor servisi)
2. Teknoloji esnekliği
3. Hata izolasyonu
4. Kolay maintenance
5. Takım bağımsızlığı

gRPC Nedir ve Neden Kullanmalıyız?

gRPC, Google tarafından geliştirilen modern bir RPC (Remote Procedure Call) framework’üdür. Öne çıkan özellikleri:

– Protocol Buffers ile yüksek performans
– Bidirectional streaming
– Language agnostic yapı
– Auto-generated client/server code
– HTTP/2 tabanlı iletişim

REST vs gRPC Karşılaştırması

Protocol Buffers ile Servis Tanımlaması

				
					protobuf
syntax = "proto3";

package game;

service GameService {
  // Oyun kaydetme
  rpc SaveGame (SaveGameRequest) returns (SaveGameResponse);
  
  // Liderlik tablosu streaming
  rpc GetLeaderboard (LeaderboardRequest) returns (stream LeaderboardEntry);
  
  // Kullanıcı istatistikleri
  rpc GetUserStats (UserStatsRequest) returns (UserStatsResponse);
  
  // Gerçek zamanlı oyun durumu
  rpc StreamGameState (stream GameStateUpdate) returns (stream GameStateResponse);
}

message SaveGameRequest {
  string user_id = 1;
  int32 score = 2;
  int32 time_spent = 3;
  repeated int32 board_state = 4;
  GameDifficulty difficulty = 5;
}

enum GameDifficulty {
  EASY = 0;
  MEDIUM = 1;
  HARD = 2;
  EXPERT = 3;
}

// Diğer message tanımlamaları...

				
			

Golang ile gRPC Server Implementasyonu

1. Server Yapısı

				
					go
type gameServer struct {
    pb.UnimplementedGameServiceServer
    db        *sql.DB
    redis     *redis.Client
    validator *validation.Validator
}

func NewGameServer(db *sql.DB, redis *redis.Client) *gameServer {
    return &gameServer{
        db:        db,
        redis:     redis,
        validator: validation.New(),
    }
}


				
			

2. Oyun Kaydetme İşlemi

				
					go
func (s *gameServer) SaveGame(ctx context.Context, req *pb.SaveGameRequest) (*pb.SaveGameResponse, error) {
    // Validasyon
    if err := s.validator.Struct(req); err != nil {
        return nil, status.Errorf(codes.InvalidArgument, "invalid request: %v", err)
    }

    // Transaction başlat
    tx, err := s.db.BeginTx(ctx, nil)
    if err != nil {
        return nil, status.Errorf(codes.Internal, "transaction error: %v", err)
    }
    defer tx.Rollback()

    // Oyun verilerini kaydet
    result, err := tx.ExecContext(ctx,
        `INSERT INTO games (user_id, score, time_spent, board_state, difficulty)
         VALUES ($1, $2, $3, $4, $5)
         RETURNING id`,
        req.UserId, req.Score, req.TimeSpent, 
        pq.Array(req.BoardState), req.Difficulty,
    )
    
    if err != nil {
        return nil, status.Errorf(codes.Internal, "db error: %v", err)
    }

    // Liderlik tablosunu güncelle
    err = s.updateLeaderboard(ctx, req.UserId, req.Score, req.Difficulty)
    if err != nil {
        return nil, status.Errorf(codes.Internal, "leaderboard error: %v", err)
    }

    // Transaction'ı commit et
    if err := tx.Commit(); err != nil {
        return nil, status.Errorf(codes.Internal, "commit error: %v", err)
    }

    return &pb.SaveGameResponse{Success: true}, nil
}



				
			

3. Redis ile Liderlik Tablosu

				
					go
func (s *gameServer) updateLeaderboard(ctx context.Context, userId string, score int32, difficulty pb.GameDifficulty) error {
    // Zorluk seviyesine göre leaderboard key'i
    leaderboardKey := fmt.Sprintf("leaderboard:%s", difficulty.String())
    
    // Z-Set kullanarak skor güncelleme
    member := &redis.Z{
        Score:  float64(score),
        Member: userId,
    }
    
    pipe := s.redis.Pipeline()
    pipe.ZAdd(ctx, leaderboardKey, member)
    pipe.ZRemRangeByRank(ctx, leaderboardKey, 0, -101) // Sadece top 100
    
    _, err := pipe.Exec(ctx)
    return err
}

				
			

Flutter İle gRPC İstemci Entegrasyonu

1. gRPC Channel Konfigürasyonu

				
					dart
class GrpcClient {
  static GameServiceClient? _client;
  
  static Future<GameServiceClient> get client async {
    if (_client != null) return _client!;
    
    final channel = ClientChannel(
      'api.chipode.com',
      port: 50051,
      options: ChannelOptions(
        credentials: await _getCredentials(),
        idleTimeout: Duration(minutes: 1),
      ),
    );
    
    _client = GameServiceClient(channel);
    return _client!;
  }
  
  static Future<ChannelCredentials> _getCredentials() async {
    final trustStore = await rootBundle.load('assets/certificates/ca.pem');
    return ChannelCredentials.secure(
      certificates: trustStore.buffer.asUint8List(),
    );
  }
}


				
			

2. Oyun Repository İmplementasyonu

				
					dart
class GameRepository {
  final GameServiceClient _client;
  
  GameRepository(this._client);
  
  Future<bool> saveGame(GameState state) async {
    try {
      final request = SaveGameRequest()
        ..userId = getCurrentUserId()
        ..score = state.score
        ..timeSpent = state.timeSpent
        ..boardState.addAll(state.board.expand((row) => row))
        ..difficulty = _difficultyToProto(state.difficulty);
      
      final response = await _client.saveGame(request);
      return response.success;
    } catch (e) {
      log.error('Save game error', e);
      rethrow;
    }
  }
  
  Stream<LeaderboardEntry> getLeaderboard(GameDifficulty difficulty) {
    final request = LeaderboardRequest()
      ..difficulty = _difficultyToProto(difficulty);
    
    return _client.getLeaderboard(request);
  }
}



				
			

Error Handling ve Retry Mekanizması

1. Interceptor Kullanımı

				
					dart
class RetryInterceptor extends ClientInterceptor {
  @override
  ResponseFuture<R> interceptUnary<Q, R>(
    ClientMethod<Q, R> method,
    Q request,
    CallOptions options,
    ClientUnaryInvoker<Q, R> invoker,
  ) {
    return _retry(
      () => invoker(method, request, options),
      maxAttempts: 3,
    );
  }
  
  Future<R> _retry<R>(
    Future<R> Function() call, {
    int maxAttempts = 3,
  }) async {
    int attempts = 0;
    while (true) {
      try {
        attempts++;
        return await call();
      } catch (e) {
        if (attempts >= maxAttempts) rethrow;
        await Future.delayed(Duration(seconds: attempts));
      }
    }
  }
}



				
			

Monitoring ve Logging

1. Prometheus Metrics

				
					go
var (
    requestDuration = promauto.NewHistogramVec(
        prometheus.HistogramOpts{
            Name: "grpc_request_duration_seconds",
            Help: "gRPC request duration in seconds",
        },
        []string{"method", "status"},
    )
    
    activeConnections = promauto.NewGauge(
        prometheus.GaugeOpts{
            Name: "grpc_active_connections",
            Help: "Number of active gRPC connections",
        },
    )
)

				
			

2. Structured Logging

				
					go
func (s *gameServer) SaveGame(ctx context.Context, req *pb.SaveGameRequest) (*pb.SaveGameResponse, error) {
    logger := log.With().
        Str("user_id", req.UserId).
        Int32("score", req.Score).
        Str("difficulty", req.Difficulty.String()).
        Logger()
    
    logger.Info().Msg("saving game")
    // ... implementation
}

				
			

Sonuç

gRPC ve mikroservis mimarisi, Chipode’un backend altyapısının temelini oluşturuyor. Bu teknolojiler sayesinde:

1. Yüksek performanslı iletişim
2. Kolay ölçeklendirme
3. Tip güvenliği
4. Etkin monitoring
5. Güvenilir hata yönetimi

sağlayabiliyoruz. Gelecek yazılarımızda, bu altyapının diğer bileşenlerini ve optimizasyon tekniklerini de detaylıca inceleyeceğiz.

Kaynaklar

Twitter
LinkedIn
Diğer Yazılar
İletişim

Chipode Uygulamaları

loading...
Google Play Store
loading...
Apple Store