cari
RumahJavajavaTutorialMembina API Berdaya Tahan: Kesilapan yang Saya Buat dan Cara Saya Mengatasinya

Building Resilient APIs: Mistakes I Made and How I Overcame Them

API ialah tulang belakang aplikasi moden. Apabila saya mula membina API dengan Spring Boot, saya sangat tertumpu pada penyampaian ciri sehingga saya terlepas pandang satu aspek penting: daya tahan. Saya belajar dengan susah payah bahawa keupayaan API untuk menangani kegagalan dengan anggun dan menyesuaikan diri dengan keadaan yang berbeza adalah yang menjadikannya benar-benar boleh dipercayai. Izinkan saya membawa anda melalui beberapa kesilapan yang saya lakukan sepanjang perjalanan dan cara saya membetulkannya. Mudah-mudahan, anda boleh mengelakkan perangkap ini dalam perjalanan anda sendiri.

Kesilapan 1: Mengabaikan Konfigurasi Tamat Masa

Perkara yang Berlaku: Dalam salah satu projek awal saya, saya membina API yang membuat panggilan luaran kepada perkhidmatan pihak ketiga. Saya menganggap perkhidmatan tersebut akan sentiasa bertindak balas dengan cepat dan tidak mengganggu menetapkan tamat masa. Semuanya kelihatan baik sehingga trafik meningkat, dan perkhidmatan pihak ketiga mula perlahan. API saya hanya akan tergantung selama-lamanya, menunggu jawapan.

Impak: Responsif API semakin merosot. Perkhidmatan bergantung mula gagal, dan pengguna menghadapi kelewatan yang lama—malah ada yang mendapat Ralat Pelayan Dalaman 500 yang digeruni.

Cara Saya Membetulkannya: Ketika itulah saya menyedari kepentingan konfigurasi tamat masa. Begini cara saya membetulkannya menggunakan Spring Boot:

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder
                .setConnectTimeout(Duration.ofSeconds(5))
                .setReadTimeout(Duration.ofSeconds(5))
                .additionalInterceptors(new RestTemplateLoggingInterceptor())
                .build();
    }

    // Custom interceptor to log request/response details
    @RequiredArgsConstructor
    public class RestTemplateLoggingInterceptor implements ClientHttpRequestInterceptor {
        private static final Logger log = LoggerFactory.getLogger(RestTemplateLoggingInterceptor.class);

        @Override
        public ClientHttpResponse intercept(HttpRequest request, byte[] body, 
                                          ClientHttpRequestExecution execution) throws IOException {
            long startTime = System.currentTimeMillis();
            log.info("Making request to: {}", request.getURI());

            ClientHttpResponse response = execution.execute(request, body);

            long duration = System.currentTimeMillis() - startTime;
            log.info("Request completed in {}ms with status: {}", 
                    duration, response.getStatusCode());

            return response;
        }
    }
}

Konfigurasi ini bukan sahaja menetapkan tamat masa yang sesuai tetapi juga termasuk pengelogan untuk membantu memantau prestasi perkhidmatan luaran.

Kesilapan 2: Tidak Melaksanakan Pemutus Litar

Apa Yang Berlaku: Ada masanya perkhidmatan dalaman kami yang kami harapkan merosot selama beberapa jam. API saya tidak mengendalikan keadaan dengan baik. Sebaliknya, ia terus mencuba semula permintaan yang gagal itu, menambah lebih banyak beban pada sistem yang sudah tertekan.

Kegagalan berlatarkan adalah salah satu masalah yang paling mencabar dalam sistem teragih. Apabila satu perkhidmatan gagal, ia boleh mencipta kesan domino yang menjatuhkan keseluruhan sistem.

Kesan: Percubaan semula berulang mengatasi sistem, memperlahankan bahagian lain aplikasi dan menjejaskan semua pengguna.

Cara Saya Membetulkannya: Ketika itulah saya menemui corak pemutus litar. Menggunakan Spring Cloud Resilience4j, saya dapat memecahkan kitaran.

