SpringBoot實現(xiàn)垂直分片的六種策略
一、垂直分片概述
1.1 什么是垂直分片
垂直分片是數(shù)據(jù)庫分庫分表的一種方式,它按照業(yè)務功能或數(shù)據(jù)表將原本在同一個數(shù)據(jù)庫的數(shù)據(jù)拆分到不同的數(shù)據(jù)庫實例中。
與水平分片(將同一張表的數(shù)據(jù)按照某種規(guī)則分散到不同庫或表中)不同,垂直分片主要解決的是業(yè)務模塊的解耦和單庫的資源瓶頸問題。
1.2 垂直分片的優(yōu)勢
- 減輕單庫壓力:將不同業(yè)務模塊分散到不同數(shù)據(jù)庫,分散了數(shù)據(jù)庫負載
- 業(yè)務解耦:不同業(yè)務模塊的數(shù)據(jù)獨立存儲,便于業(yè)務模塊的獨立擴展
- 提高系統(tǒng)可用性:單個數(shù)據(jù)庫故障只會影響部分業(yè)務模塊
- 便于維護和優(yōu)化:可以針對不同業(yè)務特點選擇不同的數(shù)據(jù)庫類型和優(yōu)化策略
- 權限隔離:便于進行業(yè)務級別的數(shù)據(jù)訪問權限控制
1.3 垂直分片的挑戰(zhàn)
- 分布式事務:跨庫操作時需要處理分布式事務
- 數(shù)據(jù)一致性:多庫數(shù)據(jù)同步和一致性保證
- 跨庫查詢:涉及多個業(yè)務模塊的查詢變得復雜
- 開發(fā)復雜度增加:需要管理多個數(shù)據(jù)源和業(yè)務拆分
二、多數(shù)據(jù)源配置策略
2.1 基本原理
多數(shù)據(jù)源配置是實現(xiàn)垂直分片最直接的方式,通過在SpringBoot中配置多個DataSource并為不同的業(yè)務模塊指定不同的數(shù)據(jù)源,實現(xiàn)業(yè)務數(shù)據(jù)的物理隔離。
2.2 實現(xiàn)步驟
2.2.1 配置多個數(shù)據(jù)源
首先在application.yml中配置多個數(shù)據(jù)源:
spring:
datasource:
# 用戶服務數(shù)據(jù)源
user:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://user-db:3306/user_db
username: user_app
password: password
# 訂單服務數(shù)據(jù)源
order:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://order-db:3306/order_db
username: order_app
password: password
# 產品服務數(shù)據(jù)源
product:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://product-db:3306/product_db
username: product_app
password: password
2.2.2 創(chuàng)建數(shù)據(jù)源配置類
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.user")
public DataSource userDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.order")
public DataSource orderDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.product")
public DataSource productDataSource() {
return DataSourceBuilder.create().build();
}
}
2.2.3 為不同模塊配置獨立的事務管理器和JdbcTemplate
@Configuration
public class UserDbConfig {
@Autowired
@Qualifier("userDataSource")
private DataSource userDataSource;
@Bean
public JdbcTemplate userJdbcTemplate() {
return new JdbcTemplate(userDataSource);
}
@Bean
public PlatformTransactionManager userTransactionManager() {
return new DataSourceTransactionManager(userDataSource);
}
}
@Configuration
public class OrderDbConfig {
@Autowired
@Qualifier("orderDataSource")
private DataSource orderDataSource;
@Bean
public JdbcTemplate orderJdbcTemplate() {
return new JdbcTemplate(orderDataSource);
}
@Bean
public PlatformTransactionManager orderTransactionManager() {
return new DataSourceTransactionManager(orderDataSource);
}
}
@Configuration
public class ProductDbConfig {
@Autowired
@Qualifier("productDataSource")
private DataSource productDataSource;
@Bean
public JdbcTemplate productJdbcTemplate() {
return new JdbcTemplate(productDataSource);
}
@Bean
public PlatformTransactionManager productTransactionManager() {
return new DataSourceTransactionManager(productDataSource);
}
}
2.2.4 在Service層使用不同的數(shù)據(jù)源
@Service
public class UserService {
@Autowired
@Qualifier("userJdbcTemplate")
private JdbcTemplate jdbcTemplate;
@Transactional("userTransactionManager")
public User createUser(User user) {
// 用戶數(shù)據(jù)庫操作
// ...
}
}
@Service
public class OrderService {
@Autowired
@Qualifier("orderJdbcTemplate")
private JdbcTemplate jdbcTemplate;
@Transactional("orderTransactionManager")
public Order createOrder(Order order) {
// 訂單數(shù)據(jù)庫操作
// ...
}
}
2.3 優(yōu)缺點分析
優(yōu)點:
- 配置簡單直觀,容易理解
- 與Spring生態(tài)高度集成
- 對業(yè)務代碼侵入性低
- 可以針對不同數(shù)據(jù)源配置不同的連接池參數(shù)
缺點:
- 無法動態(tài)增減數(shù)據(jù)源
- 分布式事務處理復雜
- 適合業(yè)務模塊劃分明確且相對獨立的場景
- 代碼中需要顯式指定使用哪個數(shù)據(jù)源和事務管理器
2.4 適用場景
- 系統(tǒng)初期垂直分片設計
- 業(yè)務模塊劃分明確,跨模塊調用較少的系統(tǒng)
- 數(shù)據(jù)源數(shù)量較少且相對固定的場景
三、動態(tài)數(shù)據(jù)源路由策略
3.1 基本原理
動態(tài)數(shù)據(jù)源路由利用Spring提供的AbstractRoutingDataSource類,根據(jù)當前執(zhí)行的上下文(如當前線程)動態(tài)決定使用哪個數(shù)據(jù)源。
這種方式實現(xiàn)了數(shù)據(jù)源選擇的透明化,使業(yè)務代碼無需關心具體使用哪個數(shù)據(jù)源。
3.2 實現(xiàn)步驟
3.2.1 創(chuàng)建數(shù)據(jù)源路由上下文
public class DataSourceContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
public static void setDataSourceType(String dataSourceType) {
contextHolder.set(dataSourceType);
}
public static String getDataSourceType() {
return contextHolder.get();
}
public static void clearDataSourceType() {
contextHolder.remove();
}
}
3.2.2 實現(xiàn)動態(tài)數(shù)據(jù)源路由
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSourceType();
}
}
3.2.3 配置動態(tài)數(shù)據(jù)源
@Configuration
public class DynamicDataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.user")
public DataSource userDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.order")
public DataSource orderDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.product")
public DataSource productDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@Primary
public DataSource dynamicDataSource() {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
Map<Object, Object> dataSourceMap = new HashMap<>(3);
dataSourceMap.put("user", userDataSource());
dataSourceMap.put("order", orderDataSource());
dataSourceMap.put("product", productDataSource());
// 設置數(shù)據(jù)源映射
dynamicDataSource.setTargetDataSources(dataSourceMap);
// 設置默認數(shù)據(jù)源
dynamicDataSource.setDefaultTargetDataSource(userDataSource());
return dynamicDataSource;
}
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dynamicDataSource());
}
}
3.2.4 創(chuàng)建數(shù)據(jù)源切換注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSourceSelector {
String value();
}
3.2.5 實現(xiàn)數(shù)據(jù)源切換的AOP切面
@Aspect
@Component
public class DataSourceAspect {
@Pointcut("@annotation(com.example.config.DataSourceSelector)")
public void dataSourcePointcut() {}
@Before("dataSourcePointcut() && @annotation(dataSource)")
public void switchDataSource(JoinPoint point, DataSourceSelector dataSource) {
String dataSourceName = dataSource.value();
DataSourceContextHolder.setDataSourceType(dataSourceName);
}
@After("dataSourcePointcut()")
public void restoreDataSource(JoinPoint point) {
DataSourceContextHolder.clearDataSourceType();
}
}
3.2.6 在Service層使用注解切換數(shù)據(jù)源
@Service
public class UserService {
@Autowired
private JdbcTemplate jdbcTemplate;
@DataSourceSelector("user")
@Transactional
public User createUser(User user) {
// 用戶數(shù)據(jù)庫操作
// ...
}
}
@Service
public class OrderService {
@Autowired
private JdbcTemplate jdbcTemplate;
@DataSourceSelector("order")
@Transactional
public Order createOrder(Order order) {
// 訂單數(shù)據(jù)庫操作
// ...
}
}
3.3 優(yōu)缺點分析
優(yōu)點:
- 數(shù)據(jù)源切換對業(yè)務代碼透明,只需添加注解即可
- 支持動態(tài)增減數(shù)據(jù)源
- 可以在運行時根據(jù)不同條件切換數(shù)據(jù)源
- 只需配置一個事務管理器,簡化事務配置
缺點:
- 實現(xiàn)相對復雜
- 依賴ThreadLocal,在異步或多線程環(huán)境下需要特別處理
- 事務管理需要注意,避免切換數(shù)據(jù)源導致事務問題
- 不易實現(xiàn)分布式事務
3.4 適用場景
- 業(yè)務模塊獨立性不強,存在跨模塊訪問需求的系統(tǒng)
- 需要在運行時動態(tài)決定數(shù)據(jù)源的場景
- 數(shù)據(jù)源數(shù)量可能動態(tài)變化的系統(tǒng)
四、ORM框架多數(shù)據(jù)源配置策略
4.1 基本原理
利用ORM框架(如JPA、MyBatis)的多數(shù)據(jù)源支持,為不同的業(yè)務模塊配置獨立的ORM組件,實現(xiàn)對不同數(shù)據(jù)庫的透明訪問。
這種方式結合了ORM的便利性和垂直分片的優(yōu)勢。
4.2 實現(xiàn)步驟(以JPA為例)
4.2.1 配置多個數(shù)據(jù)源
spring:
# 用戶服務數(shù)據(jù)源
datasource:
user:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://user-db:3306/user_db
username: user_app
password: password
# 訂單服務數(shù)據(jù)源
order:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://order-db:3306/order_db
username: order_app
password: password
jpa:
hibernate:
ddl-auto: update
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL8Dialect
4.2.2 配置用戶模塊的JPA配置
@Configuration
@EnableJpaRepositories(
basePackages = "com.example.user.repository",
entityManagerFactoryRef = "userEntityManagerFactory",
transactionManagerRef = "userTransactionManager"
)
public class UserJpaConfig {
@Autowired
@Qualifier("userDataSource")
private DataSource userDataSource;
@Bean
public LocalContainerEntityManagerFactoryBean userEntityManagerFactory(
EntityManagerFactoryBuilder builder) {
return builder
.dataSource(userDataSource)
.packages("com.example.user.entity")
.persistenceUnit("userPU")
.properties(getJpaProperties())
.build();
}
@Bean
public PlatformTransactionManager userTransactionManager(
@Qualifier("userEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
private Map<String, Object> getJpaProperties() {
Map<String, Object> props = new HashMap<>();
props.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect");
props.put("hibernate.hbm2ddl.auto", "update");
return props;
}
}
4.2.3 配置訂單模塊的JPA配置
@Configuration
@EnableJpaRepositories(
basePackages = "com.example.order.repository",
entityManagerFactoryRef = "orderEntityManagerFactory",
transactionManagerRef = "orderTransactionManager"
)
public class OrderJpaConfig {
@Autowired
@Qualifier("orderDataSource")
private DataSource orderDataSource;
@Bean
public LocalContainerEntityManagerFactoryBean orderEntityManagerFactory(
EntityManagerFactoryBuilder builder) {
return builder
.dataSource(orderDataSource)
.packages("com.example.order.entity")
.persistenceUnit("orderPU")
.properties(getJpaProperties())
.build();
}
@Bean
public PlatformTransactionManager orderTransactionManager(
@Qualifier("orderEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
private Map<String, Object> getJpaProperties() {
Map<String, Object> props = new HashMap<>();
props.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect");
props.put("hibernate.hbm2ddl.auto", "update");
return props;
}
}
4.2.4 創(chuàng)建實體類和Repository
用戶模塊:
// 實體類
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String email;
// getters and setters
}
// Repository
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByEmail(String email);
}
訂單模塊:
// 實體類
@Entity
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long userId;
private BigDecimal amount;
private Date orderDate;
// getters and setters
}
// Repository
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
List<Order> findByUserId(Long userId);
}
4.2.5 在Service層使用
@Service
@Transactional("userTransactionManager")
public class UserService {
@Autowired
private UserRepository userRepository;
public User createUser(User user) {
return userRepository.save(user);
}
public User getUserById(Long id) {
return userRepository.findById(id).orElse(null);
}
}
@Service
@Transactional("orderTransactionManager")
public class OrderService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private UserService userService;
public Order createOrder(Order order) {
// 驗證用戶是否存在
User user = userService.getUserById(order.getUserId());
if (user == null) {
throw new RuntimeException("User not found");
}
return orderRepository.save(order);
}
public List<Order> getUserOrders(Long userId) {
return orderRepository.findByUserId(userId);
}
}
4.3 優(yōu)缺點分析
優(yōu)點:
- 充分利用ORM框架的便利性
- 實體類和數(shù)據(jù)庫操作代碼保持簡潔
- 業(yè)務代碼不需要關心數(shù)據(jù)源切換
- 對于不同業(yè)務模塊有清晰的包結構隔離
缺點:
- 配置較為復雜
- 跨模塊查詢需要在Service層手動處理
- 不同模塊的事務無法統(tǒng)一管理,分布式事務支持有限
- 過多的EntityManagerFactory會增加內存開銷
4.4 適用場景
- 已經(jīng)使用ORM框架的項目
- 業(yè)務模塊劃分明確,數(shù)據(jù)模型相對獨立
- 開發(fā)團隊熟悉JPA或其他ORM框架
- 對分布式事務要求不高的場景
五、分庫中間件策略
5.1 基本原理
利用專業(yè)的分庫分表中間件(如ShardingSphere、MyCat等)進行垂直分片,通過中間件提供的路由和代理功能,實現(xiàn)對多個數(shù)據(jù)庫的統(tǒng)一管理和訪問。
這種方式將分片邏輯從應用層下沉到中間件層,簡化了應用開發(fā)。
5.2 實現(xiàn)步驟(以ShardingSphere-JDBC為例)
5.2.1 添加依賴
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.1.0</version>
</dependency>
5.2.2 配置垂直分片規(guī)則
spring:
shardingsphere:
datasource:
names: user-db,order-db,product-db
user-db:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://user-db:3306/user_db
username: user_app
password: password
order-db:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://order-db:3306/order_db
username: order_app
password: password
product-db:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://product-db:3306/product_db
username: product_app
password: password
rules:
sharding:
tables:
# 用戶表配置
users:
actual-data-nodes: user-db.users
user_address:
actual-data-nodes: user-db.user_address
# 訂單表配置
orders:
actual-data-nodes: order-db.orders
order_items:
actual-data-nodes: order-db.order_items
# 產品表配置
products:
actual-data-nodes: product-db.products
product_categories:
actual-data-nodes: product-db.product_categories
props:
sql-show: true
5.2.3 創(chuàng)建實體類和Repository
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String email;
// getters and setters
}
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// 查詢方法
}
@Entity
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long userId;
private BigDecimal amount;
// getters and setters
}
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
List<Order> findByUserId(Long userId);
}
5.2.4 配置數(shù)據(jù)庫訪問
@Configuration
@EnableJpaRepositories(basePackages = "com.example.repository")
@EnableTransactionManagement
public class JpaConfig {
@Bean
public EntityManagerFactory entityManagerFactory(DataSource dataSource) {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.example.entity");
factory.setDataSource(dataSource);
factory.afterPropertiesSet();
return factory.getObject();
}
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory);
return txManager;
}
}
5.2.5 在Service層使用
@Service
@Transactional
public class UserService {
@Autowired
private UserRepository userRepository;
public User createUser(User user) {
return userRepository.save(user);
}
public User getUserById(Long id) {
return userRepository.findById(id).orElse(null);
}
}
@Service
@Transactional
public class OrderService {
@Autowired
private OrderRepository orderRepository;
public Order createOrder(Order order) {
return orderRepository.save(order);
}
public List<Order> getUserOrders(Long userId) {
return orderRepository.findByUserId(userId);
}
}
5.3 優(yōu)缺點分析
優(yōu)點:
- 分片邏輯下沉到中間件,對應用層透明
- 統(tǒng)一的事務管理,部分中間件支持弱XA事務
- 應用代碼無需關心數(shù)據(jù)源切換
- 支持復雜的分片規(guī)則和讀寫分離
缺點:
- 引入額外的中間件,增加系統(tǒng)復雜度
- 對SQL有一定限制,部分復雜查詢可能不支持
- 性能上會有一定的損耗
- 學習成本較高
5.4 適用場景
- 大型系統(tǒng),數(shù)據(jù)量大且需要復雜分片策略
- 需要同時支持垂直分片和水平分片的場景
- 對分布式事務有一定要求的系統(tǒng)
六、微服務架構下的垂直分片策略
6.1 基本原理
在微服務架構中,每個微服務擁有自己獨立的數(shù)據(jù)庫,通過業(yè)務功能的拆分自然實現(xiàn)了垂直分片。
不同微服務之間通過API調用而非直接數(shù)據(jù)庫訪問進行交互,實現(xiàn)了數(shù)據(jù)的物理隔離和訪問控制。
6.2 實現(xiàn)步驟
6.2.1 拆分微服務和數(shù)據(jù)庫
根據(jù)業(yè)務領域劃分微服務:
- 用戶服務:管理用戶相關數(shù)據(jù)
- 訂單服務:管理訂單相關數(shù)據(jù)
- 產品服務:管理產品相關數(shù)據(jù)
- ...
每個微服務擁有獨立的數(shù)據(jù)庫。
6.2.2 用戶服務實現(xiàn)
// 用戶服務數(shù)據(jù)庫配置
@Configuration
@EnableJpaRepositories(basePackages = "com.example.userservice.repository")
public class UserServiceDbConfig {
// 數(shù)據(jù)源、事務管理器等配置
}
// 用戶實體類
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String email;
// getters and setters
}
// 用戶Repository
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// 查詢方法
}
// 用戶服務接口
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public ResponseEntity<User> getUserById(@PathVariable Long id) {
return ResponseEntity.ok(userService.getUserById(id));
}
@PostMapping
public ResponseEntity<User> createUser(@RequestBody User user) {
return ResponseEntity.ok(userService.createUser(user));
}
}
6.2.3 訂單服務實現(xiàn)
// 訂單服務數(shù)據(jù)庫配置
@Configuration
@EnableJpaRepositories(basePackages = "com.example.orderservice.repository")
public class OrderServiceDbConfig {
// 數(shù)據(jù)源、事務管理器等配置
}
// 訂單實體類
@Entity
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long userId;
private BigDecimal amount;
// getters and setters
}
// 訂單Repository
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
List<Order> findByUserId(Long userId);
}
// 用戶客戶端(Feign)
@FeignClient(name = "user-service", fallback = UserClientFallback.class)
public interface UserClient {
@GetMapping("/api/users/{id}")
User getUserById(@PathVariable Long id);
}
// 訂單服務
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private UserClient userClient;
public Order createOrder(Order order) {
// 通過Feign調用用戶服務驗證用戶
User user = userClient.getUserById(order.getUserId());
if (user == null) {
throw new RuntimeException("User not found");
}
return orderRepository.save(order);
}
}
// 訂單API
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@Autowired
private OrderService orderService;
@PostMapping
public ResponseEntity<Order> createOrder(@RequestBody Order order) {
return ResponseEntity.ok(orderService.createOrder(order));
}
@GetMapping("/user/{userId}")
public ResponseEntity<List<Order>> getUserOrders(@PathVariable Long userId) {
return ResponseEntity.ok(orderService.getUserOrders(userId));
}
}
6.3 優(yōu)缺點分析
優(yōu)點:
- 業(yè)務和數(shù)據(jù)完全解耦,每個服務獨立發(fā)展
- 技術??梢造`活選擇,不同服務可以使用不同的數(shù)據(jù)庫類型
- 服務獨立部署和擴展,提高系統(tǒng)彈性
- 服務邊界清晰,符合領域驅動設計理念
缺點:
- 分布式事務處理復雜,通常需要采用最終一致性方案
- 跨服務查詢需要通過API組合數(shù)據(jù),可能影響性能
- 系統(tǒng)復雜度增加,運維成本提高
- 服務拆分需要充分考慮業(yè)務邊界,拆分不當會導致頻繁的跨服務調用
6.4 適用場景
- 大型復雜系統(tǒng),需要獨立擴展不同業(yè)務模塊
- 團隊組織結構與業(yè)務劃分一致,適合采用微服務架構
- 長期演進的系統(tǒng),需要技術棧靈活性
- 對服務隔離性和彈性有較高要求的場景
七、策略比較
| 策略 | 復雜度 | 透明度 | 事務支持 | 跨庫查詢 | 性能影響 | 維護成本 |
|---|---|---|---|---|---|---|
| 多數(shù)據(jù)源配置 | 低 | 低 | 單庫事務 | 需代碼處理 | 低 | 低 |
| 動態(tài)數(shù)據(jù)源路由 | 中 | 中 | 單庫事務 | 需代碼處理 | 低 | 中 |
| ORM多數(shù)據(jù)源 | 中 | 中 | 單庫事務 | 需代碼處理 | 低 | 中 |
| 分庫中間件 | 高 | 高 | 分布式事務 | 部分支持 | 中 | 高 |
| 微服務架構 | 高 | 低 | 最終一致性 | API組合 | 中 | 高 |
注:分布式事務支持程度取決于所選中間件或自主實現(xiàn)的數(shù)據(jù)一致性保障機制
八、垂直分片的最佳實踐
8.1 數(shù)據(jù)模型設計
按業(yè)務領域劃分表
將相關性強的表分到同一個數(shù)據(jù)庫
盡量避免跨庫關聯(lián)查詢
使用冗余字段減少跨庫依賴
合理使用主鍵
避免使用自增主鍵(特別是在未來可能需要水平分片的場景)
考慮使用UUID或分布式ID生成器
建立合理的索引降低查詢壓力
數(shù)據(jù)冗余與一致性平衡
適當冗余關鍵數(shù)據(jù)降低跨庫查詢
建立數(shù)據(jù)同步機制保證最終一致性
區(qū)分強一致性場景和最終一致性場景
8.2 事務處理
本地事務處理
盡量將事務限制在單一數(shù)據(jù)庫內
單數(shù)據(jù)庫事務使用Spring的@Transactional注解
分布式事務策略
對于簡單場景:兩階段提交(XA)
對于高并發(fā)場景:TCC(Try-Confirm-Cancel)
對于長事務場景:Saga模式
考慮使用Seata等分布式事務框架
最終一致性實現(xiàn)
基于消息隊列的事件驅動架構
補償機制和重試策略
冪等設計確保操作可重復執(zhí)行
8.3 查詢優(yōu)化
減少跨庫查詢
合理劃分業(yè)務邊界,減少跨業(yè)務查詢需求
使用數(shù)據(jù)冗余避免頻繁跨庫查詢
考慮使用CQRS模式,為查詢場景構建專用視圖
查詢路由策略
分析查詢模式,優(yōu)化分片鍵選擇
對于復雜查詢,考慮使用查詢視圖或搜索引擎
合理使用緩存減少數(shù)據(jù)庫訪問
結果聚合處理
在應用層對多數(shù)據(jù)源結果進行聚合
使用并行查詢提高效率
結果分頁和懶加載減少數(shù)據(jù)傳輸量
以上就是SpringBoot實現(xiàn)垂直分片的六種策略的詳細內容,更多關于SpringBoot垂直分片的資料請關注腳本之家其它相關文章!
相關文章
Java爬蟲實現(xiàn)Jsoup利用dom方法遍歷Document對象
本文主要介紹了Java爬蟲實現(xiàn)Jsoup利用dom方法遍歷Document對象,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-05-05
Assert.assertNotNull()斷言是否是空問題
這篇文章主要介紹了Assert.assertNotNull()斷言是否是空問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-10-10
spring中WebClient如何設置連接超時時間以及讀取超時時間
這篇文章主要給大家介紹了關于spring中WebClient如何設置連接超時時間以及讀取超時時間的相關資料,WebClient是Spring框架5.0引入的基于響應式編程模型的HTTP客戶端,它提供一種簡便的方式來處理HTTP請求和響應,需要的朋友可以參考下2024-08-08

