【发布时间】:2021-02-28 18:53:15
【问题描述】:
我有一个在 Spring 上运行的 Java 应用程序,它有一个创建发票的服务,每张发票有 10 次读写。但是我们无法让它通过 150TPS(每秒事务数),硬件没有达到 30% 的容量,我们将 maxpool 大小设置为 300,DB 设置为 3000 i/o,我们没有看到任何改进,我不确定它代码或配置
public class InvoiceHomeService {
private final Logger log = LoggerFactory.getLogger(InvoiceHomeService.class);
private final DosageService dosageService;
private final DosageRepository dosageRepository;
private final InvoiceService invoiceService;
private final ApplicationProperties applicationProperties;
public Invoice create(Company company,
CreateInvoiceHomeRequest request,
Branch branch,
EconomicActivity economicActivity,
String modalityId) throws DosageNotAvailableException, DateOutRangeException {
Sorter invoiceType = new Sorter(SortersConstants.HOME);
DosageTransaction dosageTransaction = getDosageTransaction(request, company, economicActivity, invoiceType, modalityId);
Invoice invoice = new Invoice();
/* Critital information */
invoice.setExternalId(request.getId());
invoice.setInvoiceType(invoiceType);
invoice.setInvoiceMethod(new Sorter(SortersConstants.IM_VIRTUAL));
invoice.setTotalAnticipatedPayment(BigDecimal.ZERO);
/* Basic information */
invoice.setContractId(request.getContractId());
// invoice.setCustomerId(request.getCustomerId());
invoice.setBillingPeriod(request.getBillingPeriod());
invoice.setVoucherNumber(request.getVoucherNumber());
invoice.setVoucherType(request.getVoucherType());
// invoice.setVoucherSerial(request.getVoucherSerial());
invoice.setVoucherState(request.getVoucherState());
invoice.setPaymentType(request.getTypeOfPayment());
invoice.setEmailNotification(request.getEmailNotification());
invoice.setPhoneNumberNotification(request.getPhoneNumberNotification());
invoice.setIsTigo(request.getIsTigo());
invoice.setPersonType(request.getTypeOfPerson());
/* Extras information */
// invoice.setExtraPhoneLine(request.getExtraPhoneLine());
// invoice.setExtraPlan(request.getExtraPlan());
invoice.setExtraCustomerAddress(request.getExtraCustomerAddress());
invoice.setExtraPeriodStartdate(request.getExtraPeriodStartdate());
invoice.setExtraPeriodEnddate(request.getExtraPeriodEnddate());
invoice.setExtraPaydayLimit(request.getExtraPaymentDeadline());
invoice.setExtraServiceInterruptionDate(request.getExtraServiceInterruptionDate());
invoice.setExtraPeriodDays(request.getExtraPeriodDays());
/* Customer Information */
invoice.setNitCustomer(request.getNitCustomer());
invoice.setSocialReason(request.getSocialReason());
/* Invoice template */
invoice.setInvoiceTemplate(JasperSingleton.INVOICE_TEMPLATE_HOME_VERSION);
Set<InvoiceDetails> details = new HashSet<>();
for (CreateInvoiceDetailsHomeRequest detail : request.getDetails()) {
InvoiceDetails item = new InvoiceDetails();
item.setQuantity(detail.getQuantity());
item.setConcept(detail.getConcept());
item.setUnitPrice(detail.getUnitPrice());
item.setSequence(detail.getSequence());
item.setSubtotal(detail.getSubtotal());
item.setExtraPeriod(detail.getExtraPeriod());
details.add(item);
}
invoice.setDetails(details);
invoice = invoiceService.createInvoice(
invoice,
dosageTransaction.getDosage(),
company,
branch,
economicActivity,
dosageTransaction.getSequence(),
request.getEmissionDate(),
request.getEmissionDate(),
request.getTotalAmount(),
economicActivity.getType()
);
return invoice;
}
public synchronized DosageTransaction getDosageTransaction(CreateInvoiceHomeRequest request, Company company, EconomicActivity economicActivity, Sorter invoiceType, String modalityId) throws DosageNotAvailableException, DateOutRangeException {
Optional<Dosage> optionalDosage = dosageService.getDosageActive(company.getId(), invoiceType.getSequence(),
economicActivity.getId(), SortersConstants.DT_CYCLE, modalityId, invoiceType.getId());
if (!optionalDosage.isPresent()) throw new DosageNotAvailableException();
Dosage dosage = optionalDosage.get();
if (!request.getEmissionDate().isAfter(dosage.getStartDate().minusDays(1)) ||
!request.getEmissionDate().isBefore(dosage.getDeadlineDate().plusDays(1))) throw new DateOutRangeException();
if (modalityId.equalsIgnoreCase(SortersConstants.DM_CICLICAL) && dosage.getSequence() > applicationProperties.getDosageConfig().getMaxInvoicePerDosage().longValue()) {
dosage.setState(new Sorter(SortersConstants.DS_LOCKED));
dosage = dosageRepository.save(dosage);
log.info("Change state dosage: {}, state: {}", dosage.getId(), dosage.getState().getId());
return getDosageTransaction(request, company, economicActivity, invoiceType, modalityId);
}
Long sequence = invoiceService.getSequenceDosageSync(dosage.getId());
return new DosageTransaction(dosage, sequence);
}
}
【问题讨论】:
-
那么为什么你认为你需要 300 TPS?您是否正在尝试满足某些特定的软件要求?目标不一定是使 CPU 利用率饱和;可能还有其他限制因素。建立另一个 AWS 实例不是更容易吗?
-
是的,我们需要满足每秒 300 个事务来处理负载,集群不是一个选项。
-
使用序列会影响性能,因为它需要为每个事务锁定序列表。它是一个缓存序列还是可能在插入语句中调用
nextval? -
那么,您可以使用哪些分析工具?在任何其他普通应用程序中,我要做的第一件事就是测量。
-
为什么要同步getDosageTransaction?如果没有,会发生什么?您是否测量了您的网络活动以及往返需要多长时间?事务边界是什么?
标签: java performance spring-data database-concurrency