@Configuration
public class Resilience4jConfig {

    @Bean
    public CircuitBreakerConfig circuitBreakerConfig() {
        return CircuitBreakerConfig.custom()
                .failureRateThreshold(50)
                .waitDurationInOpenState(Duration.ofSeconds(60))
                .permittedNumberOfCallsInHalfOpenState(2)
                .slidingWindowSize(2)
                .build();
    }

    @Bean
    public RetryConfig retryConfig() {
        return RetryConfig.custom()
                .maxAttempts(3)
                .waitDuration(Duration.ofSeconds(2))
                .build();
    }
}

@Service
@Slf4j
public class ResilientService {

    private final CircuitBreaker circuitBreaker;
    private final RestTemplate restTemplate;

    public ResilientService(CircuitBreakerRegistry registry, RestTemplate restTemplate) {
        this.circuitBreaker = registry.circuitBreaker("internalService");
        this.restTemplate = restTemplate;
    }

    @CircuitBreaker(name = "internalService", fallbackMethod = "fallbackResponse")
    @Retry(name = "internalService")
    public String callInternalService() {
        return restTemplate.getForObject("https://internal-service.com/data", String.class);
    }

    public String fallbackResponse(Exception ex) {
        log.warn("Circuit breaker activated, returning fallback response", ex);
        return new FallbackResponse("Service temporarily unavailable", 
                                  getBackupData()).toJson();
    }

    private Object getBackupData() {
        // Implement cache or default data strategy
        return new CachedDataService().getLatestValidData();
    }
}

Tambahan mudah ini menghalang API saya daripada mengatasi dirinya sendiri, perkhidmatan dalaman atau perkhidmatan pihak ketiga, memastikan kestabilan sistem.

Kesilapan 3: Pengendalian Ralat yang Lemah

Apa yang Berlaku: Pada awalnya, saya tidak terlalu memikirkan tentang pengendalian ralat. API saya sama ada melemparkan ralat generik (seperti HTTP 500 untuk segala-galanya) atau mendedahkan butiran dalaman sensitif dalam surih tindanan.

Impak: Pengguna keliru tentang perkara yang salah dan pendedahan butiran dalaman mewujudkan potensi risiko keselamatan.

Cara Saya Membetulkannya: Saya memutuskan untuk memusatkan pengendalian ralat menggunakan anotasi @ControllerAdvice Spring. Inilah yang saya lakukan:

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder
                .setConnectTimeout(Duration.ofSeconds(5))
                .setReadTimeout(Duration.ofSeconds(5))
                .additionalInterceptors(new RestTemplateLoggingInterceptor())
                .build();
    }

    // Custom interceptor to log request/response details
    @RequiredArgsConstructor
    public class RestTemplateLoggingInterceptor implements ClientHttpRequestInterceptor {
        private static final Logger log = LoggerFactory.getLogger(RestTemplateLoggingInterceptor.class);

        @Override
        public ClientHttpResponse intercept(HttpRequest request, byte[] body, 
                                          ClientHttpRequestExecution execution) throws IOException {
            long startTime = System.currentTimeMillis();
            log.info("Making request to: {}", request.getURI());

            ClientHttpResponse response = execution.execute(request, body);

            long duration = System.currentTimeMillis() - startTime;
            log.info("Request completed in {}ms with status: {}", 
                    duration, response.getStatusCode());

            return response;
        }
    }
}

Ini menjadikan mesej ralat jelas dan selamat, membantu pengguna dan pembangun.

Kesilapan 4: Mengabaikan Had Kadar

Perkara yang Berlaku: Pada suatu hari yang baik, kami melancarkan kempen promosi dan trafik ke API kami meningkat. Walaupun ini merupakan berita baik untuk perniagaan, sesetengah pengguna mula menghantar spam kepada API dengan permintaan, menyebabkan orang lain kelaparan sumber.

Impak: Prestasi merosot untuk semua orang, dan kami menerima banyak aduan.

