Coding changes the world.

ranklist

游戏排行榜算法设计实现

需求背景:
查看前top N的排名用户
查看自己的排名
用户积分变更后,排名及时更新
方案一:MySQL来实现
利用MySQL来实现,存放一张用户积分表user_score
游戏排行榜算法设计实现比较
取前top N,自己的排名都可以通过简单的sql语句搞定。
算法简单,利用sql的功能,不需要其他复杂逻辑,对于数据量比较少、性能要求不高,可以使用。但是对于海量数据,性能是无法接受的。
方案二:skiplist的实现
用这个实现起来比较简单;用hashmap来存储具体的对象;用skiplist用来排序。也可以简单的用一个map和set来实现。Map内面存具体对象,set用来排序。
关于skip list这里简单介绍下:skip list是链表的一种特殊形式,对链表的一种优化;保证INSERT和REMOVE操作是O(logn),而通用链表的复杂度为O(n);
优点:实现较简单,效率基本上O(log(N))
缺点:当达到亿级别时的数据时,性能会急剧下降
方案三:基于redis的 sort set的实现
redis的zset用来做排行榜的、好友列表, 去重, 历史记录等业务需求。接口使用非常简单。接口非常丰富,基本上需要的实现都能满足,说明如下:
ZAdd/ZRem是O(log(N)),ZRangeByScore/ZRemRangeByScore是O(log(N)+M),N是Set大小,M是结果/操作元素的个数。
ZSET的实现用到了两个数据结构:hash table 和 skip list(跳跃表),其中hash table是具体使用redis中的dict来实现的,主要是为了保证查询效率为O(1) ,而skip list(跳跃表)主要是保证元素有序并能够保证INSERT和REMOVE操作是O(logn)的复杂度。
优点:基于redis开发,速度快;使用redis相关特性
缺点:当达到亿级别时的数据时,性能会急剧下降

Continue reading

mysql

mysql master-slave集群

MySQL的集群主要有两个成熟方案:分布式集群和主从集群

mysql 主从复制模式主要为master负责接收用户的请求,DDL,DML,DCL等操作,slave主要负责同步master的二进制日志,以便备份数据。在一此数据库访问量比较大的场景,master-slave模式还可以结合mysql-proxy做读写分离,mysql-proxy负责将用户的写请求转发到master,将用户的读请求转发到slave,以分担数据库的压力。甚至更健壮的系统,一个master对应多个slave,做成高可用HA集群,当master宕机的时候,多个slave会协商出一个slave重新成为master,以达到服务的持续性。

在mysql master-slave架构中,slave会启动两个主要的线程,一个是io thread,另一个是sql thread。大家都知道,mysql的replication主要是通过slave同步master中的二进制日志,然后将二进制日志先储存在slave中的中继日志中, Continue reading

libevent

libevent网络库框架

libevent概述

Libevent 是一个用C语言编写的、轻量级的开源高性能事件通知库,主要有以下几个亮点:事件驱动( event-driven),高性能;轻量级,专注于网络,不如 ACE 那么臃肿庞大;源代码相当精炼、易读;跨平台,支持 Windows、 Linux、 *BSD 和 Mac Os;支持多种 I/O 多路复用技术, epoll、 poll、 dev/poll、 select 和 kqueue 等;支持 I/O,定时器和信号等事件;注册事件优先级。

一个异步事件框架
libevent本身是一个Reactor,是同步的。但libevent的bufferevent是用Reactor实现了一个Proactor,所以libevent又是异步的

Continue reading

epoll

epoll相较于select的区别和优点

epoll把原来select调用分成了3个部分:

1)调用epoll_create()建立一个epoll对象(在epoll文件系统中为这个句柄对象分配资源)

2)调用epoll_ctl向epoll对象中添加这100万个连接的套接字

3)调用epoll_wait收集发生的事件的连接

对于第一个缺点,fd数目有限:
epoll没有这个限制,它所支持的FD上限是最大可以打开文件的数目,这个数字一般远大于2048,举个例子,在1GB内存的机器上大约是10万左右,具体数目可以cat /proc/sys/fs/file-max查看,一般来说这个数目和系统内存关系很大。

Continue reading

redis

redis

1.认识Redis

工作模型:单线程架构和IO多路复用来实现高性能的内存数据库服务
原因:a)单线程简化数据结构和算法的实现;b)避免线程切换和线程竞争的开销
应用场景:缓存/排行系统/统计器应用/社交网络/消息队列/热数据

2.数据类型
2-1.字符串类型
命令相关:使用mget可以减少网络次数,提高开发效率(字符串不能超过512MB)
内部编码:根据当前值的类型和长度决定使用哪种编码

int:8bytes长整型
embstr:小于等于39bytes的字符串
raw:大于39bytes的字符串
底层数据结构:数组
应用场景:缓存功能/计数/共享Seesion/限速
2-2.哈希类型
命令相关:键值本身又是一个键值对结构; set key field
内部编码:

Continue reading

smart pointer

C++11标准下的智能指针

智能指针:

在某种程度上,对垃圾回收技术提供了支持,使得程序能够在内存管理方面更加安全。

