第260集使用MySQL,实现一个高性能,分布式ID生成器架构实战:分布式ID设计、MySQL优化与企业级ID生成方案 | 字数总计: 8.2k | 阅读时长: 41分钟 | 阅读量:
前言 分布式ID生成器是分布式系统中的核心组件之一,需要保证全局唯一性、高性能、高可用等特性。MySQL作为关系型数据库,虽然在高并发场景下存在性能瓶颈,但通过合理的架构设计和优化策略,仍然可以实现高性能的分布式ID生成器。本文从分布式ID设计到MySQL优化,从并发控制到企业级方案,系统梳理基于MySQL的分布式ID生成器完整解决方案。
一、分布式ID生成器架构设计 1.1 分布式ID生成器架构
1.2 分布式ID设计原则
二、MySQL分布式ID生成器实现 2.1 基于数据库自增ID方案 2.1.1 基础实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 CREATE TABLE id_generator ( id BIGINT AUTO_INCREMENT PRIMARY KEY, business_type VARCHAR (50 ) NOT NULL COMMENT '业务类型' , step_size INT NOT NULL DEFAULT 1000 COMMENT '步长' , current_max_id BIGINT NOT NULL DEFAULT 0 COMMENT '当前最大ID' , version INT NOT NULL DEFAULT 0 COMMENT '版本号' , created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间' , updated_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间' , UNIQUE KEY uk_business_type (business_type) ) ENGINE= InnoDB DEFAULT CHARSET= utf8mb4 COMMENT= 'ID生成器表' ; INSERT INTO id_generator (business_type, step_size, current_max_id) VALUES ('user' , 1000 , 0 ), ('order' , 1000 , 0 ), ('product' , 1000 , 0 );
2.1.2 Java实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 @Service public class MySQLDistributedIdGenerator { @Autowired private IdGeneratorMapper idGeneratorMapper; @Autowired private RedisTemplate<String, Object> redisTemplate; private final Map<String, IdRange> localCache = new ConcurrentHashMap <>(); private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1 ); public Long generateId (String businessType) { IdRange idRange = localCache.get(businessType); if (idRange != null && idRange.hasNext()) { return idRange.next(); } idRange = getFromRedisCache(businessType); if (idRange != null && idRange.hasNext()) { localCache.put(businessType, idRange); return idRange.next(); } idRange = getNewIdRange(businessType); localCache.put(businessType, idRange); updateRedisCache(businessType, idRange); return idRange.next(); } public List<Long> generateIds (String businessType, int count) { List<Long> ids = new ArrayList <>(); for (int i = 0 ; i < count; i++) { ids.add(generateId(businessType)); } return ids; } private IdRange getNewIdRange (String businessType) { return idGeneratorMapper.getNewIdRange(businessType); } private IdRange getFromRedisCache (String businessType) { String cacheKey = "id_range:" + businessType; return (IdRange) redisTemplate.opsForValue().get(cacheKey); } private void updateRedisCache (String businessType, IdRange idRange) { CompletableFuture.runAsync(() -> { String cacheKey = "id_range:" + businessType; redisTemplate.opsForValue().set(cacheKey, idRange, Duration.ofMinutes(30 )); }); } public static class IdRange { private long start; private long end; private long current; public IdRange (long start, long end) { this .start = start; this .end = end; this .current = start; } public boolean hasNext () { return current <= end; } public long next () { if (!hasNext()) { throw new IllegalStateException ("ID段已用完" ); } return current++; } public long getStart () { return start; } public void setStart (long start) { this .start = start; } public long getEnd () { return end; } public void setEnd (long end) { this .end = end; } public long getCurrent () { return current; } public void setCurrent (long current) { this .current = current; } } }
2.1.3 MyBatis Mapper实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 @Mapper public interface IdGeneratorMapper { @Select("SELECT business_type, step_size, current_max_id FROM id_generator WHERE business_type = #{businessType}") IdGeneratorInfo getById (@Param("businessType") String businessType) ; @Update("UPDATE id_generator SET current_max_id = current_max_id + step_size, version = version + 1, updated_time = NOW() WHERE business_type = #{businessType} AND version = #{version}") int updateIdRange (@Param("businessType") String businessType, @Param("version") int version) ; @Select("SELECT business_type, step_size, current_max_id FROM id_generator WHERE business_type = #{businessType} FOR UPDATE") IdGeneratorInfo getByIdForUpdate (@Param("businessType") String businessType) ; @Update("UPDATE id_generator SET current_max_id = current_max_id + step_size, updated_time = NOW() WHERE business_type = #{businessType}") int updateIdRangeForUpdate (@Param("businessType") String businessType) ; default MySQLDistributedIdGenerator.IdRange getNewIdRange (String businessType) { int maxRetries = 3 ; for (int i = 0 ; i < maxRetries; i++) { IdGeneratorInfo info = getById(businessType); if (info == null ) { throw new IllegalArgumentException ("业务类型不存在: " + businessType); } long start = info.getCurrentMaxId() + 1 ; long end = info.getCurrentMaxId() + info.getStepSize(); int updated = updateIdRange(businessType, info.getVersion()); if (updated > 0 ) { return new MySQLDistributedIdGenerator .IdRange(start, end); } try { Thread.sleep(10 ); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException ("线程被中断" , e); } } throw new RuntimeException ("获取ID段失败,重试次数已用完" ); } }
2.2 基于数据库序列方案 2.2.1 序列表设计 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 CREATE TABLE sequence_generator ( id BIGINT AUTO_INCREMENT PRIMARY KEY, sequence_name VARCHAR (100 ) NOT NULL COMMENT '序列名称' , current_value BIGINT NOT NULL DEFAULT 0 COMMENT '当前值' , increment_by INT NOT NULL DEFAULT 1 COMMENT '步长' , max_value BIGINT NOT NULL DEFAULT 9223372036854775807 COMMENT '最大值' , min_value BIGINT NOT NULL DEFAULT 1 COMMENT '最小值' , cycle BOOLEAN NOT NULL DEFAULT FALSE COMMENT '是否循环' , cache_size INT NOT NULL DEFAULT 1000 COMMENT '缓存大小' , version INT NOT NULL DEFAULT 0 COMMENT '版本号' , created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间' , updated_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间' , UNIQUE KEY uk_sequence_name (sequence_name) ) ENGINE= InnoDB DEFAULT CHARSET= utf8mb4 COMMENT= '序列生成器表' ; INSERT INTO sequence_generator (sequence_name, current_value, increment_by, cache_size) VALUES ('user_id_seq' , 0 , 1 , 1000 ), ('order_id_seq' , 0 , 1 , 1000 ), ('product_id_seq' , 0 , 1 , 1000 );
2.2.2 序列生成器实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 @Service public class MySQLSequenceGenerator { @Autowired private SequenceMapper sequenceMapper; @Autowired private RedisTemplate<String, Object> redisTemplate; private final Map<String, SequenceRange> localCache = new ConcurrentHashMap <>(); public Long nextValue (String sequenceName) { SequenceRange range = localCache.get(sequenceName); if (range != null && range.hasNext()) { return range.next(); } range = getFromRedisCache(sequenceName); if (range != null && range.hasNext()) { localCache.put(sequenceName, range); return range.next(); } range = getNewSequenceRange(sequenceName); localCache.put(sequenceName, range); updateRedisCache(sequenceName, range); return range.next(); } public List<Long> nextValues (String sequenceName, int count) { List<Long> values = new ArrayList <>(); for (int i = 0 ; i < count; i++) { values.add(nextValue(sequenceName)); } return values; } private SequenceRange getNewSequenceRange (String sequenceName) { return sequenceMapper.getNewSequenceRange(sequenceName); } private SequenceRange getFromRedisCache (String sequenceName) { String cacheKey = "sequence_range:" + sequenceName; return (SequenceRange) redisTemplate.opsForValue().get(cacheKey); } private void updateRedisCache (String sequenceName, SequenceRange range) { CompletableFuture.runAsync(() -> { String cacheKey = "sequence_range:" + sequenceName; redisTemplate.opsForValue().set(cacheKey, range, Duration.ofMinutes(30 )); }); } public static class SequenceRange { private long start; private long end; private long current; private int incrementBy; public SequenceRange (long start, long end, int incrementBy) { this .start = start; this .end = end; this .current = start; this .incrementBy = incrementBy; } public boolean hasNext () { return current <= end; } public long next () { if (!hasNext()) { throw new IllegalStateException ("序列段已用完" ); } long value = current; current += incrementBy; return value; } public long getStart () { return start; } public void setStart (long start) { this .start = start; } public long getEnd () { return end; } public void setEnd (long end) { this .end = end; } public long getCurrent () { return current; } public void setCurrent (long current) { this .current = current; } public int getIncrementBy () { return incrementBy; } public void setIncrementBy (int incrementBy) { this .incrementBy = incrementBy; } } }
2.3 基于数据库表方案 2.3.1 分段表设计 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 CREATE TABLE id_segment ( id BIGINT AUTO_INCREMENT PRIMARY KEY, business_type VARCHAR (50 ) NOT NULL COMMENT '业务类型' , segment_no INT NOT NULL COMMENT '分段号' , start_id BIGINT NOT NULL COMMENT '起始ID' , end_id BIGINT NOT NULL COMMENT '结束ID' , current_id BIGINT NOT NULL COMMENT '当前ID' , status TINYINT NOT NULL DEFAULT 0 COMMENT '状态:0-未使用,1-使用中,2-已用完' , created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间' , updated_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间' , UNIQUE KEY uk_business_segment (business_type, segment_no) ) ENGINE= InnoDB DEFAULT CHARSET= utf8mb4 COMMENT= 'ID分段表' ; CREATE INDEX idx_business_status ON id_segment (business_type, status);CREATE INDEX idx_current_id ON id_segment (current_id);
2.3.2 分段生成器实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 @Service public class MySQLSegmentIdGenerator { @Autowired private IdSegmentMapper idSegmentMapper; @Autowired private RedisTemplate<String, Object> redisTemplate; private final Map<String, SegmentInfo> localCache = new ConcurrentHashMap <>(); public Long generateId (String businessType) { SegmentInfo segment = localCache.get(businessType); if (segment != null && segment.hasNext()) { return segment.next(); } segment = getFromRedisCache(businessType); if (segment != null && segment.hasNext()) { localCache.put(businessType, segment); return segment.next(); } segment = getNewSegment(businessType); localCache.put(businessType, segment); updateRedisCache(businessType, segment); return segment.next(); } private SegmentInfo getNewSegment (String businessType) { return idSegmentMapper.getAvailableSegment(businessType); } private SegmentInfo getFromRedisCache (String businessType) { String cacheKey = "segment:" + businessType; return (SegmentInfo) redisTemplate.opsForValue().get(cacheKey); } private void updateRedisCache (String businessType, SegmentInfo segment) { CompletableFuture.runAsync(() -> { String cacheKey = "segment:" + businessType; redisTemplate.opsForValue().set(cacheKey, segment, Duration.ofMinutes(30 )); }); } public static class SegmentInfo { private long segmentId; private long startId; private long endId; private long currentId; public SegmentInfo (long segmentId, long startId, long endId, long currentId) { this .segmentId = segmentId; this .startId = startId; this .endId = endId; this .currentId = currentId; } public boolean hasNext () { return currentId <= endId; } public long next () { if (!hasNext()) { throw new IllegalStateException ("分段已用完" ); } return currentId++; } public long getSegmentId () { return segmentId; } public void setSegmentId (long segmentId) { this .segmentId = segmentId; } public long getStartId () { return startId; } public void setStartId (long startId) { this .startId = startId; } public long getEndId () { return endId; } public void setEndId (long endId) { this .endId = endId; } public long getCurrentId () { return currentId; } public void setCurrentId (long currentId) { this .currentId = currentId; } } }
三、MySQL性能优化策略 3.1 数据库优化 3.1.1 索引优化 1 2 3 4 5 6 7 8 9 10 11 12 13 CREATE UNIQUE INDEX uk_business_type ON id_generator (business_type);CREATE INDEX idx_business_version ON id_generator (business_type, version);CREATE INDEX idx_business_current ON id_generator (business_type, current_max_id, step_size);ALTER TABLE id_generator PARTITION BY HASH(business_type) PARTITIONS 4 ;
3.1.2 查询优化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 SELECT business_type, current_max_id, step_size, version FROM id_generator WHERE business_type = 'user' ;SELECT business_type, current_max_id, step_size, version FROM id_generator WHERE business_type = 'user' FOR UPDATE ;UPDATE id_generator SET current_max_id = current_max_id + step_size, version = version + 1 , updated_time = NOW() WHERE business_type = 'user' AND version = ?;INSERT INTO id_generator (business_type, step_size, current_max_id) VALUES ('user' , 1000 , 0 ), ('order' , 1000 , 0 ), ('product' , 1000 , 0 ) ON DUPLICATE KEY UPDATE current_max_id = VALUES (current_max_id), updated_time = NOW();
3.1.3 连接池优化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 spring: datasource: hikari: maximum-pool-size: 20 minimum-idle: 5 connection-timeout: 30000 idle-timeout: 600000 max-lifetime: 1800000 leak-detection-threshold: 60000 connection-test-query: SELECT 1 auto-commit: true transaction-isolation: READ_COMMITTED cache-prep-stmts: true prep-stmt-cache-size: 250 prep-stmt-cache-sql-limit: 2048
3.2 并发控制优化 3.2.1 乐观锁实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 @Service public class OptimisticLockIdGenerator { @Autowired private IdGeneratorMapper idGeneratorMapper; private final int MAX_RETRIES = 3 ; public IdRange getNewIdRangeWithOptimisticLock (String businessType) { for (int i = 0 ; i < MAX_RETRIES; i++) { try { IdGeneratorInfo info = idGeneratorMapper.getById(businessType); if (info == null ) { throw new IllegalArgumentException ("业务类型不存在: " + businessType); } long start = info.getCurrentMaxId() + 1 ; long end = info.getCurrentMaxId() + info.getStepSize(); int updated = idGeneratorMapper.updateIdRange(businessType, info.getVersion()); if (updated > 0 ) { return new IdRange (start, end); } Thread.sleep(10 + i * 10 ); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException ("线程被中断" , e); } } throw new RuntimeException ("获取ID段失败,重试次数已用完" ); } }
3.2.2 悲观锁实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 @Service public class PessimisticLockIdGenerator { @Autowired private IdGeneratorMapper idGeneratorMapper; @Transactional public IdRange getNewIdRangeWithPessimisticLock (String businessType) { IdGeneratorInfo info = idGeneratorMapper.getByIdForUpdate(businessType); if (info == null ) { throw new IllegalArgumentException ("业务类型不存在: " + businessType); } long start = info.getCurrentMaxId() + 1 ; long end = info.getCurrentMaxId() + info.getStepSize(); int updated = idGeneratorMapper.updateIdRangeForUpdate(businessType); if (updated == 0 ) { throw new RuntimeException ("更新ID段失败" ); } return new IdRange (start, end); } }
3.2.3 分布式锁实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 @Service public class DistributedLockIdGenerator { @Autowired private RedisTemplate<String, Object> redisTemplate; @Autowired private IdGeneratorMapper idGeneratorMapper; private final String LOCK_PREFIX = "id_generator_lock:" ; private final int LOCK_TIMEOUT = 30 ; public IdRange getNewIdRangeWithDistributedLock (String businessType) { String lockKey = LOCK_PREFIX + businessType; String lockValue = UUID.randomUUID().toString(); try { boolean acquired = acquireLock(lockKey, lockValue, LOCK_TIMEOUT); if (!acquired) { throw new RuntimeException ("获取分布式锁失败" ); } IdGeneratorInfo info = idGeneratorMapper.getById(businessType); if (info == null ) { throw new IllegalArgumentException ("业务类型不存在: " + businessType); } long start = info.getCurrentMaxId() + 1 ; long end = info.getCurrentMaxId() + info.getStepSize(); int updated = idGeneratorMapper.updateIdRangeForUpdate(businessType); if (updated == 0 ) { throw new RuntimeException ("更新ID段失败" ); } return new IdRange (start, end); } finally { releaseLock(lockKey, lockValue); } } private boolean acquireLock (String lockKey, String lockValue, int timeout) { return redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, Duration.ofSeconds(timeout)); } private void releaseLock (String lockKey, String lockValue) { String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end" ; redisTemplate.execute(new DefaultRedisScript <>(script, Long.class), Collections.singletonList(lockKey), lockValue); } }
3.3 缓存优化 3.3.1 多级缓存 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 @Service public class MultiLevelCacheIdGenerator { @Autowired private IdGeneratorMapper idGeneratorMapper; @Autowired private RedisTemplate<String, Object> redisTemplate; private final Map<String, IdRange> localCache = new ConcurrentHashMap <>(); private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1 ); public Long generateId (String businessType) { IdRange range = localCache.get(businessType); if (range != null && range.hasNext()) { return range.next(); } range = getFromRedisCache(businessType); if (range != null && range.hasNext()) { localCache.put(businessType, range); return range.next(); } range = getNewIdRange(businessType); localCache.put(businessType, range); updateCacheAsync(businessType, range); return range.next(); } private IdRange getFromRedisCache (String businessType) { String cacheKey = "id_range:" + businessType; return (IdRange) redisTemplate.opsForValue().get(cacheKey); } private void updateCacheAsync (String businessType, IdRange range) { CompletableFuture.runAsync(() -> { String cacheKey = "id_range:" + businessType; redisTemplate.opsForValue().set(cacheKey, range, Duration.ofMinutes(30 )); preloadNextIdRange(businessType); }); } private void preloadNextIdRange (String businessType) { try { IdRange nextRange = getNewIdRange(businessType); String cacheKey = "id_range:" + businessType; redisTemplate.opsForValue().set(cacheKey, nextRange, Duration.ofMinutes(30 )); } catch (Exception e) { log.warn("预热ID段失败: {}" , e.getMessage()); } } @PostConstruct public void startCacheCleanup () { scheduler.scheduleAtFixedRate(() -> { localCache.entrySet().removeIf(entry -> !entry.getValue().hasNext()); }, 5 , 5 , TimeUnit.MINUTES); } }
3.3.2 缓存预热 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 @Service public class CacheWarmupService { @Autowired private IdGeneratorMapper idGeneratorMapper; @Autowired private RedisTemplate<String, Object> redisTemplate; @PostConstruct public void warmupCache () { List<String> businessTypes = idGeneratorMapper.getAllBusinessTypes(); businessTypes.parallelStream().forEach(businessType -> { try { warmupBusinessType(businessType); } catch (Exception e) { log.error("预热业务类型失败: {}" , businessType, e); } }); } private void warmupBusinessType (String businessType) { IdRange range = getNewIdRange(businessType); String cacheKey = "id_range:" + businessType; redisTemplate.opsForValue().set(cacheKey, range, Duration.ofMinutes(30 )); log.info("预热业务类型完成: {}" , businessType); } @Scheduled(fixedRate = 300000) public void scheduledWarmup () { checkCacheUsage(); warmupLowUsageCache(); } private void checkCacheUsage () { } private void warmupLowUsageCache () { } }
四、高可用架构设计 4.1 主从复制架构 4.1.1 主从配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 [mysqld] server- id = 1 log- bin = mysql- bin binlog- format = ROW sync- binlog = 1 innodb- flush- log- at - trx- commit = 1 [mysqld] server- id = 2 relay- log = mysql- relay- bin read- only = 1 slave- skip - errors = 1062 ,1032
4.1.2 读写分离 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 @Service public class ReadWriteSplitIdGenerator { @Autowired @Qualifier("masterDataSource") private DataSource masterDataSource; @Autowired @Qualifier("slaveDataSource") private DataSource slaveDataSource; @Autowired private IdGeneratorMapper idGeneratorMapper; @Transactional public IdRange getNewIdRange (String businessType) { return idGeneratorMapper.getNewIdRange(businessType); } public IdGeneratorInfo getById (String businessType) { return idGeneratorMapper.getById(businessType); } public boolean checkHealth () { try { boolean masterHealthy = checkDataSourceHealth(masterDataSource); boolean slaveHealthy = checkDataSourceHealth(slaveDataSource); return masterHealthy && slaveHealthy; } catch (Exception e) { log.error("健康检查失败" , e); return false ; } } private boolean checkDataSourceHealth (DataSource dataSource) { try (Connection connection = dataSource.getConnection()) { return connection.isValid(5 ); } catch (SQLException e) { return false ; } } }
4.2 集群架构 4.2.1 分片策略 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 @Service public class ShardedIdGenerator { @Autowired private List<IdGeneratorMapper> shardMappers; @Autowired private ShardRouter shardRouter; public Long generateId (String businessType) { int shardIndex = shardRouter.getShardIndex(businessType); IdGeneratorMapper mapper = shardMappers.get(shardIndex); IdRange range = mapper.getNewIdRange(businessType); return range.next(); } @Component public static class ShardRouter { private final int shardCount; public ShardRouter (@Value("${id.generator.shard.count:4}") int shardCount) { this .shardCount = shardCount; } public int getShardIndex (String businessType) { return Math.abs(businessType.hashCode()) % shardCount; } } }
4.2.2 负载均衡 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 @Service public class LoadBalancedIdGenerator { @Autowired private List<IdGeneratorService> idGeneratorServices; @Autowired private LoadBalancer loadBalancer; public Long generateId (String businessType) { IdGeneratorService service = loadBalancer.select(idGeneratorServices); return service.generateId(businessType); } @Component public static class LoadBalancer { private final AtomicInteger counter = new AtomicInteger (0 ); public IdGeneratorService select (List<IdGeneratorService> services) { int index = counter.getAndIncrement() % services.size(); return services.get(index); } public IdGeneratorService selectRandom (List<IdGeneratorService> services) { int index = ThreadLocalRandom.current().nextInt(services.size()); return services.get(index); } public IdGeneratorService selectWeighted (List<IdGeneratorService> services, List<Integer> weights) { return services.get(0 ); } } }
4.3 故障转移 4.3.1 故障检测 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 @Service public class FailureDetectionService { @Autowired private List<IdGeneratorService> idGeneratorServices; private final Map<String, HealthStatus> healthStatus = new ConcurrentHashMap <>(); private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1 ); @PostConstruct public void startFailureDetection () { scheduler.scheduleAtFixedRate(this ::detectFailures, 0 , 30 , TimeUnit.SECONDS); } private void detectFailures () { idGeneratorServices.forEach(service -> { String serviceId = service.getServiceId(); try { boolean healthy = service.healthCheck(); updateHealthStatus(serviceId, healthy); } catch (Exception e) { updateHealthStatus(serviceId, false ); log.warn("服务健康检查失败: {}" , serviceId, e); } }); } private void updateHealthStatus (String serviceId, boolean healthy) { HealthStatus status = healthStatus.computeIfAbsent(serviceId, k -> new HealthStatus ()); status.setHealthy(healthy); status.setLastCheckTime(System.currentTimeMillis()); if (!healthy) { status.incrementFailureCount(); } else { status.resetFailureCount(); } } public List<IdGeneratorService> getHealthyServices () { return idGeneratorServices.stream() .filter(service -> { HealthStatus status = healthStatus.get(service.getServiceId()); return status != null && status.isHealthy(); }) .collect(Collectors.toList()); } public static class HealthStatus { private boolean healthy = true ; private long lastCheckTime = System.currentTimeMillis(); private int failureCount = 0 ; public void incrementFailureCount () { this .failureCount++; } public void resetFailureCount () { this .failureCount = 0 ; } public boolean isHealthy () { return healthy; } public void setHealthy (boolean healthy) { this .healthy = healthy; } public long getLastCheckTime () { return lastCheckTime; } public void setLastCheckTime (long lastCheckTime) { this .lastCheckTime = lastCheckTime; } public int getFailureCount () { return failureCount; } } }
4.3.2 故障转移 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 @Service public class FailoverIdGenerator { @Autowired private FailureDetectionService failureDetectionService; @Autowired private List<IdGeneratorService> idGeneratorServices; public Long generateId (String businessType) { List<IdGeneratorService> healthyServices = failureDetectionService.getHealthyServices(); if (healthyServices.isEmpty()) { throw new RuntimeException ("没有可用的ID生成服务" ); } for (IdGeneratorService service : healthyServices) { try { return service.generateId(businessType); } catch (Exception e) { log.warn("服务调用失败,尝试下一个服务: {}" , service.getServiceId(), e); } } throw new RuntimeException ("所有服务都不可用" ); } public List<Long> generateIds (String businessType, int count) { List<Long> ids = new ArrayList <>(); for (int i = 0 ; i < count; i++) { ids.add(generateId(businessType)); } return ids; } }
五、性能监控与优化 5.1 性能监控 5.1.1 监控指标 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 @Component public class IdGeneratorMetrics { private final MeterRegistry meterRegistry; private final Counter idGenerationCounter; private final Timer idGenerationTimer; private final Gauge cacheHitRate; private final Gauge cacheMissRate; public IdGeneratorMetrics (MeterRegistry meterRegistry) { this .meterRegistry = meterRegistry; this .idGenerationCounter = Counter.builder("id.generator.count" ) .description("ID生成次数" ) .register(meterRegistry); this .idGenerationTimer = Timer.builder("id.generator.duration" ) .description("ID生成耗时" ) .register(meterRegistry); this .cacheHitRate = Gauge.builder("id.generator.cache.hit.rate" ) .description("缓存命中率" ) .register(meterRegistry, this , IdGeneratorMetrics::getCacheHitRate); this .cacheMissRate = Gauge.builder("id.generator.cache.miss.rate" ) .description("缓存未命中率" ) .register(meterRegistry, this , IdGeneratorMetrics::getCacheMissRate); } public void recordIdGeneration (String businessType, long duration) { idGenerationCounter.increment(Tags.of("business_type" , businessType)); idGenerationTimer.record(duration, TimeUnit.MILLISECONDS); } public void recordCacheHit (String businessType) { Counter.builder("id.generator.cache.hit" ) .description("缓存命中次数" ) .tag("business_type" , businessType) .register(meterRegistry) .increment(); } public void recordCacheMiss (String businessType) { Counter.builder("id.generator.cache.miss" ) .description("缓存未命中次数" ) .tag("business_type" , businessType) .register(meterRegistry) .increment(); } private double getCacheHitRate () { return 0.95 ; } private double getCacheMissRate () { return 0.05 ; } }
5.1.2 性能分析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 @Service public class PerformanceAnalysisService { @Autowired private IdGeneratorMetrics metrics; @Autowired private MeterRegistry meterRegistry; public PerformanceAnalysisResult analyzePerformance () { PerformanceAnalysisResult result = new PerformanceAnalysisResult (); analyzeIdGenerationPerformance(result); analyzeCachePerformance(result); analyzeDatabasePerformance(result); return result; } private void analyzeIdGenerationPerformance (PerformanceAnalysisResult result) { Timer idGenerationTimer = meterRegistry.find("id.generator.duration" ).timer(); if (idGenerationTimer != null ) { result.setAvgIdGenerationTime(idGenerationTimer.mean(TimeUnit.MILLISECONDS)); result.setMaxIdGenerationTime(idGenerationTimer.max(TimeUnit.MILLISECONDS)); result.setP95IdGenerationTime(idGenerationTimer.percentile(0.95 , TimeUnit.MILLISECONDS)); result.setP99IdGenerationTime(idGenerationTimer.percentile(0.99 , TimeUnit.MILLISECONDS)); } Counter idGenerationCounter = meterRegistry.find("id.generator.count" ).counter(); if (idGenerationCounter != null ) { result.setTotalIdGenerationCount(idGenerationCounter.count()); } } private void analyzeCachePerformance (PerformanceAnalysisResult result) { Gauge cacheHitRate = meterRegistry.find("id.generator.cache.hit.rate" ).gauge(); if (cacheHitRate != null ) { result.setCacheHitRate(cacheHitRate.value()); } Gauge cacheMissRate = meterRegistry.find("id.generator.cache.miss.rate" ).gauge(); if (cacheMissRate != null ) { result.setCacheMissRate(cacheMissRate.value()); } } private void analyzeDatabasePerformance (PerformanceAnalysisResult result) { result.setDatabaseConnectionCount(10 ); result.setDatabaseQueryTime(50.0 ); result.setDatabaseUpdateTime(30.0 ); } }
5.2 性能优化 5.2.1 批量优化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 @Service public class BatchIdGenerator { @Autowired private IdGeneratorMapper idGeneratorMapper; @Autowired private RedisTemplate<String, Object> redisTemplate; private final Map<String, BatchIdRange> batchCache = new ConcurrentHashMap <>(); public List<Long> generateBatchIds (String businessType, int count) { List<Long> ids = new ArrayList <>(); BatchIdRange batchRange = batchCache.get(businessType); if (batchRange != null && batchRange.hasNext(count)) { return batchRange.next(count); } batchRange = getFromRedisBatchCache(businessType); if (batchRange != null && batchRange.hasNext(count)) { batchCache.put(businessType, batchRange); return batchRange.next(count); } batchRange = getNewBatchIdRange(businessType, count); batchCache.put(businessType, batchRange); updateRedisBatchCache(businessType, batchRange); return batchRange.next(count); } private BatchIdRange getNewBatchIdRange (String businessType, int count) { int stepSize = Math.max(count * 2 , 1000 ); IdRange range = idGeneratorMapper.getNewIdRange(businessType); return new BatchIdRange (range.getStart(), range.getEnd()); } private BatchIdRange getFromRedisBatchCache (String businessType) { String cacheKey = "batch_id_range:" + businessType; return (BatchIdRange) redisTemplate.opsForValue().get(cacheKey); } private void updateRedisBatchCache (String businessType, BatchIdRange batchRange) { CompletableFuture.runAsync(() -> { String cacheKey = "batch_id_range:" + businessType; redisTemplate.opsForValue().set(cacheKey, batchRange, Duration.ofMinutes(30 )); }); } public static class BatchIdRange { private long start; private long end; private long current; public BatchIdRange (long start, long end) { this .start = start; this .end = end; this .current = start; } public boolean hasNext (int count) { return current + count - 1 <= end; } public List<Long> next (int count) { if (!hasNext(count)) { throw new IllegalStateException ("批量ID段不足" ); } List<Long> ids = new ArrayList <>(); for (int i = 0 ; i < count; i++) { ids.add(current++); } return ids; } public long getStart () { return start; } public void setStart (long start) { this .start = start; } public long getEnd () { return end; } public void setEnd (long end) { this .end = end; } public long getCurrent () { return current; } public void setCurrent (long current) { this .current = current; } } }
5.2.2 异步优化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 @Service public class AsyncIdGenerator { @Autowired private IdGeneratorMapper idGeneratorMapper; @Autowired private RedisTemplate<String, Object> redisTemplate; private final ExecutorService asyncExecutor = Executors.newFixedThreadPool(10 ); public CompletableFuture<Long> generateIdAsync (String businessType) { return CompletableFuture.supplyAsync(() -> { return generateId(businessType); }, asyncExecutor); } public CompletableFuture<List<Long>> generateIdsAsync (String businessType, int count) { return CompletableFuture.supplyAsync(() -> { return generateIds(businessType, count); }, asyncExecutor); } public CompletableFuture<Void> preloadIdRangeAsync (String businessType) { return CompletableFuture.runAsync(() -> { try { IdRange range = getNewIdRange(businessType); String cacheKey = "id_range:" + businessType; redisTemplate.opsForValue().set(cacheKey, range, Duration.ofMinutes(30 )); log.info("异步预热ID段完成: {}" , businessType); } catch (Exception e) { log.error("异步预热ID段失败: {}" , businessType, e); } }, asyncExecutor); } private Long generateId (String businessType) { return 1L ; } private List<Long> generateIds (String businessType, int count) { return Collections.singletonList(1L ); } private IdRange getNewIdRange (String businessType) { return new IdRange (1 , 1000 ); } }
六、企业级部署方案 6.1 容器化部署 6.1.1 Docker配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 FROM openjdk:8 -jdk-alpineWORKDIR /app COPY target/id-generator-*.jar app.jar ENV JAVA_OPTS="-Xms512m -Xmx1g -XX:+UseG1GC" EXPOSE 8080 CMD ["sh" , "-c" , "java $JAVA_OPTS -jar app.jar" ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 version: '3.8' services: id-generator: build: . ports: - "8080:8080" environment: - SPRING_PROFILES_ACTIVE=prod - MYSQL_HOST=mysql - REDIS_HOST=redis depends_on: - mysql - redis restart: unless-stopped mysql: image: mysql:8.0 environment: - MYSQL_ROOT_PASSWORD=root123 - MYSQL_DATABASE=id_generator ports: - "3306:3306" volumes: - mysql_data:/var/lib/mysql - ./sql:/docker-entrypoint-initdb.d restart: unless-stopped redis: image: redis:6.2-alpine ports: - "6379:6379" volumes: - redis_data:/data restart: unless-stopped volumes: mysql_data: redis_data:
6.1.2 Kubernetes部署 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 apiVersion: apps/v1 kind: Deployment metadata: name: id-generator spec: replicas: 3 selector: matchLabels: app: id-generator template: metadata: labels: app: id-generator spec: containers: - name: id-generator image: id-generator:latest ports: - containerPort: 8080 env: - name: SPRING_PROFILES_ACTIVE value: "k8s" - name: MYSQL_HOST value: "mysql-service" - name: REDIS_HOST value: "redis-service" resources: requests: memory: "512Mi" cpu: "250m" limits: memory: "1Gi" cpu: "500m" livenessProbe: httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 5 periodSeconds: 5 --- apiVersion: v1 kind: Service metadata: name: id-generator-service spec: selector: app: id-generator ports: - port: 8080 targetPort: 8080 type: ClusterIP --- apiVersion: v1 kind: Service metadata: name: mysql-service spec: selector: app: mysql ports: - port: 3306 targetPort: 3306 type: ClusterIP --- apiVersion: v1 kind: Service metadata: name: redis-service spec: selector: app: redis ports: - port: 6379 targetPort: 6379 type: ClusterIP
6.2 监控告警 6.2.1 Prometheus配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 global: scrape_interval: 15s scrape_configs: - job_name: 'id-generator' static_configs: - targets: ['id-generator-service:8080' ] metrics_path: '/actuator/prometheus' scrape_interval: 5s rule_files: - "id-generator-rules.yml" alerting: alertmanagers: - static_configs: - targets: - alertmanager:9093
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 groups: - name: id-generator-alerts rules: - alert: HighIdGenerationLatency expr: id_generator_duration_seconds{quantile="0.95"} > 1 for: 2m labels: severity: warning annotations: summary: "ID生成延迟过高" description: "ID生成P95延迟超过1秒,当前值: {{ $value }} 秒" - alert: LowCacheHitRate expr: id_generator_cache_hit_rate < 0.8 for: 5m labels: severity: warning annotations: summary: "缓存命中率过低" description: "缓存命中率低于80%,当前值: {{ $value }} %" - alert: HighErrorRate expr: rate(id_generator_errors_total[5m]) > 0.1 for: 2m labels: severity: critical annotations: summary: "ID生成错误率过高" description: "ID生成错误率超过10%,当前值: {{ $value }} "
6.2.2 Grafana仪表板 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 { "dashboard" : { "title" : "ID生成器监控仪表板" , "panels" : [ { "title" : "ID生成QPS" , "type" : "graph" , "targets" : [ { "expr" : "rate(id_generator_count_total[1m])" , "legendFormat" : "{{business_type}}" } ] } , { "title" : "ID生成延迟" , "type" : "graph" , "targets" : [ { "expr" : "id_generator_duration_seconds" , "legendFormat" : "{{quantile}}" } ] } , { "title" : "缓存命中率" , "type" : "singlestat" , "targets" : [ { "expr" : "id_generator_cache_hit_rate" , "legendFormat" : "命中率" } ] } , { "title" : "数据库连接数" , "type" : "graph" , "targets" : [ { "expr" : "hikaricp_connections_active" , "legendFormat" : "活跃连接" } , { "expr" : "hikaricp_connections_idle" , "legendFormat" : "空闲连接" } ] } ] } }
6.3 运维管理 6.3.1 健康检查 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 @Component public class HealthCheckService { @Autowired private DataSource dataSource; @Autowired private RedisTemplate<String, Object> redisTemplate; @Autowired private IdGeneratorMapper idGeneratorMapper; public HealthStatus checkHealth () { HealthStatus status = new HealthStatus (); boolean dbHealthy = checkDatabaseHealth(); status.setDatabaseHealthy(dbHealthy); boolean redisHealthy = checkRedisHealth(); status.setRedisHealthy(redisHealthy); boolean idGeneratorHealthy = checkIdGeneratorHealth(); status.setIdGeneratorHealthy(idGeneratorHealthy); status.setOverallHealthy(dbHealthy && redisHealthy && idGeneratorHealthy); return status; } private boolean checkDatabaseHealth () { try (Connection connection = dataSource.getConnection()) { return connection.isValid(5 ); } catch (SQLException e) { log.error("数据库健康检查失败" , e); return false ; } } private boolean checkRedisHealth () { try { String result = redisTemplate.getConnectionFactory().getConnection().ping(); return "PONG" .equals(result); } catch (Exception e) { log.error("Redis健康检查失败" , e); return false ; } } private boolean checkIdGeneratorHealth () { try { Long id = idGeneratorMapper.getNewIdRange("health_check" ).next(); return id != null && id > 0 ; } catch (Exception e) { log.error("ID生成器健康检查失败" , e); return false ; } } public static class HealthStatus { private boolean overallHealthy; private boolean databaseHealthy; private boolean redisHealthy; private boolean idGeneratorHealthy; private long checkTime = System.currentTimeMillis(); public boolean isOverallHealthy () { return overallHealthy; } public void setOverallHealthy (boolean overallHealthy) { this .overallHealthy = overallHealthy; } public boolean isDatabaseHealthy () { return databaseHealthy; } public void setDatabaseHealthy (boolean databaseHealthy) { this .databaseHealthy = databaseHealthy; } public boolean isRedisHealthy () { return redisHealthy; } public void setRedisHealthy (boolean redisHealthy) { this .redisHealthy = redisHealthy; } public boolean isIdGeneratorHealthy () { return idGeneratorHealthy; } public void setIdGeneratorHealthy (boolean idGeneratorHealthy) { this .idGeneratorHealthy = idGeneratorHealthy; } public long getCheckTime () { return checkTime; } public void setCheckTime (long checkTime) { this .checkTime = checkTime; } } }
6.3.2 运维脚本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 #!/bin/bash SERVICE_NAME="id-generator" HEALTH_CHECK_URL="http://localhost:8080/actuator/health" LOG_FILE="/var/log/id-generator/ops.log" log () { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1 " >> $LOG_FILE } health_check () { local response=$(curl -s -o /dev/null -w "%{http_code}" $HEALTH_CHECK_URL ) if [ "$response " = "200" ]; then log "健康检查通过" return 0 else log "健康检查失败,HTTP状态码: $response " return 1 fi } restart_service () { log "开始重启服务" systemctl stop $SERVICE_NAME sleep 10 systemctl start $SERVICE_NAME sleep 30 if health_check; then log "服务重启成功" return 0 else log "服务重启失败" return 1 fi } clear_cache () { log "开始清理缓存" redis-cli FLUSHDB curl -X POST "$HEALTH_CHECK_URL /clear-cache" log "缓存清理完成" } performance_test () { log "开始性能测试" ab -n 10000 -c 100 http://localhost:8080/api/id/generate?businessType=test log "性能测试完成" } main () { case "$1 " in "health" ) health_check ;; "restart" ) restart_service ;; "clear-cache" ) clear_cache ;; "performance-test" ) performance_test ;; *) echo "用法: $0 {health|restart|clear-cache|performance-test}" exit 1 ;; esac } main "$@ "
七、总结 基于MySQL实现高性能分布式ID生成器,通过合理的架构设计、性能优化和运维管理,可以满足企业级应用的需求。虽然MySQL在高并发场景下存在性能瓶颈,但通过分段、缓存、异步等优化策略,仍然可以实现高性能的分布式ID生成服务。
7.1 关键要点
架构设计 :采用分段、缓存、异步等策略提高性能
并发控制 :使用乐观锁、悲观锁、分布式锁保证数据一致性
性能优化 :通过索引优化、连接池优化、批量操作提高性能
高可用 :通过主从复制、集群部署、故障转移保证高可用
监控运维 :建立完善的监控告警和运维管理体系
7.2 最佳实践
分段策略 :使用分段表减少锁竞争,提高并发性能
缓存优化 :使用多级缓存减少数据库访问,提高响应速度
批量操作 :使用批量获取减少网络开销,提高吞吐量
异步处理 :使用异步操作提高系统响应性和并发能力
监控告警 :建立完善的监控体系,及时发现和处理问题
通过以上措施,可以构建一个高性能、高可用的MySQL分布式ID生成器,为分布式系统提供可靠的ID生成服务。