From 7fc315933eebb2f89aa19d33041a1a007e5081bc Mon Sep 17 00:00:00 2001 From: Ghost_chu Date: Tue, 8 Oct 2024 20:36:04 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=9B=B4=E5=A4=9A=E8=BF=BD?= =?UTF-8?q?=E8=B8=AA=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/tracker/TrackerController.java | 22 ++++++++++++--- .../module/tracker/TrackerService.java | 28 +++++++++++++++++-- .../internal/TrackedPeerRepository.java | 6 ++++ src/main/resources/application.properties | 1 + 4 files changed, 51 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/ghostchu/btn/sparkle/module/tracker/TrackerController.java b/src/main/java/com/ghostchu/btn/sparkle/module/tracker/TrackerController.java index 7cfaf9e..4974695 100644 --- a/src/main/java/com/ghostchu/btn/sparkle/module/tracker/TrackerController.java +++ b/src/main/java/com/ghostchu/btn/sparkle/module/tracker/TrackerController.java @@ -7,6 +7,7 @@ import com.ghostchu.btn.sparkle.util.BencodeUtil; import inet.ipaddr.IPAddress; import inet.ipaddr.IPAddressString; +import io.micrometer.core.instrument.MeterRegistry; import jakarta.persistence.LockModeType; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -45,6 +46,8 @@ public class TrackerController extends SparkleController { @Autowired private AuditService auditService; + private MeterRegistry meterRegistry; + public static String compactPeers(List peers, boolean isV6) throws IllegalStateException { ByteBuffer buffer = ByteBuffer.allocate((isV6 ? 18 : 6) * peers.size()); for (TrackerService.Peer peer : peers) { @@ -90,7 +93,9 @@ public static List extractInfoHashes(String queryString) { @Transactional @Lock(LockModeType.WRITE) public byte[] announce() { + tickMetrics("announce_req", 1); if (req.getQueryString() == null) { + tickMetrics("announce_req_fails", 1); return "Sorry, This is a BitTorrent Tracker, and access announce endpoint via Browser is disallowed and useless.".getBytes(StandardCharsets.UTF_8); } if (ua(req) != null) { @@ -100,6 +105,7 @@ public byte[] announce() { || ua(req).contains("Safari") || ua(req).contains("Edge") || ua(req).contains("Opera")) { + tickMetrics("announce_req_fails", 1); return "Sorry, This is a BitTorrent Tracker, and access announce endpoint via Browser is disallowed and useless.".getBytes(StandardCharsets.UTF_8); } } @@ -153,7 +159,9 @@ public byte[] announce() { } } var peers = trackerService.fetchPeersFromTorrent(infoHash, peerId, null, numWant); - + tickMetrics("announce_provided_peers", peers.v4().size() + peers.v6().size()); + tickMetrics("announce_provided_peers_ipv4", peers.v4().size()); + tickMetrics("announce_provided_peers_ipv6", peers.v6().size()); // 合成响应 var map = new HashMap<>() {{ put("interval", announceInterval / 1000); @@ -178,6 +186,7 @@ public byte[] announce() { }}); } }}; + tickMetrics("announce_req_success", 1); auditService.log(req, "TRACKER_ANNOUNCE", true, Map.of("hash", infoHash, "user-agent", ua(req))); return BencodeUtil.INSTANCE.encode(map); } @@ -191,9 +200,9 @@ public ResponseEntity scrape() { for (byte[] infoHash : infoHashes) { files.put(new String(infoHash, StandardCharsets.ISO_8859_1), new TreeMap<>() {{ var peers = trackerService.scrape(infoHash); - put("complete", peers.seeders() + 15); - put("incomplete", peers.leechers() + 15); - put("downloaded", peers.downloaded() + 15); + put("complete", peers.seeders()); + put("incomplete", peers.leechers()); + put("downloaded", peers.downloaded()); }}); } map.put("files", files); @@ -217,6 +226,11 @@ public List getPossiblePeerIps(HttpServletRequest req) { return found; } + + private void tickMetrics(String service, double increment) { + meterRegistry.counter("sparkle_tracker_" + service).increment(increment); + } + private record SparkleTrackerMetricsMessage( long seeders, long leechers, diff --git a/src/main/java/com/ghostchu/btn/sparkle/module/tracker/TrackerService.java b/src/main/java/com/ghostchu/btn/sparkle/module/tracker/TrackerService.java index 9f3f639..7fb2843 100644 --- a/src/main/java/com/ghostchu/btn/sparkle/module/tracker/TrackerService.java +++ b/src/main/java/com/ghostchu/btn/sparkle/module/tracker/TrackerService.java @@ -4,6 +4,8 @@ import com.ghostchu.btn.sparkle.util.ByteUtil; import com.ghostchu.btn.sparkle.util.TimeUtil; import com.ghostchu.btn.sparkle.util.ipdb.GeoIPManager; +import io.micrometer.core.instrument.Counter; +import io.micrometer.core.instrument.MeterRegistry; import jakarta.transaction.Transactional; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -30,17 +32,36 @@ public class TrackerService { private final long inactiveInterval; private final int maxPeersReturn; private final GeoIPManager geoIPManager; - + private final Counter announceCounter; + private final Counter peersFetchCounter; + private final Counter scrapeCounter; + private final MeterRegistry meterRegistry; public TrackerService(TrackedPeerRepository trackedPeerRepository, TrackedTaskRepository trackedTaskRepository, @Value("${service.tracker.inactive-interval}") long inactiveInterval, - @Value("${service.tracker.max-peers-return}") int maxPeersReturn, GeoIPManager geoIPManager) { + @Value("${service.tracker.max-peers-return}") int maxPeersReturn, GeoIPManager geoIPManager, + MeterRegistry meterRegistry) { this.trackedPeerRepository = trackedPeerRepository; this.trackedTaskRepository = trackedTaskRepository; this.inactiveInterval = inactiveInterval; this.maxPeersReturn = maxPeersReturn; this.geoIPManager = geoIPManager; + this.meterRegistry = meterRegistry; + this.announceCounter = meterRegistry.counter("sparkle_tracker_announce"); + this.peersFetchCounter = meterRegistry.counter("sparkle_tracker_peers_fetch"); + this.scrapeCounter = meterRegistry.counter("sparkle_tracker_scrape"); + } + + @Scheduled(fixedDelayString = "${service.tracker.metrics-interval}") + @Transactional + public void updateTrackerMetrics() { + var totalPeers = meterRegistry.gauge("sparkle_tracker_tracking_total_peers", trackedPeerRepository.count()); + var uniquePeers = meterRegistry.gauge("sparkle_tracker_tracking_unique_peers", trackedPeerRepository.countDistinctByPeerId()); + var uniqueIps = meterRegistry.gauge("sparkle_tracker_tracking_unique_ips", trackedPeerRepository.countDistinctByPeerIp()); + var activeTasks = meterRegistry.gauge("sparkle_tracker_tracking_tasks", trackedPeerRepository.countDistinctByTorrentInfoHash()); + var totalTasks = meterRegistry.gauge("sparkle_tracker_tracking_tasks", trackedTaskRepository.count()); + log.info("[Tracker 实时] 总Peer: {}, 唯一Peer: {}, 唯一IP: {}, 活动种子: {}, 种子总数: {}", totalPeers, uniquePeers, uniqueIps, activeTasks, totalTasks); } @Scheduled(fixedDelayString = "${service.tracker.cleanup-interval}") @@ -52,6 +73,7 @@ public void cleanup() { @Async public void executeAnnounce(PeerAnnounce announce) { + announceCounter.increment(); var trackedPeer = trackedPeerRepository.findByPeerIpAndPeerIdAndTorrentInfoHash( announce.peerIp(), ByteUtil.filterUTF8(ByteUtil.bytesToHex(announce.peerId())), @@ -121,6 +143,7 @@ public void executeAnnounce(PeerAnnounce announce) { @Cacheable(value = {"peers#3000"}, key = "#torrentInfoHash") public TrackedPeerList fetchPeersFromTorrent(byte[] torrentInfoHash, byte[] peerId, InetAddress peerIp, int numWant) { + peersFetchCounter.increment(); List v4 = new ArrayList<>(); List v6 = new ArrayList<>(); int seeders = 0; @@ -149,6 +172,7 @@ public TrackedPeerList fetchPeersFromTorrent(byte[] torrentInfoHash, byte[] peer @Cacheable(value = {"scrape#60000"}, key = "#torrentInfoHash") public ScrapeResponse scrape(byte[] torrentInfoHash) { + scrapeCounter.increment(); var seeders = trackedPeerRepository.countByTorrentInfoHashAndLeft(ByteUtil.bytesToHex(torrentInfoHash), 0L); var leechers = trackedPeerRepository.countByTorrentInfoHashAndLeftNot(ByteUtil.bytesToHex(torrentInfoHash), 0L); var downloaded = 0L; diff --git a/src/main/java/com/ghostchu/btn/sparkle/module/tracker/internal/TrackedPeerRepository.java b/src/main/java/com/ghostchu/btn/sparkle/module/tracker/internal/TrackedPeerRepository.java index cce3993..bb62b1f 100644 --- a/src/main/java/com/ghostchu/btn/sparkle/module/tracker/internal/TrackedPeerRepository.java +++ b/src/main/java/com/ghostchu/btn/sparkle/module/tracker/internal/TrackedPeerRepository.java @@ -41,6 +41,12 @@ order by RANDOM() limit ?3 long countByLeftNot(Long left); + long countDistinctByPeerId(); + + long countDistinctByPeerIp(); + + long countDistinctByTorrentInfoHash(); + @Query("select count(*) from TrackedPeer t where t.uploaded = 0") long countUsersWhoDidntUploadAnyData(); @Query("select count(*) from TrackedPeer t where t.uploaded != 0") diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 83572ad..ed44ee9 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -84,6 +84,7 @@ service.tracker.cleanup-interval=600000 service.tracker.announce-interval=3600000 service.tracker.inactive-interval=3800000 service.tracker.max-peers-return=300 +service.tracker.metrics-interval=600000 util.ipmerger.merge-threshold.ipv4=2 util.ipmerger.merge-threshold.ipv6=3