接口优化从20s优化到500ms

前言

接口性能问题,对于从事后端开发的同学来说,是一个绕不开的话题。想要优化一个接口的性能,需要从多个方面着手。

本文将会接着接口性能优化这个话题,从实战的角度出发,聊聊我是如何优化一个慢查询接口的。

上周我优化了一下线上的批量评分查询接口,将接口性能从最初的20s,优化到目前的500ms以内。

1. 案发现场

我们每天早上上班前,都会收到一封线上慢查询接口汇总邮件,邮件中会展示接口地址调用次数最大耗时平均耗时traceId等信息。

我看到其中有一个批量评分查询接口,最大耗时达到了20s,平均耗时也有2s

skywalking查看该接口的调用信息,发现绝大数情况下,该接口响应还是比较快的,大部分情况都是500ms左右就能返回,但也有少部分超过了20s的请求。

这个现象就非常奇怪了。

莫非跟数据有关?

比如:要查某一个组织的数据,是非常快的。但如果要查平台,即组织的根节点,这种情况下,需要查询的数据量非常大,接口响应就可能会非常慢。

但事实证明不是这个原因。

很快有个同事给出了答案。

他们在结算单列表页面中,批量请求了这个接口,但他传参的数据量非常大。

怎么回事呢?

当初说的需求是这个接口给分页的列表页面调用,每页大小有:10、20、30、50、100,用户可以选择。

换句话说,调用批量评价查询接口,一次性最多可以查询100条记录。

但实际情况是:结算单列表页面还包含了很多订单。基本上每一个结算单,都有多个订单。调用批量评价查询接口时,需要把结算单和订单的数据合并到一起。

这样导致的结果是:调用批量评价查询接口时,一次性传入的参数非常多,入参list中包含几百、甚至几千条数据都有可能。

2. 现状

如果一次性传入几百或者几千个id,批量查询数据还好,可以走主键索引,查询效率也不至于太差。

但那个批量评分查询接口,逻辑不简单。

伪代码如下:

public List<ScoreEntity> query(List<SearchEntity> list) {
    //结果
    List<ScoreEntity> result = Lists.newArrayList();
    //获取组织id
    List<Long> orgIds = list.stream().map(SearchEntity::getOrgId).collect(Collectors.toList());
    //通过regin调用远程接口获取组织信息
    List<OrgEntity> orgList = feginClient.getOrgByIds(orgIds);
    
    for(SearchEntity entity : list) {
        //通过组织id找组织code
        String orgCode = findOrgCode(orgList, entity.getOrgId());
    
    
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这里给出一些优化建议: 1. 使用 fgets 函数代替 scanf 函数,可以避免输入字符串时出现空格等问题。 2. 在输入书的简介时,使用 fgets 函数,可以输入包含空格的多个单词。 3. 在输出书的信息时,使用更加清晰的格式,可以更好地展示书的信息,例如使用表格的形式。 4. 对于输入的各项信息,可以添加一些验证,确保输入的数据类型正确、输入的字符串不超过规定长度等。 5. 可以添加一些异常处理,例如输入错误时,输出相应的错误信息,而不是直接退出程序。 6. 可以使用动态数组来存储书的信息,避免书的数量达到上限后无法继续添加书的问题。 7. 可以使用文件来存储书的信息,避免程序关闭后信息丢失的问题。 下面给出一个修改后的代码,仅供参考: ```c #include <stdio.h> #include <string.h> #include <stdlib.h> #define MAX_DESCRIPTION 50 struct Book { char number[20]; char name[50]; char author[20]; float price; int quantity; char description[MAX_DESCRIPTION]; }; struct Book *books = NULL; int num_books = 0; int max_books = 0; void add_book() { if (num_books == max_books) { printf("Error: the maximum number of books has been reached.\n"); return; } struct Book new_book; printf("Enter the book number: "); fgets(new_book.number, sizeof(new_book.number), stdin); printf("Enter the book name: "); fgets(new_book.name, sizeof(new_book.name), stdin); printf("Enter the book author: "); fgets(new_book.author, sizeof(new_book.author), stdin); printf("Enter the book price: "); scanf("%f", &new_book.price); printf("Enter the book quantity: "); scanf("%d", &new_book.quantity); printf("Enter the book description (50 characters or less): "); fgets(new_book.description, sizeof(new_book.description), stdin); fgets(new_book.description, sizeof(new_book.description), stdin); if (strlen(new_book.number) == 0 || strlen(new_book.name) == 0 || strlen(new_book.author) == 0 || new_book.price <= 0 || new_book.quantity <= 0 || strlen(new_book.description) == 0) { printf("Error: invalid input.\n"); return; } books[num_books] = new_book; num_books++; printf("The book has been added successfully.\n"); } void search_book() { char keyword[50]; printf("Enter the keyword to search: "); scanf("%s", keyword); int found = 0; printf("+----------------------------------------+\n"); printf("| %-10s | %-20s | %-10s |\n", "Book Number", "Book Name", "Book Author"); printf("+----------------------------------------+\n"); for (int i = 0; i < num_books; i++) { if (strstr(books[i].name, keyword) != NULL || strstr(books[i].author, keyword) != NULL) { printf("| %-10s | %-20s | %-10s |\n", books[i].number, books[i].name, books[i].author); found = 1; } } printf("+----------------------------------------+\n"); if (!found) { printf("No matching books found.\n"); } } void list_books() { if (num_books == 0) { printf("No books found.\n"); return; } printf("+------------+----------------------+------------+----------+----------+----------------------+\n"); printf("| Book Number | Book Name | Book Author | Price | Quantity | Description |\n"); printf("+------------+----------------------+------------+----------+----------+----------------------+\n"); for (int i = 0; i < num_books; i++) { printf("| %-10s | %-20s | %-10s | %-8.2f | %-8d | %-20s |\n", books[i].number, books[i].name, books[i].author, books[i].price, books[i].quantity, books[i].description); } printf("+------------+----------------------+------------+----------+----------+----------------------+\n"); } void load_books() { FILE *fp = fopen("books.dat", "rb"); if (fp == NULL) { printf("Error: cannot open file books.dat.\n"); return; } fread(&num_books, sizeof(int), 1, fp); if (num_books > 0) { max_books = num_books; books = malloc(num_books * sizeof(struct Book)); fread(books, sizeof(struct Book), num_books, fp); } fclose(fp); } void save_books() { FILE *fp = fopen("books.dat", "wb"); if (fp == NULL) { printf("Error: cannot open file books.dat.\n"); return; } fwrite(&num_books, sizeof(int), 1, fp); if (num_books > 0) { fwrite(books, sizeof(struct Book), num_books, fp); } fclose(fp); } void free_books() { if (books != NULL) { free(books); } } int main() { load_books(); while (1) { printf("----------------------------------------\n"); printf("1. Add Book\n"); printf("2. Search Book\n"); printf("3. List Books\n"); printf("4. Exit\n"); printf("----------------------------------------\n"); printf("Enter your choice: "); int choice; scanf("%d", &choice); switch (choice) { case 1: add_book(); break; case 2: search_book(); break; case 3: list_books(); break; case 4: save_books(); free_books(); exit(0); default: printf("Error: invalid choice.\n"); break; } } return 0; } ``` 这里使用了动态数组来存储书的信息,如果需要存储更多的书,可以通过重新分配内存来扩展数组的大小。同时,使用了文件来存储书的信息,程序启动时会从文件中读取已有的书的信息,程序退出时会将所有书的信息写入文件中。这样可以确保即使程序关闭,书的信息也不会丢失。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值