问题:我们的一个新客户希望数据存储在他自己的国家(法律法规)。然而,我们使用分布在不同国家的几个数据中心的现有客户数据。
问:我们如何在不太改变现有Cassandra架构的情况下,将新客户的数据分离到其自己的国家?
潜在的解决方案#1:为该客户使用单独的密钥空间。关键字空间之间的模式是相同的,这增加了数据迁移的复杂性,等等。DataStax支持确认可以为每个区域配置keyspace。然而,我们使用的Spring Data Cassandra不允许动态选择keyspace。唯一的方法是使用CqlTemplate并在每次调用之前运行use keyspace blabla
,或者在表之前添加keyspaceselect*from blabla.mytable
,但这听起来像是一个黑客。
下面的示例和解释与GitHub中的相同
GitHub中的示例现在正在工作。未来最有效的解决方案似乎是使用存储库扩展。将很快更新下面的示例。
请注意,我最初发布的解决方案有一些缺陷,这些缺陷是我在JMeter测试中发现的。Datastax Java驱动html" target="_blank">程序参考建议避免通过session
对象设置keyspace。您必须在每个查询中显式设置keyspace。
我将首先定义如何在每个请求上设置租户ID。一个很好的例子是使用特定的HTTP头来定义REST API:
Tenant-Id: ACME
类似地,在每个远程协议上,您可以在每个消息上转发租户ID。假设您使用的是AMQP或JMS,您可以在消息头或属性中转发这个消息。
接下来,您应该在控制器中存储每个请求的传入头。您可以使用ThreadLocal
,也可以尝试使用请求范围的bean。
@Component
@Scope(scopeName = "request", proxyMode= ScopedProxyMode.TARGET_CLASS)
public class TenantId {
private String tenantId;
public void set(String id) {
this.tenantId = id;
}
public String get() {
return tenantId;
}
}
@RestController
public class UserController {
@Autowired
private UserRepository userRepo;
@Autowired
private TenantId tenantId;
@RequestMapping(value = "/userByName")
public ResponseEntity<String> getUserByUsername(
@RequestHeader("Tenant-ID") String tenantId,
@RequestParam String username) {
// Setting the tenant ID
this.tenantId.set(tenantId);
// Finding user
User user = userRepo.findOne(username);
return new ResponseEntity<>(user.getUsername(), HttpStatus.OK);
}
}
public class KeyspaceAwareCassandraRepository<T, ID extends Serializable>
extends SimpleCassandraRepository<T, ID> {
private final CassandraEntityInformation<T, ID> metadata;
private final CassandraOperations operations;
@Autowired
private TenantId tenantId;
public KeyspaceAwareCassandraRepository(
CassandraEntityInformation<T, ID> metadata,
CassandraOperations operations) {
super(metadata, operations);
this.metadata = metadata;
this.operations = operations;
}
private void injectDependencies() {
SpringBeanAutowiringSupport
.processInjectionBasedOnServletContext(this,
getServletContext());
}
private ServletContext getServletContext() {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
.getRequest().getServletContext();
}
@Override
public T findOne(ID id) {
injectDependencies();
CqlIdentifier primaryKey = operations.getConverter()
.getMappingContext()
.getPersistentEntity(metadata.getJavaType())
.getIdProperty().getColumnName();
Select select = QueryBuilder.select().all()
.from(tenantId.get(),
metadata.getTableName().toCql())
.where(QueryBuilder.eq(primaryKey.toString(), id))
.limit(1);
return operations.selectOne(select, metadata.getJavaType());
}
// All other overrides should be similar
}
@SpringBootApplication
@EnableCassandraRepositories(repositoryBaseClass = KeyspaceAwareCassandraRepository.class)
public class DemoApplication {
...
}
我已经用这个链接备份了我在卡桑德拉的密钥空间cassandra-backup.sh 为了恢复,我写了一个脚本,从包含快照的备份文件夹中复制内容,并粘贴到 /var/lib/cassandra/data/mykeypsace/下的相应目录中,但是当我看到mykeyspace的表内容时,没有恢复任何内容。例如,备份文件夹:path/mykeyspace/tableOne/snapshot/all-co
我有一个nxt请求帖子与表单url编码使用Feign客户端
问题内容: 我想知道是否有人尝试使用默认键空间构建cassandra docker镜像,但我尝试在BUILD时间内完成该操作,但由于cassandra不在该阶段运行,因此无法正常工作。这类似于以下内容: 我的新方法是从入口点脚本执行此操作,但是,如果其他人有更好的主意,我现在想。 快乐运输:D 问题答案: 今天解决了这个问题。构建映像,该映像将在修改之前附加一个修改过的默认Cassandra 将所
我正在尝试将以下结构存储在卡桑德拉中。 上面的大多数查询是 这就是为什么将()设置为主键很有用的原因。 根据docu,Cassandra的默认分区键是主键的第一列-在我的例子中是,但我想在Cassandr集群上均匀分布数据,我不能允许一个中的所有数据只存储在一个分区中,因为有些商店有10M条记录,有些只有1k条记录。 我可以设置()作为分区键,然后我可以达到Cassandra集群中记录的统一分布。
所以我有一张表,它看起来像这样: 我们依赖该表根据进行分页来正确排序。 问题是:当从cassandra返回结果时,看起来它们是根据ASCII值而不是逻辑的A-Z排序进行排序的。-对于观看它的人来说,这在程序上是有意义的,但在逻辑上是不合理的。 是否有一个选项来改变当前聚类顺序的方法? -或者另一种逻辑排序的方法?