那么智能指针有哪几种呢?

1.uniqued_ptr:不允许许多指针共享资源,所指向的空间只能由它所指向,它中存放的地址不允许复制到别的指针上,但可以用标准库中move()把它所指向的对象(地址)转移给别的指针,最后Uniqued_ptr就失效了;

Continue reading

c++11

C++11新特性-初始化列表initializer_list

一、插入排序
一、什么是列表初始化
使用一个花括号来初始化变量,表现形式如下:

// 第一种
std::vector a{1,2,3,4,5};

// 第二种
std::vector a = {1,2,3,4,5};

这里用到了一个新的类型,即 initializer_list,包含在标准库头文件中。

二、优点
1、在 C++11 以前,如果要初始化一个 vector,需要这样做

std::vector<int> a;
a.push_back(1);
a.push_back(2);
a.push_back(3);
a.push_back(4);
a.push_back(5);

很明显,使用列表初始化使得代码量少了很多,也更加的简洁优雅。

Continue reading

entities

entities

Entities
An entityx::Entity is a convenience class wrapping an opaque uint64_t value allocated by the entityx::EntityManager. Each entity has a set of components associated with it that can be added, queried or retrieved directly.

Continue reading

GameServer

游戏服务器入门

一 专业基础
1.1 网络
1.1.1 理解TCP/IP协议
网络传输模型
滑动窗口技术
建立连接的三次握手与断开连接的四次握手
连接建立与断开过程中的各种状态
TCP/IP协议的传输效率
思考
1)请解释DOS攻击与DRDOS攻击的基本原理
2)一个100Byte数据包,精简到50Byte, 其传输效率提高了50%
3)TIMEWAIT状态怎么解释?
1.1.2 掌握常用的网络通信模型
Select
Epoll,边缘触发与平台出发点区别与应用
Select与Epoll的区别及应用
1.2 存储
计算机系统存储体系 Continue reading

Socket

Socket 选项

socket 选项
1、SO_REUSEADDR

一般来说,一个端口释放后会等待两分钟之后才能再被使用,SO_REUSEADDR 是让端口释放后立即就可以被再次使用。

SO_REUSEADDR 用于对 TCP 套接字处于 TIME_WAIT 状态下的 socket,才可以重复绑定使用。

server 程序总是应该在调用 bind() 之前设置 SO_REUSEADDR 套接字选项 TCP,先调用 close() 的一方会进入 TIME_WAIT 状态。

SO_REUSEADDR 提供如下四个功能:

允许启动一个监听服务器并捆绑其众所周知端口,即使以前建立的将此端口用做他们的本地端口的连接仍存在。这通常是重启监听服务器时出现,若不设置此选项,则 bind 时将出错。 Continue reading

GatewayServer

游戏网关服务器GatewayServer的作用

GatewayServer
  也称之为连接服务器,网络游戏的客户端一般是连接到这里,然后再由该连接服务器根据不同的需要,把游戏消息转发给其它相应的服务器(逻辑和地图服务器)。也因为它是客户端直接连接的对象,它同时也承担了验证客户身份的工作。

游戏网关服务器GatewayServer的作用:
游戏网关服务器可以作为客户端与 game server 的隔离作用
消息解析

Continue reading

sort

各个排序算法原理

一、插入排序
  每次将一个待排序的数据,跟前面已经有序的序列的数字一一比较找到自己合适的位置,插入到序列中,直到全部数据插入完成。

二、希尔排序
先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。由于希尔排序是对相隔若干距离的数据进行直接插入排序,因此可以形象的称希尔排序为“跳着插”

Continue reading

data structure

堆和栈的区别

堆和栈的区别
从管理方式上:栈是由编译器自动管理,无需我们手动控制;
对于堆,开辟和释放工作由程序员控制,所以有内存泄漏等情况的发生。
从申请大小上:栈是有高地址向低地址扩展的,是一块连续的内存区域,所以栈的栈顶地址或者大小 是一开始就分配好的。在使用过程中,比如递归调用层数过多,那么就有可能造成栈溢出,所以栈能获得的空间比较少;
堆是向高地址扩展的,是链表组织的方式,所以有可能是不连续的,他的大小只受限于有效的虚拟内存大小,所以堆能开辟的空间较大。
从碎片问题上:栈是没有碎片的情况,因为他有严格的出栈入栈,不会存在一个内存块从栈的中间位置弹出;
堆有碎片的情况,频繁的调用new/delete分配释放内存,必然会造成内存碎片。

Continue reading

class

实现一个不能被继承的类

1、方法一 将其构造函数声明为私有的

最直观的解决方法就是将其构造函数声明为私有的,这样就可以阻止子类构造对象了。但是这样的话,就无法构造本身的对象了,就无法利用了。
既然这样,我们又可以想定义一个静态方法来构造类和释放类。

#include
using namespace std;
class A
{
    public:
       static A* Construct(int n)
       {
           A *pa = new A;
           pa->num = n;
           cout<<"num is:"<num<num<

2、方法二 利用友元不能被继承的特性,可以实现这样的类。

Continue reading