Memcached 是一个高性能的分布式内存缓存系统,主要用于加速动态数据库驱动的网站和应用程序。它通过缓存数据和对象来减少数据库负载,从而提高系统性能。以下是 Memcached 的功能和各个应用场景的详细介绍。
Memcached 提供了高速的数据访问,通过将数据存储在内存中来减少对数据库的请求,从而加速应用程序的响应时间。
Memcached 支持分布式部署,可以将缓存数据分布在多个服务器上,从而提高系统的缓存容量和可靠性。
Memcached 使用简单的 key-value 数据存储模型,支持字符串、对象等多种数据类型的缓存。
Memcached 支持多种缓存失效策略,包括基于时间的过期(TTL)和内存淘汰策略(如 LRU)等。
Memcached 使用 slab 分配机制来管理内存,减少内存碎片,提高内存使用效率。
在高并发应用中,数据库查询可能成为性能瓶颈。通过缓存常用的数据库查询结果,可以显著减少数据库负载,提高系统响应速度。
Node.js 实现数据库查询缓存
const memjs = require('memjs');
const mysql = require('mysql');
const mc = memjs.Client.create();
const connection = mysql.createConnection({
host: 'localhost',
user: 'user',
password: 'password',
database: 'test'
});
connection.connect();
const query = 'SELECT * FROM users WHERE id = 1';
mc.get('user:1', (err, value) => {
if (err) {
console.error(err);
} else if (value) {
console.log('Cache hit:', JSON.parse(value.toString()));
} else {
connection.query(query, (error, results) => {
if (error) throw error;
const user = results[0];
console.log('Cache miss, fetching from database:', user);
// 将查询结果缓存 10 分钟
mc.set('user:1', JSON.stringify(user), { expires: 600 });
});
}
});
Java 实现数据库查询缓存
import net.spy.memcached.MemcachedClient;
import java.net.InetSocketAddress;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class MemcachedDbExample {
public static void main(String[] args) throws Exception {
MemcachedClient memcachedClient = new MemcachedClient(new InetSocketAddress("localhost", 11211));
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "user", "password");
String query = "SELECT * FROM users WHERE id = 1";
Object cachedUser = memcachedClient.get("user:1");
if (cachedUser != null) {
System.out.println("Cache hit: " + cachedUser);
} else {
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query);
if (resultSet.next()) {
String user = resultSet.getString("name");
System.out.println("Cache miss, fetching from database: " + user);
// 将查询结果缓存 10 分钟
memcachedClient.set("user:1", 600, user);
}
}
connection.close();
memcachedClient.shutdown();
}
}
Memcached 可用于存储会话数据,特别是在多台服务器的集群环境中,共享会话数据有助于负载均衡和故障切换。
Node.js 实现会话管理
const memjs = require('memjs');
const express = require('express');
const session = require('express-session');
const MemcachedStore = require('connect-memjs')(session);
const app = express();
const mc = memjs.Client.create();
app.use(session({
secret: 'secret-key',
resave: false,
saveUninitialized: true,
store: new MemcachedStore({ client: mc })
}));
app.get('/', (req, res) => {
if (req.session.views) {
req.session.views++;
} else {
req.session.views = 1;
}
res.send(`Number of views: ${req.session.views}`);
});
app.listen(3000, () => {
console.log('Server started on port 3000');
});
Java 实现会话管理
import net.spy.memcached.MemcachedClient;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlet.DefaultServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.InetSocketAddress;
public class MemcachedSessionExample {
private static MemcachedClient memcachedClient;
public static void main(String[] args) throws Exception {
memcachedClient = new MemcachedClient(new InetSocketAddress("localhost", 11211));
Server server = new Server(8080);
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
server.setHandler(context);
context.addServlet(new ServletHolder(new SessionServlet()), "/");
server.start();
server.join();
}
public static class SessionServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String sessionId = req.getSession().getId();
Integer views = (Integer) memcachedClient.get(sessionId);
if (views == null) {
views = 1;
} else {
views++;
}
memcachedClient.set(sessionId, 1800, views); // 将会话数据缓存 30 分钟
resp.getWriter().println("Number of views: " + views);
}
}
}
对于需要频繁生成的动态内容,如社交媒体时间线、新闻订阅源等,Memcached 可以缓存生成的内容以减少计算和数据库查询。
Node.js 实现动态内容缓存
const memjs = require('memjs');
const express = require('express');
const app = express();
const mc = memjs.Client.create();
app.get('/feed', async (req, res) => {
mc.get('user:feed', (err, value) => {
if (err) {
console.error(err);
res.sendStatus(500);
return;
}
if (value) {
console.log('Cache hit');
res.send(value.toString());
} else {
console.log('Cache miss');
// 模拟动态生成内容
const feedContent = generateDynamicFeed();
mc.set('user:feed', feedContent, { expires: 300 }); // 缓存 5 分钟
res.send(feedContent);
}
});
});
function generateDynamicFeed() {
return 'Dynamic content generated at ' + new Date();
}
app.listen(3000, () => {
console.log('Server started on port 3000');
});
Java 实现动态内容缓存
import net.spy.memcached.MemcachedClient;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlet.DefaultServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.InetSocketAddress;
public class MemcachedDynamicContentExample {
private static MemcachedClient memcachedClient;
public static void main(String[] args) throws Exception {
memcachedClient = new MemcachedClient(new InetSocketAddress("localhost", 11211));
Server server = new Server(8080);
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
server.setHandler(context);
context.addServlet(new ServletHolder(new FeedServlet()), "/feed");
server.start();
server.join();
}
public static class FeedServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String feedKey = "user:feed";
String feedContent = (String) memcachedClient.get(feedKey);
if (feedContent == null) {
feedContent = generateDynamicFeed();
memcachedClient.set(feedKey, 300, feedContent); // 缓存 5 分钟
System.out.println("Cache miss");
} else {
System.out.println("Cache hit");
}
resp.getWriter().println(feedContent);
}
private String generateDynamicFeed() {
return "Dynamic content generated at " + new java.util.Date();
}
}
}
当应用程序依赖于第三方 API 时,可以通过缓存 API 响应来减少调用频率,从
而节省成本和提高性能。
Node.js 实现第三方 API 响应缓存
const memjs = require('memjs');
const axios = require('axios');
const mc = memjs.Client.create();
const apiUrl = 'https://api.example.com/data';
async function getApiData() {
mc.get('api:data', async (err, value) => {
if (err) {
console.error(err);
return;
}
if (value) {
console.log('Cache hit:', value.toString());
} else {
console.log('Cache miss');
try {
const response = await axios.get(apiUrl);
const data = response.data;
// 将 API 响应缓存 10 分钟
mc.set('api:data', JSON.stringify(data), { expires: 600 });
console.log('API response:', data);
} catch (error) {
console.error('Error fetching API data:', error);
}
}
});
}
getApiData();
Java 实现第三方 API 响应缓存
import net.spy.memcached.MemcachedClient;
import java.net.InetSocketAddress;
import java.net.HttpURLConnection;
import java.net.URL;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class MemcachedApiExample {
private static MemcachedClient memcachedClient;
private static final String API_URL = "https://api.example.com/data";
public static void main(String[] args) throws Exception {
memcachedClient = new MemcachedClient(new InetSocketAddress("localhost", 11211));
getApiData();
memcachedClient.shutdown();
}
private static void getApiData() throws Exception {
String cachedData = (String) memcachedClient.get("api:data");
if (cachedData != null) {
System.out.println("Cache hit: " + cachedData);
} else {
System.out.println("Cache miss");
String apiResponse = fetchApiData();
memcachedClient.set("api:data", 600, apiResponse); // 缓存 10 分钟
System.out.println("API response: " + apiResponse);
}
}
private static String fetchApiData() throws Exception {
HttpURLConnection connection = (HttpURLConnection) new URL(API_URL).openConnection();
connection.setRequestMethod("GET");
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuilder content = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
content.append(inputLine);
}
in.close();
return content.toString();
}
}
对于需要耗费大量计算资源的操作,如复杂计算、数据分析等,可以将计算结果缓存,以减少重复计算。
Node.js 实现计算结果缓存
const memjs = require('memjs');
const mc = memjs.Client.create();
function expensiveCalculation(param) {
// 模拟耗时计算
let result = 0;
for (let i = 0; i < 1000000; i++) {
result += i * param;
}
return result;
}
function getCachedCalculation(param, callback) {
mc.get(`calculation:${param}`, (err, value) => {
if (err) {
console.error(err);
callback(err);
return;
}
if (value) {
console.log('Cache hit:', value.toString());
callback(null, Number(value.toString()));
} else {
console.log('Cache miss');
const result = expensiveCalculation(param);
// 将计算结果缓存 1 小时
mc.set(`calculation:${param}`, result.toString(), { expires: 3600 });
callback(null, result);
}
});
}
getCachedCalculation(5, (err, result) => {
if (err) {
console.error(err);
} else {
console.log('Calculation result:', result);
}
});
Java 实现计算结果缓存
import net.spy.memcached.MemcachedClient;
import java.net.InetSocketAddress;
public class MemcachedCalculationExample {
private static MemcachedClient memcachedClient;
public static void main(String[] args) throws Exception {
memcachedClient = new MemcachedClient(new InetSocketAddress("localhost", 11211));
getCachedCalculation(5);
memcachedClient.shutdown();
}
private static void getCachedCalculation(int param) {
String cacheKey = "calculation:" + param;
Object cachedResult = memcachedClient.get(cacheKey);
if (cachedResult != null) {
System.out.println("Cache hit: " + cachedResult);
} else {
System.out.println("Cache miss");
long result = expensiveCalculation(param);
memcachedClient.set(cacheKey, 3600, result); // 缓存 1 小时
System.out.println("Calculation result: " + result);
}
}
private static long expensiveCalculation(int param) {
// 模拟耗时计算
long result = 0;
for (int i = 0; i < 1000000; i++) {
result += i * param;
}
return result;
}
}
对于频繁访问的静态页面,可以使用 Memcached 缓存 HTML 内容,减少服务器渲染的负担。
Node.js 实现 HTML 内容缓存
const memjs = require('memjs');
const express = require('express');
const app = express();
const mc = memjs.Client.create();
app.get('/static-page', (req, res) => {
mc.get('static:page', (err, value) => {
if (err) {
console.error(err);
res.sendStatus(500);
return;
}
if (value) {
console.log('Cache hit');
res.send(value.toString());
} else {
console.log('Cache miss');
const htmlContent = generateStaticHtml();
mc.set('static:page', htmlContent, { expires: 300 }); // 缓存 5 分钟
res.send(htmlContent);
}
});
});
function generateStaticHtml() {
return '<html><body><h1>Static Page</h1></body></html>';
}
app.listen(3000, () => {
console.log('Server started on port 3000');
});
Java 实现 HTML 内容缓存
import net.spy.memcached.MemcachedClient;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlet.DefaultServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.InetSocketAddress;
public class MemcachedHtmlCacheExample {
private static MemcachedClient memcachedClient;
public static void main(String[] args) throws Exception {
memcachedClient = new MemcachedClient(new InetSocketAddress("localhost", 11211));
Server server = new Server(8080);
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
server.setHandler(context);
context.addServlet(new ServletHolder(new StaticPageServlet()), "/static-page");
server.start();
server.join();
}
public static class StaticPageServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String cachedHtml = (String) memcachedClient.get("static:page");
if (cachedHtml == null) {
cachedHtml = generateStaticHtml();
memcachedClient.set("static:page", 300, cachedHtml); // 缓存 5 分钟
System.out.println("Cache miss");
} else {
System.out.println("Cache hit");
}
resp.getWriter().println(cachedHtml);
}
private String generateStaticHtml() {
return "<html><body><h1>Static Page</h1></body></html>";
}
}
}
Memcached 是一种强大的缓存解决方案,可以显著提高应用程序的性能和响应速度。通过合理利用 Memcached 的功能,可以有效地减轻数据库负载,提高系统的稳定性和扩展性。在使用 Memcached 时,需要根据具体的应用场景和需求来配置缓存策略,以达到最佳效果。
如果您有任何其他问题或需要进一步的解释,请随时告诉我!