Cara Saya Membetulkannya: Untuk mengendalikan perkara ini, saya melaksanakan pengehadan kadar menggunakan Bucket4j dengan Redis. Berikut ialah contoh:

@Configuration
public class Resilience4jConfig {

    @Bean
    public CircuitBreakerConfig circuitBreakerConfig() {
        return CircuitBreakerConfig.custom()
                .failureRateThreshold(50)
                .waitDurationInOpenState(Duration.ofSeconds(60))
                .permittedNumberOfCallsInHalfOpenState(2)
                .slidingWindowSize(2)
                .build();
    }

    @Bean
    public RetryConfig retryConfig() {
        return RetryConfig.custom()
                .maxAttempts(3)
                .waitDuration(Duration.ofSeconds(2))
                .build();
    }
}

@Service
@Slf4j
public class ResilientService {

    private final CircuitBreaker circuitBreaker;
    private final RestTemplate restTemplate;

    public ResilientService(CircuitBreakerRegistry registry, RestTemplate restTemplate) {
        this.circuitBreaker = registry.circuitBreaker("internalService");
        this.restTemplate = restTemplate;
    }

    @CircuitBreaker(name = "internalService", fallbackMethod = "fallbackResponse")
    @Retry(name = "internalService")
    public String callInternalService() {
        return restTemplate.getForObject("https://internal-service.com/data", String.class);
    }

    public String fallbackResponse(Exception ex) {
        log.warn("Circuit breaker activated, returning fallback response", ex);
        return new FallbackResponse("Service temporarily unavailable", 
                                  getBackupData()).toJson();
    }

    private Object getBackupData() {
        // Implement cache or default data strategy
        return new CachedDataService().getLatestValidData();
    }
}

Ini memastikan penggunaan yang adil dan melindungi API daripada penyalahgunaan.

Kesilapan 5: Mengabaikan Kebolehmerhatian

Apa yang Berlaku: Setiap kali berlaku masalah dalam pengeluaran, ia seperti mencari jarum dalam timbunan jerami. Saya tidak mempunyai pengelogan atau metrik yang betul, jadi mendiagnosis isu mengambil masa yang lebih lama daripada yang sepatutnya.

Impak: Penyelesaian masalah menjadi mimpi ngeri, menangguhkan penyelesaian isu dan mengecewakan pengguna.

Cara Saya Membetulkannya: Saya menambahkan Spring Boot Actuator untuk pemeriksaan kesihatan dan menyepadukan Prometheus dengan Grafana untuk visualisasi metrik:

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(HttpClientErrorException.class)
    public ResponseEntity<errorresponse> handleHttpClientError(HttpClientErrorException ex, 
                                                             WebRequest request) {
        log.error("Client error occurred", ex);

        ErrorResponse error = ErrorResponse.builder()
                .timestamp(LocalDateTime.now())
                .status(ex.getStatusCode().value())
                .message(sanitizeErrorMessage(ex.getMessage()))
                .path(((ServletWebRequest) request).getRequest().getRequestURI())
                .build();

        return ResponseEntity.status(ex.getStatusCode()).body(error);
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<errorresponse> handleGeneralException(Exception ex, 
                                                              WebRequest request) {
        log.error("Unexpected error occurred", ex);

        ErrorResponse error = ErrorResponse.builder()
                .timestamp(LocalDateTime.now())
                .status(HttpStatus.INTERNAL_SERVER_ERROR.value())
                .message("An unexpected error occurred. Please try again later.")
                .path(((ServletWebRequest) request).getRequest().getRequestURI())
                .build();

        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
    }

    private String sanitizeErrorMessage(String message) {
        // Remove sensitive information from error messages
        return message.replaceAll("(password|secret|key)=\[.*?\]", "=[REDACTED]");
    }
}
</errorresponse></errorresponse>

Saya juga melaksanakan pengelogan berstruktur menggunakan ELK Stack (Elasticsearch, Logstash, Kibana). Ini menjadikan log lebih mudah diambil tindakan.

Bawa pulang

