今天我们还是聊CAS,聊聊CAS在“分布式ID生成方案”中的应用。所谓“分布式ID生成方案”,是指在分布式环境下生成全球唯一ID的方法。可以使用DB自增键(autoincid)生成全局唯一ID,插入记录,生成ID:这种方案利用了数据库的单点特性,优点是:无需要额外写代码全局唯一绝对增量增量ID步长决定了它的缺点:需要做数据库HA,保证生成ID的高可用数据库中有很多记录。生成ID的性能取决于数据库插入性能。服务,使用批量生成来降低数据库的写入压力,提高整体性能。添加服务后,DB中只需要保存当前的max-id即可。在服务启动和初始化过程中,首先拉取当前的max-id:selectmax_idfromT;然后分批获取一批ID,放入id-servcie内存中,将max-id写回数据库:updateTsetmax_id=200;这样id-service就拿到了这批ID[100,200],upstream在获取ID的时候,不是每次都插入数据库,分配完100个ID之后,修改max-id的值,使得分配ID的整体性能提高了100倍。这种方案的优点:数据库中只保存一条记录,性能大大提高。缺点是:如果重启id-service,可能有一部分内存已经申请了id还没有分配,导致id为空。当然,这不是一个严重的问题,服务没有HA,就无法保证高可用性。优化方案为:服务冗余,集群保证高可用。冗余服务后,多个服务在启动时批量申请ID可能会因为并发导致数据不一致:selectmax_idfromT;如上图所示,两个id-service在启动过程中同时拿到了100的max-id。两个id-service同时写回数据库的max-id:updateTsetmax_id=200;max-id回写成功后,两个id-service认为自己拿到了那批ID[100,200],导致集群失败。生成了重复的ID。问题原因是并发回写的时候没有比较max-id的初值:id-service1回写max-id=200成功如果max-id必须等于100id-service2回写max-id=200成功的条件是max-id也必须等于100,回写id-service1时,max-id为100,应该回写成功。回写id-service2的时候,max-id已经改成了200,应该回写不成功。只要实现CAS乐观锁,回写时比较max-id的初始条件,就可以避免数据不一致。回写SQL升级自:updateTsetmax_id=200;to:updateTsetmax_id=200wheremax_id=100;这样id-service2回写的时候会失败:失败后id-service2会再次查询max-id:此时max-id已经变为200,所以id-service2已经获取到[200,300]BatchID,回写max-id=300:updatesetmax_id=300wheremax_id=200;回写成功。该方案的优点是:可以通过横向扩展实现分布式ID生成服务的最佳性能。CAS的使用很简单,保证不会产生重复的ID。缺点是:由于有多个服务,生成的ID不是绝对增加,而是趋势增加【本文为专栏作者“58神剑”原创稿件,转载请联系原作者】点此阅读作者更多好文
