/// <summary> /// member_no로 부터 샤드 아이디 얻기 /// </summary> /// <param name="user_no"></param> /// <returns></returns> public GameContext(Session session) { // 수평샤딩 // 범용적인 구성 방법 // shard key는 일반적으로 유저를 기준으로 하는 accountId(memberId) 를 사용 // 대상 테이블의 PK는 shard key + @ 로 사용을 권장(ex: accountId + itemId) // 분산은 range, modulo 를 일반적으로 사용하지만 // 최근 가입한 유저가 더 많은 트래픽을 유발할 수 있는 게임의 특성상 modulo연산 사용을 권장 // 론칭 후 운영 중인 상태에서는 데이터를 재배치 하기 힘드므로 // 성능테스트 일정 이전엔 2개의 shard만 구성하고 성능테스트 결과에 따라 shard 갯수 최종 픽스 //return user_no % 2; shard_id_ = Shard.GetShardId(session.member_no); }
public LogContext(Session session) { shard_id_ = Shard.GetShardId(session.member_no); }
public LogContext(long member_no) { shard_id_ = Shard.GetShardId(member_no); }
/// <summary> /// /// </summary> /// <param name="entity_no"></param> /// <param name="is_read_db"></param> /// <returns></returns> public async Task <T> GetEntity(long member_no, long entity_no, bool is_read_db, bool is_dirty_update, bool is_dirty) { T entity = null; var ret = await Cache.Instance.GetDatabase().StringGetAsync($"{entity_name}:{entity_no}:{Shard.GetShardId(member_no)}"); if (ret.HasValue == true) { entity = JsonConvert.DeserializeObject <T>(ret); } else if (is_read_db) { entity = await query.Get(member_no, entity_no); await SetEntity(entity, member_no); } if (is_dirty_update && entity != null) { entity.SetUpdater(async() => { await UpdateEntity(member_no, entity); }); } if (entity != null) { entity.SetDirty(is_dirty); } return(entity); }
public async Task <bool> RemoveEntities(long member_no, long user_no) { var db = Cache.Instance.GetDatabase(); var ret = await Cache.Instance.GetDatabase().StringGetAsync($"{entities_name}:{user_no}"); if (ret.HasValue == true) { var entity_dic = JsonConvert.DeserializeObject <Dictionary <int, long> >(ret); foreach (var entity in entity_dic) { await Cache.Instance.GetDatabase().KeyDeleteAsync($"{entity_name}:{entity.Value}:{Shard.GetShardId(member_no)}"); } } await Cache.Instance.GetDatabase().KeyDeleteAsync($"{entities_name}:{user_no}"); return(true); }
public async Task <bool> RemoveEntity(long member_no, T entity) { var ret = await Cache.Instance.GetDatabase().StringGetAsync($"{entities_name}:{entity.GetUserNo()}"); if (ret.HasValue == true) { var entity_dic = JsonConvert.DeserializeObject <Dictionary <int, long> >(ret); if (entity_dic.Remove(entity.GetKey()) == false) { return(false); } // 케릭터 목록 캐싱 await Cache.Instance.GetDatabase().StringSetAsync($"{entities_name}:{entity.GetUserNo()}", JsonConvert.SerializeObject(entity_dic), session_expire); } await Cache.Instance.GetDatabase().KeyDeleteAsync($"{entity_name}:{entity.GetValue()}:{Shard.GetShardId(member_no)}"); return(true); }
async Task CacheEntity(long member_no, T entity, bool is_change_entity_list) { if (is_change_entity_list) { var ret = await Cache.Instance.GetDatabase().StringGetAsync($"{entities_name}:{entity.GetUserNo()}"); if (ret.HasValue == true) { var entity_dic = JsonConvert.DeserializeObject <Dictionary <int, long> >(ret); entity_dic[entity.GetKey()] = entity.GetValue(); // 케릭터 목록 캐싱 await Cache.Instance.GetDatabase().StringSetAsync($"{entities_name}:{entity.GetUserNo()}", JsonConvert.SerializeObject(entity_dic), session_expire); } } // 케릭터 캐싱 await Cache.Instance.GetDatabase().StringSetAsync($"{entity_name}:{entity.GetValue()}:{Shard.GetShardId(member_no)}", JsonConvert.SerializeObject(entity), session_expire); }
public async Task <bool> SetEntity(T entity, long member_no) { try { return(await Cache.Instance.GetDatabase().StringSetAsync($"{entity_name}:{entity.GetValue()}:{Shard.GetShardId(member_no)}", JsonConvert.SerializeObject(entity), session_expire)); } catch (Exception ex) { Log.Error(ex.Message); return(false); } }