Membina API yang berdaya tahan adalah satu perjalanan dan kesilapan adalah sebahagian daripada proses. Berikut ialah pengajaran utama yang saya pelajari:

  1. Sentiasa konfigurasi tamat masa untuk panggilan luaran.
  2. Gunakan pemutus litar untuk mengelakkan kegagalan lata.
  3. Memusatkan pengendalian ralat untuk menjadikannya jelas dan selamat.
  4. Laksanakan pengehadan kadar untuk mengurus lonjakan trafik.

Perubahan ini mengubah cara saya mendekati pembangunan API. Jika anda pernah menghadapi cabaran yang sama atau mempunyai petua lain, saya ingin mendengar cerita anda!

Nota Akhir: Ingat bahawa daya tahan bukanlah ciri yang anda tambah—ia adalah ciri yang anda bina ke dalam sistem anda dari bawah. Setiap komponen ini memainkan peranan penting dalam mencipta API yang bukan sahaja berfungsi tetapi terus berfungsi dengan pasti di bawah tekanan.

Atas ialah kandungan terperinci Membina API Berdaya Tahan: Kesilapan yang Saya Buat dan Cara Saya Mengatasinya. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Bagaimanakah saya melaksanakan caching pelbagai peringkat dalam aplikasi java menggunakan perpustakaan seperti kafein atau cache jambu?Bagaimanakah saya melaksanakan caching pelbagai peringkat dalam aplikasi java menggunakan perpustakaan seperti kafein atau cache jambu?Mar 17, 2025 pm 05:44 PM

Artikel ini membincangkan pelaksanaan caching pelbagai peringkat di Java menggunakan kafein dan cache jambu untuk meningkatkan prestasi aplikasi. Ia meliputi persediaan, integrasi, dan faedah prestasi, bersama -sama dengan Pengurusan Dasar Konfigurasi dan Pengusiran PRA Terbaik

Bagaimanakah saya dapat melaksanakan teknik pengaturcaraan berfungsi di Java?Bagaimanakah saya dapat melaksanakan teknik pengaturcaraan berfungsi di Java?Mar 11, 2025 pm 05:51 PM

Artikel ini meneroka mengintegrasikan pengaturcaraan berfungsi ke dalam Java menggunakan ekspresi Lambda, API Streams, rujukan kaedah, dan pilihan. Ia menyoroti faedah seperti kebolehbacaan dan kebolehkerjaan kod yang lebih baik melalui kesimpulan dan kebolehubahan

Bagaimanakah mekanisme kelas muatan Java berfungsi, termasuk kelas yang berbeza dan model delegasi mereka?Bagaimanakah mekanisme kelas muatan Java berfungsi, termasuk kelas yang berbeza dan model delegasi mereka?Mar 17, 2025 pm 05:35 PM

Kelas kelas Java melibatkan pemuatan, menghubungkan, dan memulakan kelas menggunakan sistem hierarki dengan bootstrap, lanjutan, dan pemuat kelas aplikasi. Model delegasi induk memastikan kelas teras dimuatkan dahulu, yang mempengaruhi LOA kelas tersuai

Bagaimanakah saya boleh menggunakan JPA (Java Constence API) untuk pemetaan objek-objek dengan ciri-ciri canggih seperti caching dan malas malas?Bagaimanakah saya boleh menggunakan JPA (Java Constence API) untuk pemetaan objek-objek dengan ciri-ciri canggih seperti caching dan malas malas?Mar 17, 2025 pm 05:43 PM

Artikel ini membincangkan menggunakan JPA untuk pemetaan objek-relasi dengan ciri-ciri canggih seperti caching dan pemuatan malas. Ia meliputi persediaan, pemetaan entiti, dan amalan terbaik untuk mengoptimumkan prestasi sambil menonjolkan potensi perangkap. [159 aksara]

Bagaimanakah saya menggunakan Maven atau Gradle untuk Pengurusan Projek Java Lanjutan, Membina Automasi, dan Resolusi Ketergantungan?Bagaimanakah saya menggunakan Maven atau Gradle untuk Pengurusan Projek Java Lanjutan, Membina Automasi, dan Resolusi Ketergantungan?Mar 17, 2025 pm 05:46 PM

Artikel ini membincangkan menggunakan Maven dan Gradle untuk Pengurusan Projek Java, membina automasi, dan resolusi pergantungan, membandingkan pendekatan dan strategi pengoptimuman mereka.

Bagaimana saya menggunakan API Java's Nio (Input/Output Baru) untuk I/O yang tidak menyekat?Bagaimana saya menggunakan API Java's Nio (Input/Output Baru) untuk I/O yang tidak menyekat?Mar 11, 2025 pm 05:51 PM

Artikel ini menerangkan NIO API Java untuk I/O yang tidak menyekat, menggunakan pemilih dan saluran untuk mengendalikan pelbagai sambungan dengan cekap dengan satu benang. Ia memperincikan proses, faedah (skalabilitas, prestasi), dan potensi perangkap (kerumitan,

Bagaimanakah saya membuat dan menggunakan perpustakaan Java Custom (fail JAR) dengan pengurusan versi dan pergantungan yang betul?Bagaimanakah saya membuat dan menggunakan perpustakaan Java Custom (fail JAR) dengan pengurusan versi dan pergantungan yang betul?Mar 17, 2025 pm 05:45 PM

Artikel ini membincangkan membuat dan menggunakan perpustakaan Java tersuai (fail balang) dengan pengurusan versi dan pergantungan yang betul, menggunakan alat seperti Maven dan Gradle.

Bagaimana saya menggunakan API Soket Java untuk komunikasi rangkaian?Bagaimana saya menggunakan API Soket Java untuk komunikasi rangkaian?Mar 11, 2025 pm 05:53 PM

Artikel ini memperincikan API soket Java untuk komunikasi rangkaian, yang meliputi persediaan pelanggan-pelayan, pengendalian data, dan pertimbangan penting seperti pengurusan sumber, pengendalian ralat, dan keselamatan. Ia juga meneroka teknik pengoptimuman prestasi, i

See all articles

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

AI Hentai Generator

AI Hentai Generator

Menjana ai hentai secara percuma.

Artikel Panas

R.E.P.O. Kristal tenaga dijelaskan dan apa yang mereka lakukan (kristal kuning)
3 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Tetapan grafik terbaik
3 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Cara Memperbaiki Audio Jika anda tidak dapat mendengar sesiapa
3 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌

Alat panas

mPDF

mPDF

mPDF ialah perpustakaan PHP yang boleh menjana fail PDF daripada HTML yang dikodkan UTF-8. Pengarang asal, Ian Back, menulis mPDF untuk mengeluarkan fail PDF "dengan cepat" dari tapak webnya dan mengendalikan bahasa yang berbeza. Ia lebih perlahan dan menghasilkan fail yang lebih besar apabila menggunakan fon Unicode daripada skrip asal seperti HTML2FPDF, tetapi menyokong gaya CSS dsb. dan mempunyai banyak peningkatan. Menyokong hampir semua bahasa, termasuk RTL (Arab dan Ibrani) dan CJK (Cina, Jepun dan Korea). Menyokong elemen peringkat blok bersarang (seperti P, DIV),

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Dreamweaver Mac版

Dreamweaver Mac版

Alat pembangunan web visual

EditPlus versi Cina retak

EditPlus versi Cina retak

Saiz kecil, penyerlahan sintaks, tidak menyokong fungsi gesaan kod

Pelayar Peperiksaan Selamat

Pelayar Peperiksaan Selamat

Pelayar Peperiksaan Selamat ialah persekitaran pelayar selamat untuk mengambil peperiksaan dalam talian dengan selamat. Perisian ini menukar mana-mana komputer menjadi stesen kerja yang selamat. Ia mengawal akses kepada mana-mana utiliti dan menghalang pelajar daripada menggunakan sumber yang tidak dibenarkan.